![](/media/cache/profiles/40172752.jpg.50x50_q85.jpg)
Satellite Observers Workbench. NOT yet complete, just published for forum posters to \"cherry pick\" pieces of code as requiered as an example.
Revision 0:0a841b89d614, committed 2010-10-11
- Comitter:
- AjK
- Date:
- Mon Oct 11 10:34:55 2010 +0000
- Commit message:
- Totally Alpha quality as this project isn\t completed. Just publishing it as it answers many questions asked in the forums
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/config/config.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,129 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +/* Need to come back and finish this. */ + +#include "sowb.h" +#include "user.h" +#include "debug.h" +#include "config.h" +#include "ff.h" + +CONFIG_UNION system_config; + +bool config_block_process; +bool config_loaded; +bool config_reload; + +/** config_init + */ +void config_init(void) { + int i, j; + + DEBUG_INIT_START; + + /* + for (i = CONFIG_FLASH_PAGE_BASE, j = 0; i < 4096; i++, j++) { + flash_read_page(i, system_config.buffers[j], true); + } + + config_loaded = true; + config_reload = false; + config_block_process = false; + */ + + DEBUG_INIT_END; +} + +/** config_process + */ +void config_process(void) { + + /* For long period operations (e.g. config_save()) that may call + system _process() functions, block ourselves from re-entering. */ + if (config_block_process) return; + +} + +void config_save(void) { + int i, j; + char buffer[FLASH_PAGE_SIZE]; + + /* Don't re-enter this function from _process(). */ + config_block_process = true; + + /* Sector 15 is used as a "scratch area". It allows us to store + pages from other sectors that we need to "restore" since the + LPC1768 doesn't have enough space to store entire sectors. */ + while (flash_sector_erase_in_progress()) WHILE_WAITING_DO_PROCESS_FUNCTIONS; + flash_erase_sector(15); + while (flash_sector_erase_in_progress()) WHILE_WAITING_DO_PROCESS_FUNCTIONS; + + /* We need to make a copy of all the pages below our config area + before we store our configuration. */ + for (i = 4096 - 256; i < CONFIG_FLASH_PAGE_BASE; i++) { + flash_read_page(i, buffer, true); + flash_page_write(3840 + i, buffer); + while(flash_write_in_progress()) WHILE_WAITING_DO_PROCESS_FUNCTIONS; + } + + /* Now erase the sector in which our config resides. */ + while (flash_sector_erase_in_progress()) WHILE_WAITING_DO_PROCESS_FUNCTIONS; + flash_erase_sector(14); + while (flash_sector_erase_in_progress()) WHILE_WAITING_DO_PROCESS_FUNCTIONS; + + + for (i = CONFIG_FLASH_PAGE_BASE, j = 0; i < CONFIG_FLASH_PAGE_BASE + CONFIG_FLASH_PAGES; i++, j++) { + while(flash_write_in_progress() || flash_sector_erase_in_progress()) { + WHILE_WAITING_DO_PROCESS_FUNCTIONS; + } + flash_page_write(i, system_config.buffers[j]); + } + + config_block_process = false; +} + +/** config_copy_flash_page + * + * Used to copy the raw config struct, page by page + * to an external memory buffer. + * + * @param int page The page to copy. + * @param char* buffer The buffer to copy the page to. + */ +void config_copy_flash_page(int page, char *buffer) { + memcpy(buffer, system_config.buffers[page], FLASH_PAGE_SIZE); +} + +/** config_get_page + * + * Get the base address of a specific page of config data. + * + * @param int page The page to get the address of. + * @return char* The address of the page. + */ +char * config_get_page(int page) { + return system_config.buffers[page]; +} + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/config/config.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,46 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef CONFIG_H +#define CONFIG_H + +#include "flash.h" + +#define CONFIG_MAX_SIZE 4096 +#define CONFIG_FLASH_PAGES CONFIG_MAX_SIZE / FLASH_PAGE_SIZE +#define CONFIG_FLASH_PAGE_BASE 3840 - CONFIG_FLASH_PAGES + +typedef struct _config_values { + int config_struct_version; +} CONFIG_VALUES; + +typedef union _config_union { + char buffers[CONFIG_FLASH_PAGES][FLASH_PAGE_SIZE]; + CONFIG_VALUES values; +} CONFIG_UNION; + +void config_init(void); +void config_process(void); +void config_copy_flash_page(int page, char *buffer); +char * config_get_page(int page); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debug/debug.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,193 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#include "sowb.h" +#include "debug.h" + +/* Design note. We do not use a txBufferOverflow flag like we + do with the RX buffer as all calls to Uart0_putc() will + block if there isn't room to send. It's up to the designer + to either ensure they don't flood the TX buffer with too + many debug strings or alternatively increase the buffer + size to handle the higher amounts of traffic. */ + +volatile char txBuffer[UART0_TX_BUFFER_SIZE]; +volatile char rxBuffer[UART0_RX_BUFFER_SIZE]; +volatile unsigned char txBufferIn, txBufferOut; +volatile unsigned char rxBufferIn, rxBufferOut; +volatile bool txBufferFull, rxBufferFull, rxBufferOverflow; + +/** UART0_IRQHandler + */ +extern "C" void UART0_IRQHandler(void) __irq { + uint32_t iir; + + iir = LPC_UART0->IIR; + + if (iir & 1) return; + + iir = (iir >> 1) & 0x3; + + if (iir == 2) { + if (rxBufferIn == rxBufferOut && rxBufferFull) { + char c __attribute__((unused)); /* oh dear, no room, send to /dev/null */ + c = LPC_UART0->RBR; + rxBufferOverflow = true; + } + else { + rxBuffer[rxBufferIn++] = LPC_UART0->RBR; + rxBufferIn &= (UART0_RX_BUFFER_SIZE - 1); + if (rxBufferIn == rxBufferOut) rxBufferFull = true; + } + } + + if (iir == 1) { + if (txBufferIn != txBufferOut || txBufferFull) { + LPC_UART0->THR = (uint8_t)(txBuffer[txBufferOut++]); + txBufferOut &= (UART0_TX_BUFFER_SIZE - 1); + txBufferFull = false; + } + else { + LPC_UART0->IER = 0x1; + } + } +} + +/** Uart0_init + */ +void Uart0_init(void) { + volatile char c __attribute__((unused)); + + LPC_SC->PCONP |= (1UL << 3); + LPC_SC->PCLKSEL0 &= ~(3UL << 6); + LPC_SC->PCLKSEL0 |= (1UL << 6); + LPC_PINCON->PINSEL0 &= ~((1UL << 4) | (1UL << 6)); + LPC_PINCON->PINSEL0 |= ((1UL << 4) | (1UL << 6)); + LPC_UART0->LCR = 0x80; + LPC_UART0->DLM = 0x0; // 0x00 for 115200 baud, for 9600 use 0x2; + LPC_UART0->DLL = 0x34; // 0x34 for 115200 baud, for 9600 use 0x71; + LPC_UART0->LCR = 0x3; + LPC_UART0->FCR = 0x7; + + NVIC_SetVector(UART0_IRQn, (uint32_t)UART0_IRQHandler); + NVIC_EnableIRQ(UART0_IRQn); + + /* Enable UART0 RX interrupt only. */ + LPC_UART0->IER = 0x1; +} + +/** debug_init + */ +void debug_init(void) { + txBufferIn = txBufferOut = 0; + memset((char *)txBuffer, 0, UART0_TX_BUFFER_SIZE); + rxBufferIn = rxBufferOut = 0; + memset((char *)txBuffer, 0, UART0_RX_BUFFER_SIZE); + txBufferFull = rxBufferFull = false; + rxBufferOverflow = false; + Uart0_init(); +} + +#ifdef DEBUG_USE_UART0 + +/** debug_string + * + * Print a null termimnated string to UART0. + * + * @param char *s A pointer to the null terminated string. + */ +void debug_string(char *s) { + while (*(s)) { + Uart0_putc(*s++); + } +} + +/** debug_stringl + * + * Print a string of specified length to UART0. + * + * @param char *s A pointer to the null terminated string. + * @param int length The length of the string to print. + */ +void debug_stringl(char *s, int length) { + while (length--) { + Uart0_putc(*s++); + } +} + +/* Local function prototype for _init(). */ +void Uart0_init(void); + +/** Uart0_putc + * + * Put a character out the UART0 serial port. + * Note, if the THR register is not empty AND the output buffer is not empty + * then place the character into the output buffer and enable interrupt to + * flush the buffer. + * + * Additionally, if the TX buffer is full this function will BLOCK! + * If you have lots of debugging messages to spit out then it may be + * wise to either "slimeline" what you need to print out or alternatively + * increase the size of the txBuffer to cope with the increased traffic. + * Be aware of this blocking! + * + * @param char c The character to send out of UART0. + */ +void Uart0_putc(char c) { + if ((LPC_UART0->LSR & 0x20) && (txBufferIn == txBufferOut && !txBufferFull)) { + LPC_UART0->THR = (uint8_t)c; + } + else { + while (txBufferFull) ; /* Blocks!!! */ + txBuffer[txBufferIn++] = c; + txBufferIn &= (UART0_TX_BUFFER_SIZE - 1); + if (txBufferIn == txBufferOut && !txBufferFull) txBufferFull = true; + LPC_UART0->IER = 0x3; + } +} + +/** Uart0_getc + * + * Used to get a character from Uart0. If the passed arg "block" is non-zero + * then this function will block (wait) for user input. Otherwise if a char + * is available return it, otherwise return -1 to show buffer was empty. + * + * @param int block Should we block? + * @return int Cast char to int for char or -1 if non-blocking and no char. + */ +int Uart0_getc(int block) { + char c; + + if (block) while (rxBufferOut == rxBufferIn && !rxBufferFull) ; /* Blocks! */ + else if (rxBufferIn == rxBufferOut && !rxBufferFull) return -1; + + c = rxBuffer[rxBufferOut++]; + rxBufferOut &= (UART0_RX_BUFFER_SIZE - 1); + if (rxBufferFull) rxBufferFull = false; + return (int)c; +} + +/* end of #ifdef DEBUG_USE_UART0 */ +#endif + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debug/debug.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,79 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef DEBUG_H +#define DEBUG_H + +/* Comment out the following to totally disable debugging output on UART0. + This is the global kill switch for debug output. */ +#define DEBUG_ON + + +/* These are finer grained debug enable switches. */ +#ifdef DEBUG_ON +#define DEBUG_USE_UART0 +#endif + +/* The following is used "interally" by the debug.c and various other modules. */ + +void debug_init(void); + +/* Buffer sizes MUST be a aligned 2^, for example 8, 16, 32, 64, 128, 256, 512, 1024, etc + Do NOT use any other value or the buffer wrapping firmware won't work. */ +#ifdef DEBUG_USE_UART0 +#define UART0_TX_BUFFER_SIZE 8192 +#define UART0_RX_BUFFER_SIZE 16 +#else +#define UART0_TX_BUFFER_SIZE 4 +#define UART0_RX_BUFFER_SIZE 4 +#endif + + +#ifdef DEBUG_USE_UART0 +/* If debugging is on declare the real function prototypes. */ +int debug_printf(const char *format, ...); +int debug_sprintf(char *out, const char *format, ...); +void debug_string(char *s); +void debug_stringl(char *s, int length); + +#else + +/* If no debugging, replace debug functions with simple empty macros. */ +#define debug_printf(x, ...) +#define debug_sprintf(x, y, ...) +#define debug_string(x) +#define debug_stringl(x, y) + +/* End #ifdef DEBUG_USE_UART0 */ +#endif + +#define DEBUG_INIT_START debug_printf("INIT: %s()... ", __FUNCTION__) +#define DEBUG_INIT_END debug_printf("complete.\r\n") + +/* These function prototypes are always declared. */ +void Uart0_putc(char c); +int Uart0_getc(int block); + + +/* End #ifndef DEBUG_H */ +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debug/debug_printf.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,214 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +/* The following is from (with only minor edits to fit onto Mbed):- + Copyright 2001, 2002 Georges Menie (www.menie.org) + stdarg version contributed by Christian Ettinger + See... + http://www.menie.org/georges/embedded/ + http://www.menie.org/georges/embedded/printf-stdarg.c + + This printf function will accept integer formats (%d, %x, %X, %u), string format (%s) + and character format (%c); left and right alignement, padding with space or 'O'. */ + +#include "sowb.h" +#include "debug.h" +#include <stdarg.h> + +#ifdef DEBUG_ON + +static void printchar(char **str, int c) +{ + if (str) { + **str = c; + ++(*str); + } + else (void)Uart0_putc(c); +} + +#define PAD_RIGHT 1 +#define PAD_ZERO 2 + +static int prints(char **out, const char *string, int width, int pad) +{ + register int pc = 0, padchar = ' '; + + if (width > 0) { + register int len = 0; + register const char *ptr; + for (ptr = string; *ptr; ++ptr) ++len; + if (len >= width) width = 0; + else width -= len; + if (pad & PAD_ZERO) padchar = '0'; + } + if (!(pad & PAD_RIGHT)) { + for ( ; width > 0; --width) { + printchar (out, padchar); + ++pc; + } + } + for ( ; *string ; ++string) { + printchar (out, *string); + ++pc; + } + for ( ; width > 0; --width) { + printchar (out, padchar); + ++pc; + } + + return pc; +} + +/* the following should be enough for 32 bit int */ +#define PRINT_BUF_LEN 12 + +static int printi(char **out, int i, int b, int sg, int width, int pad, int letbase) +{ + char print_buf[PRINT_BUF_LEN]; + register char *s; + register int t, neg = 0, pc = 0; + register unsigned int u = i; + + if (i == 0) { + print_buf[0] = '0'; + print_buf[1] = '\0'; + return prints (out, print_buf, width, pad); + } + + if (sg && b == 10 && i < 0) { + neg = 1; + u = -i; + } + + s = print_buf + PRINT_BUF_LEN-1; + *s = '\0'; + + while (u) { + t = u % b; + if( t >= 10 ) + t += letbase - '0' - 10; + *--s = t + '0'; + u /= b; + } + + if (neg) { + if( width && (pad & PAD_ZERO) ) { + printchar (out, '-'); + ++pc; + --width; + } + else { + *--s = '-'; + } + } + + return pc + prints (out, s, width, pad); +} + +static int print(char **out, const char *format, va_list args ) +{ + register int width, pad; + register int pc = 0; + char scr[2]; + + for (; *format != 0; ++format) { + if (*format == '%') { + ++format; + width = pad = 0; + if (*format == '\0') break; + if (*format == '%') goto out; + if (*format == '-') { + ++format; + pad = PAD_RIGHT; + } + while (*format == '0') { + ++format; + pad |= PAD_ZERO; + } + for ( ; *format >= '0' && *format <= '9'; ++format) { + width *= 10; + width += *format - '0'; + } + if( *format == 's' ) { + register char *s = (char *)va_arg( args, int ); + pc += prints (out, s?s:"(null)", width, pad); + continue; + } + if( *format == 'd' ) { + pc += printi (out, va_arg( args, int ), 10, 1, width, pad, 'a'); + continue; + } + if( *format == 'x' ) { + pc += printi (out, va_arg( args, int ), 16, 0, width, pad, 'a'); + continue; + } + if( *format == 'X' ) { + pc += printi (out, va_arg( args, int ), 16, 0, width, pad, 'A'); + continue; + } + if( *format == 'u' ) { + pc += printi (out, va_arg( args, int ), 10, 0, width, pad, 'a'); + continue; + } + if( *format == 'c' ) { + /* char are converted to int then pushed on the stack */ + scr[0] = (char)va_arg( args, int ); + scr[1] = '\0'; + pc += prints (out, scr, width, pad); + continue; + } + } + else { + out: + printchar (out, *format); + ++pc; + } + } + if (out) **out = '\0'; + va_end( args ); + return pc; +} + + +int debug_printf(const char *format, ...) { + #ifdef DEBUG_ON + va_list args; + va_start( args, format ); + return print( 0, format, args ); + #else + return 0; + #endif +} + +int debug_sprintf(char *out, const char *format, ...) { + #ifdef DEBUG_ON + va_list args; + va_start( args, format ); + return print( &out, format, args ); + #else + return 0; + #endif +} + +/* end of #ifdef DEBUG_ON */ +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dma/dma.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,161 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#include "sowb.h" +#include "debug.h" +#include "dma.h" + +uint32_t channel_in_use_flags = 0; + +/* Declare callback functions here before placing + in the array below. */ +int flash_read_dma0_irq(int); +int flash_read_dma1_irq(int); +int flash_write_dma0_irq(int); + +/* Make sure each array definition below ends with + a NULL,NULL struct to mark the end of the array. */ + +const DMA_CALLBACKS dma_channel0[] = { + { flash_read_dma0_irq, flash_read_dma0_irq }, + { flash_write_dma0_irq, flash_write_dma0_irq }, + { NULL, NULL } +}; + +const DMA_CALLBACKS dma_channel1[] = { + { flash_read_dma1_irq, flash_read_dma1_irq }, + { NULL, NULL } +}; + +const DMA_CALLBACKS dma_channel2[] = { + { NULL, NULL } +}; + +const DMA_CALLBACKS dma_channel3[] = { + { NULL, NULL } +}; + +const DMA_CALLBACKS dma_channel4[] = { + { NULL, NULL } +}; + +const DMA_CALLBACKS dma_channel5[] = { + { NULL, NULL } +}; + +const DMA_CALLBACKS dma_channel6[] = { + { NULL, NULL } +}; + +const DMA_CALLBACKS dma_channel7[] = { + { NULL, NULL } +}; + +/* Don't change anything below here. */ + +/* An array of pointers to the channel ISR handlers. */ +const DMA_CALLBACKS *dma_channels[8] = { + dma_channel0, dma_channel1, dma_channel2, dma_channel3, + dma_channel4, dma_channel5, dma_channel6, dma_channel7 +}; + +/** DMA_IRQHandler + */ +extern "C" void DMA_IRQHandler(void) __irq { + for (int channel_number = 0; channel_number < 8; channel_number++) { + if (LPC_GPDMA->DMACIntStat & (1UL << channel_number)) { + if (LPC_GPDMA->DMACIntTCStat & (1UL << channel_number)) { + int irq_idx = 0; + while (dma_channels[channel_number][irq_idx].TcCallback != NULL) { + if ((dma_channels[channel_number][irq_idx].TcCallback)(channel_number)) { + LPC_GPDMA->DMACIntTCClear = (1UL << channel_number); + break; + } + irq_idx++; + } + } + if (LPC_GPDMA->DMACIntErrStat & (1UL << channel_number)) { + int irq_idx = 0; + while (dma_channels[channel_number][irq_idx].ErrCallback != NULL) { + if ((dma_channels[channel_number][irq_idx].ErrCallback)(channel_number)) { + LPC_GPDMA->DMACIntErrClr = (1UL << channel_number); + break; + } + irq_idx++; + } + } + } + } + + /* IRQ should be handled by now, check to make sure. */ + if (LPC_GPDMA->DMACIntStat) { + LPC_GPDMA->DMACIntTCClear = (uint32_t)0xFF; /* If not, clear anyway! */ + } + if (LPC_GPDMA->DMACIntErrStat) { + LPC_GPDMA->DMACIntErrClr = (uint32_t)0xFF; /* If not, clear anyway! */ + } +} + + +/** DMA_init + */ +void DMA_init(void) { + DEBUG_INIT_START; + LPC_SC->PCONP |= (1UL << 29); + LPC_GPDMA->DMACConfig = 1; + NVIC_SetVector(DMA_IRQn, (uint32_t)DMA_IRQHandler); + NVIC_EnableIRQ(DMA_IRQn); + DEBUG_INIT_END; +} + +/** DMA_process + */ +void DMA_process(void) { + /* Nothing to do. */ +} + +/** dma_request_channel + * + * Used to request control of a DMA channel. Allows modules + * to share channels if needed. + * + * @param int channel The channel being requested. + * @return bool true if given control, false if another is already in control. + */ +bool DMA_request_channel(int channel) { + if (!(channel_in_use_flags & (1UL << channel))) { + channel_in_use_flags |= (1UL << channel); + return true; + } + return false; +} + +/** dma_release_channel + * + * Used to release a previously requested channel. + * + * @param int channel The channel to release. + */ +void DMA_release_channel(int channel) { + channel_in_use_flags &= ~(1UL << channel); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dma/dma.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,47 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef DMA_H +#define DMA_H + +#define DMA_CHANNEL_0 (1UL << 0) +#define DMA_CHANNEL_1 (1UL << 1) +#define DMA_CHANNEL_2 (1UL << 2) +#define DMA_CHANNEL_3 (1UL << 3) +#define DMA_CHANNEL_4 (1UL << 4) +#define DMA_CHANNEL_5 (1UL << 5) +#define DMA_CHANNEL_6 (1UL << 6) +#define DMA_CHANNEL_7 (1UL << 7) + +typedef int (*DMA_callback)(int channel); + +typedef struct _dma_callbacks { + DMA_callback TcCallback; + DMA_callback ErrCallback; +} DMA_CALLBACKS; + +void DMA_init(void); +void DMA_process(void); +bool DMA_request_channel(int channel); +void DMA_release_channel(int channel); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flash/25AA02EE48.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,88 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#include "sowb.h" +#include "user.h" +#include "flash.h" +#include "ssp0.h" +#include "gpio.h" + +char mac_addr[6]; + +/** _25AA02E48_mac_addr + * + * Get a copy of the MAC address with a null terminator. + * + * @param char *s a buffer, 7 bytes long, to hold the MAC+null + */ +void _25AA02E48_mac_addr(char *s) { + memcpy(s, mac_addr, 6); + s[6] = '\0'; +} + +/** _25AA02E48_mac_addr_printable + * + * Create a string that represents the MAC addr as a + * printable ASCII string. The caller is responsible + * for allocating enough space in the buffer pointed + * to by s to hold the string. + * + * @param char *s a buffer, 18 bytes long, to hold the MAC + * @param char divider A character to divide the bytes or 0 + */ +void _25AA02E48_mac_addr_printable(char *s, char divider) { + if (divider != 0) { + sprintf(s, "%02X%c%02X%c%02X%c%02X%c%02X%c%02X", + mac_addr[0], divider, mac_addr[1], divider, mac_addr[2], divider, + mac_addr[3], divider, mac_addr[4], divider, mac_addr[5]); + } + else { + sprintf(s, "%02X%02X%02X%02X%02X%02X", + mac_addr[0], mac_addr[1], mac_addr[2], + mac_addr[3], mac_addr[4], mac_addr[5]); + } +} + +/** _25AA02E48_init + */ +void _25AA02E48_init(void) { + + /* Assumes SSP0 is already _init() */ + + while(!SSP0_request()) WHILE_WAITING_DO_PROCESS_FUNCTIONS; + + LPC_SSP0->CPSR = _25AA02E48_SSP_INIT_CPSR; + AA02E48_CS_ASSERT; + FLASH_SHORT_COMMAND(FLASH_READ); + SSP0_WRITE_BYTE(0xFA); + SSP0_FLUSH_RX_FIFO; + + for (int i = 0; i < 6; i++) { + SSP0_WRITE_BYTE(0x00); + while(SSP0_IS_BUSY || (LPC_SSP0->SR & (1UL << 2)) == 0); + mac_addr[i] = (char)LPC_SSP0->DR; + } + + AA02E48_CS_DEASSERT; + LPC_SSP0->CPSR = FLASH_SSP_INIT_CPSR; + SSP0_release(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flash/FatFS/diskio.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,664 @@ +/*-----------------------------------------------------------------------*/ +/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2007 */ +/*-----------------------------------------------------------------------*/ +/* This is a stub disk I/O module that acts as front end of the existing */ +/* disk I/O modules and attach it to FatFs module with common interface. */ +/*-----------------------------------------------------------------------*/ + +#include "diskio.h" +#include "sowb.h" +#include "user.h" +#include "gpio.h" +#include "gps.h" +#include "ssp0.h" + +#define R1_IDLE_STATE (1 << 0) +#define R1_ERASE_RESET (1 << 1) +#define R1_ILLEGAL_COMMAND (1 << 2) +#define R1_COM_CRC_ERROR (1 << 3) +#define R1_ERASE_SEQUENCE_ERROR (1 << 4) +#define R1_ADDRESS_ERROR (1 << 5) +#define R1_PARAMETER_ERROR (1 << 6) + +//****************************************************************************************************************** +// MBED SPI/CS Select functions.... Modify for your layout. +//************************************************************************************** + +//SPI _spi(p5, p6, p7); // mosi, miso, sclk +//DigitalOut _cs(p8); +//DigitalOut P20(p20); +//SPI * _spi; + + +//****************************************************************************************************************** +// Low Level Sector Access Function Prototypes('C' Castrated versions of Simon Ford's C++ MBED SDFileSystem class +//****************************************************************************************************************** +int _cmd(int cmd, int arg); +int _cmd8(void); +int _cmdR2(int cmd, int arg); +int _read(BYTE *buffer, int length); +int _write(BYTE *buffer, int length); +int ext_bits(BYTE *data, int msb, int lsb); +int _sd_sectors(); +int _sectors; + +#define SD_COMMAND_TIMEOUT 5000 + +void deassert_cs(void) { + SDCARD_CS_DEASSERT; //_cs = 1; +} + +//****************************************************************************************************************** +// Sector Access functions for CHAN FatFs +//****************************************************************************************************************** + +DRESULT disk_ioctl ( + BYTE drv, /* Physical drive nmuber (0..) */ + BYTE ctrl, /* Control code */ + void *buff /* Buffer to send/receive control data */ +) +{ + DRESULT res; + + switch(ctrl) + { + case CTRL_SYNC: + res = RES_OK; + break; + + case GET_SECTOR_SIZE: + res = RES_OK; + *(WORD *)buff = 512; + break; + + case GET_SECTOR_COUNT: + res = RES_OK; + *(DWORD *)buff = (WORD)_sd_sectors(); + break; + + case GET_BLOCK_SIZE: + res = RES_OK; + *(DWORD *)buff = 1; + break; + + default: + res = RES_OK; + break; + } + return res; +} + +int _cmd58() { + SDCARD_CS_ASSERT; //_cs = 0; + int arg = 0; + + /* Request use of SSP0. */ + while(!SSP0_request()) WHILE_WAITING_DO_PROCESS_FUNCTIONS; + + // send a command + SSP0_FLUSH_RX_FIFO; + SSP0_WRITE_BYTE(0x40 | 58); + SSP0_WRITE_BYTE(arg >> 24); + SSP0_WRITE_BYTE(arg >> 16); + SSP0_WRITE_BYTE(arg >> 8); + SSP0_WRITE_BYTE(arg >> 0); + SSP0_WRITE_BYTE(0x95); + while(SSP0_IS_BUSY); + SSP0_FLUSH_RX_FIFO; + + //_spi->write(0x40 | 58); + //_spi->write(arg >> 24); + //_spi->write(arg >> 16); + //_spi->write(arg >> 8); + //_spi->write(arg >> 0); + //_spi->write(0x95); + + // wait for the repsonse (response[7] == 0) + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + for(int i = 0; i < SD_COMMAND_TIMEOUT; i++) { + int response = LPC_SSP0->DR; + if(!(response & 0x80)) { + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + int ocr = LPC_SSP0->DR << 24; + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + ocr |= LPC_SSP0->DR << 16; + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + ocr |= LPC_SSP0->DR << 8; + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + ocr |= LPC_SSP0->DR << 0; +// printf("OCR = 0x%08X\n", ocr); + SDCARD_CS_DEASSERT; //_cs = 1; + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + SSP0_FLUSH_RX_FIFO; + // _spi->write(0xFF); + SSP0_release(); + return response; + } + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + } + SDCARD_CS_DEASSERT; + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + SSP0_release(); + return -1; // timeout +} + +int initialise_card_v1() { + + /* Request use of SSP0. */ + while(!SSP0_request()) WHILE_WAITING_DO_PROCESS_FUNCTIONS; + + for(int i=0; i<SD_COMMAND_TIMEOUT; i++) { + _cmd(55, 0); + if(_cmd(41, 0) == 0) { + SSP0_release(); + return 0; //SDCARD_V1; + } + } + + //fprintf(stderr, "Timeout waiting for v1.x card\n"); + SSP0_release(); + return STA_NOINIT; +} + +int initialise_card_v2() { + int c41, c58, r; + + /* Request use of SSP0. */ + while(!SSP0_request()) WHILE_WAITING_DO_PROCESS_FUNCTIONS; + + for(int i=0; i<SD_COMMAND_TIMEOUT; i++) { + _cmd(55, 0); + c41 = _cmd(41, 0); + if(c41 == 0) { + SSP0_release(); + c58 = _cmd58(); + //fprintf(stderr, "C41 returned %02x and C58 returned %02x\r\n", c41, c58); + return 0; //SDCARD_V2; + } + } + + + //fprintf(stderr, "Timeout waiting for v2.x card response=0x%04x\r\n", c41); + SSP0_release(); + return STA_NOINIT; +} + +DSTATUS disk_initialize(BYTE Drive) { + int i, cmd8_r; + uint32_t cpsr = LPC_SSP0->CPSR; + + //_spi = new SPI(p5, p6, p7); + + /* Request use of SSP0. */ + while(!SSP0_request()) WHILE_WAITING_DO_PROCESS_FUNCTIONS; + + //_spi->frequency(100000); // Set to 100kHz for initialisation + LPC_SSP0->CPSR = 0x64; + SDCARD_CS_ASSERT; //_cs = 1; + + // Initialise the card by clocking it a bit (cs = 1) + for(int i=0; i < 16; i++) { + SSP0_WRITE_BYTE(0xFF); + } + while(SSP0_IS_BUSY); + SSP0_FLUSH_RX_FIFO; + + + + // send CMD0, should return with all zeros except IDLE STATE set (bit 0) + if(_cmd(0, 0) != 0x01) { + //fprintf(stderr, "Not in idle state\n"); + SSP0_release(); + return STA_NOINIT; + } + + for(i = 0; i < SD_COMMAND_TIMEOUT; i++) { + cmd8_r = _cmd8(); + if (cmd8_r == 0 || cmd8_r == 1 || cmd8_r == R1_ILLEGAL_COMMAND) break; + if (cmd8_r == 0 || cmd8_r == R1_ILLEGAL_COMMAND) break; + } + + if ( (cmd8_r & R1_ILLEGAL_COMMAND) != 0) { + //fprintf(stderr, "V1 %d\r\n", cmd8_r); + SSP0_release(); + return initialise_card_v1(); + } + + if (cmd8_r == 0 || cmd8_r == 1) { + //fprintf(stderr, "V2 %d\r\n", cmd8_r); + SSP0_release(); + return initialise_card_v2(); + } + + + //fprintf(stderr, "Not in idle state after sending CMD8 (not an SD card?) response = %d\r\n", cmd8_r); + SSP0_release(); + return STA_NOINIT; + + // ACMD41 to give host capacity support (repeat until not busy) + // ACMD41 is application specific command, so we send APP_CMD (CMD55) beforehand + for(int i=0;; i++) { + _cmd(55, 0); + int response = _cmd(41, 0); + if(response == 0) { + break; + } else if(i > SD_COMMAND_TIMEOUT) { + //fprintf(stderr, "Timeout waiting for card\n"); + SSP0_release(); + return STA_NOINIT; + } + } + + _sectors = _sd_sectors(); + + // Set block length to 512 (CMD16) + if(_cmd(16, 512) != 0) { + //fprintf(stderr, "Set block timeout\n"); + SSP0_release(); + return STA_NOINIT; + } + + LPC_SSP0->CPSR = cpsr; + SSP0_release(); + //_spi->frequency(10000000); // Set to 10MHz for data transfer + return 0; +} + +DRESULT disk_write(BYTE Drive,const BYTE * Buffer, DWORD SectorNumber, BYTE SectorCount) +{ + BYTE i; + + BYTE * MyBufOut = (BYTE *)Buffer; + + /* Request use of SSP0. */ + while(!SSP0_request()) WHILE_WAITING_DO_PROCESS_FUNCTIONS; + + for(i=0;i<SectorCount;i++) + { + // set write address for single block (CMD24) + if(_cmd(24, (SectorNumber + i) * 512 ) != 0) { + SSP0_release(); + return RES_ERROR; + } + + // send the data block + _write(MyBufOut, 512); + + MyBufOut+=512; + } + + SSP0_release(); + return RES_OK; +} + +DRESULT disk_read(BYTE Drive, BYTE * Buffer,DWORD SectorNumber, BYTE SectorCount) +{ + BYTE i; + + /* Request use of SSP0. */ + while(!SSP0_request()) WHILE_WAITING_DO_PROCESS_FUNCTIONS; + + for(i=0;i<SectorCount;i++) + { + // set read address for single block (CMD17) + if(_cmd(17, (SectorNumber+i) * 512) != 0) + { + SSP0_release(); + return RES_ERROR; + } + // receive the data + _read(Buffer, 512); + + Buffer+=512; + } + + SSP0_release(); + return RES_OK; +} + + +extern "C" DWORD get_fattime(void) { + GPS_TIME the_time; + + gps_get_time(&the_time); + + uint32_t year = (the_time.year - 1980) << 25; + uint32_t month = the_time.month << 21; + uint32_t day = the_time.day << 16; + uint32_t hour = the_time.hour << 11; + uint32_t minute = the_time.minute << 5; + uint32_t second = (the_time.second / 2) &0xF; + return (DWORD)(year | month | day | hour | minute | second); +} + +DSTATUS disk_status(BYTE Drive) +{ + return 0; +} + +//************************************************************************************** +// Low Level Sector Access Functions (Castrated versions of Simon Fords C++ MBED class +//************************************************************************************** + +int _cmd(int cmd, int arg) { + volatile int delay; + + for (delay = 500; delay; delay--); + SDCARD_CS_ASSERT; //_cs = 0; + for (delay = 500; delay; delay--); + + // send a command + SSP0_FLUSH_RX_FIFO; + SSP0_WRITE_BYTE(0x40 | cmd); + SSP0_WRITE_BYTE(arg >> 24); + SSP0_WRITE_BYTE(arg >> 16); + SSP0_WRITE_BYTE(arg >> 8); + SSP0_WRITE_BYTE(arg >> 0); + SSP0_WRITE_BYTE(0x95); + while(SSP0_IS_BUSY); + SSP0_FLUSH_RX_FIFO; + + //_spi->write(0x40 | cmd); + //_spi->write(arg >> 24); + //_spi->write(arg >> 16); + //_spi->write(arg >> 8); + //_spi->write(arg >> 0); + //_spi->write(0x95); + + // wait for the repsonse (response[7] == 0) + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + for(int i=0; i<SD_COMMAND_TIMEOUT; i++) { + int response = LPC_SSP0->DR; + if(!(response & 0x80)) { + SDCARD_CS_DEASSERT; //_cs = 1; + return response; + } + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + } + + SDCARD_CS_ASSERT; //_cs = 1; + return -1; // timeout +} + +int _cmdR2(int cmd, int arg) { + int response; + + SDCARD_CS_ASSERT; //_cs = 0; + + // send a command + SSP0_FLUSH_RX_FIFO; + SSP0_WRITE_BYTE(0x40 | cmd); + SSP0_WRITE_BYTE(arg >> 24); + SSP0_WRITE_BYTE(arg >> 16); + SSP0_WRITE_BYTE(arg >> 8); + SSP0_WRITE_BYTE(arg >> 0); + SSP0_WRITE_BYTE(0x95); + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + SSP0_FLUSH_RX_FIFO; + + //_spi->write(0x40 | cmd); + //_spi->write(arg >> 24); + //_spi->write(arg >> 16); + //_spi->write(arg >> 8); + //_spi->write(arg >> 0); + //_spi->write(0x95); + //_spi->write(0xFF); + + // wait for the repsonse (response[7] == 0) + //for(int i=0; i<SD_COMMAND_TIMEOUT; i++) { + response = 0; + SSP0_WRITE_BYTE(0x00); + while(SSP0_IS_BUSY); + response = (LPC_SSP0->DR & 0xFF); + response = (response << 8) & 0xFF00; + SSP0_WRITE_BYTE(0x00); + while(SSP0_IS_BUSY); + response |= (LPC_SSP0->DR & 0xFF); + SDCARD_CS_DEASSERT; //_cs = 1; + return response; + //} + SDCARD_CS_DEASSERT; //_cs = 1; + return -1; // timeout +} + +int _cmd8(void) { + SDCARD_CS_ASSERT; //_cs = 0; + + // send a command + SSP0_FLUSH_RX_FIFO; + SSP0_WRITE_BYTE(0x40 | 8); + SSP0_WRITE_BYTE(00); + SSP0_WRITE_BYTE(00); + SSP0_WRITE_BYTE(01); + SSP0_WRITE_BYTE(0xAA); + SSP0_WRITE_BYTE(0x87); + while(SSP0_IS_BUSY); + SSP0_FLUSH_RX_FIFO; + + //_spi->write(0x40 | 8); // CMD8 + //_spi->write(0x00); // reserved + //_spi->write(0x00); // reserved + //_spi->write(0x01); // 3.3v + //_spi->write(0xAA); // check pattern + //_spi->write(0x87); // crc + + // wait for the repsonse (response[7] == 0) + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + for(int i=0; i<SD_COMMAND_TIMEOUT * 1000; i++) { + char response[5]; + response[0] = LPC_SSP0->DR; + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + for(int j=1; j<5; j++) { + response[i] = LPC_SSP0->DR; + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + } + SDCARD_CS_DEASSERT; //_cs = 1; + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + SSP0_FLUSH_RX_FIFO; + return response[0]; + } + + SDCARD_CS_DEASSERT; //_cs = 1; + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + SSP0_FLUSH_RX_FIFO; + //_spi->write(0xFF); + return -1; // timeout +} + +int _cmd8original(void) { + SDCARD_CS_ASSERT; //_cs = 0; + + // send a command + SSP0_FLUSH_RX_FIFO; + SSP0_WRITE_BYTE(0x40 | 8); + SSP0_WRITE_BYTE(00); + SSP0_WRITE_BYTE(00); + SSP0_WRITE_BYTE(01); + SSP0_WRITE_BYTE(0xAA); + SSP0_WRITE_BYTE(0x87); + while(SSP0_IS_BUSY); + SSP0_FLUSH_RX_FIFO; + + //_spi->write(0x40 | 8); // CMD8 + //_spi->write(0x00); // reserved + //_spi->write(0x00); // reserved + //_spi->write(0x01); // 3.3v + //_spi->write(0xAA); // check pattern + //_spi->write(0x87); // crc + + // wait for the repsonse (response[7] == 0) + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + for(int i=0; i<SD_COMMAND_TIMEOUT * 1000; i++) { + char response[5]; + response[0] = LPC_SSP0->DR; + if(!(response[0] & 0x80)) { + //fprintf(stderr, "RS = %d\r\n", response[0]); + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + for(int j=1; j<5; j++) { + response[i] = LPC_SSP0->DR; + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + } + SDCARD_CS_DEASSERT; //_cs = 1; + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + //_spi->write(0xFF); + return response[0]; + } + } + + SDCARD_CS_DEASSERT; //_cs = 1; + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + SSP0_FLUSH_RX_FIFO; + //_spi->write(0xFF); + return -1; // timeout +} + +int _read(BYTE *buffer, int length) { + SDCARD_CS_ASSERT; //_cs = 0; + + // read until start byte (0xFF) + SSP0_FLUSH_RX_FIFO; + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + while(LPC_SSP0->DR != 0xFE) { + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + } + + // read data + SSP0_FLUSH_RX_FIFO; + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + for(int i=0; i<length; i++) { + buffer[i] = LPC_SSP0->DR; + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + } + SSP0_WRITE_BYTE(0xFF); + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + SSP0_FLUSH_RX_FIFO; + //_spi->write(0xFF); // checksum + //_spi->write(0xFF); + + SDCARD_CS_DEASSERT; //_cs = 1; + return 0; +} + +int _write(BYTE *buffer, int length) { + SDCARD_CS_ASSERT; //_cs = 0; + + // indicate start of block + SSP0_WRITE_BYTE(0xFE); + while(SSP0_IS_BUSY); + //_spi->write(0xFE); + + // write the data + for(int i=0; i<length; i++) { + SSP0_WRITE_BYTE(buffer[i]); + while(SSP0_IS_BUSY); + //_spi->write(buffer[i]); + } + + // write the checksum + SSP0_WRITE_BYTE(0xFF); + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + //_spi->write(0xFF); + //_spi->write(0xFF); + + // check the repsonse token + SSP0_FLUSH_RX_FIFO; + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + if((LPC_SSP0->DR & 0x1F) != 0x05) { + SDCARD_CS_DEASSERT; //_cs = 1; + return 1; + } + + // wait for write to finish + SSP0_FLUSH_RX_FIFO; + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + while(LPC_SSP0->DR == 0) { + SSP0_WRITE_BYTE(0xFF); + while(SSP0_IS_BUSY); + } + + SDCARD_CS_DEASSERT; //_cs = 1; + return 0; +} + +int ext_bits(BYTE *data, int msb, int lsb) { + int bits = 0; + int size = 1 + msb - lsb; + for(int i=0; i<size; i++) { + int position = lsb + i; + int byte = 15 - (position >> 3); + int bit = position & 0x7; + int value = (data[byte] >> bit) & 1; + bits |= value << i; + } + return bits; +} + +int _sd_sectors() { + + // CMD9, Response R2 (R1 byte + 16-byte block read) + if(_cmd(9, 0) != 0) { + //fprintf(stderr, "Didn't get a response from the disk\n"); + return 0; + } + + BYTE csd[16]; + if(_read(csd, 16) != 0) { + //fprintf(stderr, "Couldn't read csd response from disk\n"); + return 0; + } + + // csd_structure : csd[127:126] + // c_size : csd[73:62] + // c_size_mult : csd[49:47] + // read_bl_len : csd[83:80] + + int csd_structure = ext_bits(csd, 127, 126); + int c_size = ext_bits(csd, 73, 62); + int c_size_mult = ext_bits(csd, 49, 47); + int read_bl_len = ext_bits(csd, 83, 80); + + if(csd_structure != 0) { + //fprintf(stderr, "This disk tastes funny! I only know about type 0 CSD structures"); + return 0; + } + + int blocks = (c_size + 1) * (1 << (c_size_mult + 2)); + int block_size = 1 << read_bl_len; + + if(block_size != 512) { + //fprintf(stderr, "This disk tastes funny! I only like 512 byte blocks (%d)\r\n",block_size); + return 0; + } + + return blocks; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flash/FatFS/diskio.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,85 @@ +/*----------------------------------------------------------------------- +/ Low level disk interface modlue include file (C)ChaN, 2010 +/-----------------------------------------------------------------------*/ + +#ifndef _DISKIO +#define _DISKIO + +#define _READONLY 0 /* 1: Remove write functions */ +#define _USE_IOCTL 1 /* 1: Use disk_ioctl fucntion */ + +#include "integer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Status of Disk Functions */ +typedef BYTE DSTATUS; + +/* Results of Disk Functions */ +typedef enum { + RES_OK = 0, /* 0: Successful */ + RES_ERROR, /* 1: R/W Error */ + RES_WRPRT, /* 2: Write Protected */ + RES_NOTRDY, /* 3: Not Ready */ + RES_PARERR /* 4: Invalid Parameter */ +} DRESULT; + + +/*---------------------------------------*/ +/* Prototypes for disk control functions */ + +int assign_drives (int, int); +DSTATUS disk_initialize (BYTE); +DSTATUS disk_status (BYTE); +DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE); +DWORD get_fattime(void); +#if _READONLY == 0 +DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE); +#endif +DRESULT disk_ioctl (BYTE, BYTE, void*); + + + +/* Disk Status Bits (DSTATUS) */ + +#define STA_NOINIT 0x01 /* Drive not initialized */ +#define STA_NODISK 0x02 /* No medium in the drive */ +#define STA_PROTECT 0x04 /* Write protected */ + + +/* Command code for disk_ioctrl fucntion */ + +/* Generic command (defined for FatFs) */ +#define CTRL_SYNC 0 /* Flush disk cache (for write functions) */ +#define GET_SECTOR_COUNT 1 /* Get media size (for only f_mkfs()) */ +#define GET_SECTOR_SIZE 2 /* Get sector size (for multiple sector size (_MAX_SS >= 1024)) */ +#define GET_BLOCK_SIZE 3 /* Get erase block size (for only f_mkfs()) */ +#define CTRL_ERASE_SECTOR 4 /* Force erased a block of sectors (for only _USE_ERASE) */ + +/* Generic command */ +#define CTRL_POWER 5 /* Get/Set power status */ +#define CTRL_LOCK 6 /* Lock/Unlock media removal */ +#define CTRL_EJECT 7 /* Eject media */ + +/* MMC/SDC specific ioctl command */ +#define MMC_GET_TYPE 10 /* Get card type */ +#define MMC_GET_CSD 11 /* Get CSD */ +#define MMC_GET_CID 12 /* Get CID */ +#define MMC_GET_OCR 13 /* Get OCR */ +#define MMC_GET_SDSTAT 14 /* Get SD status */ + +/* ATA/CF specific ioctl command */ +#define ATA_GET_REV 20 /* Get F/W revision */ +#define ATA_GET_MODEL 21 /* Get model name */ +#define ATA_GET_SN 22 /* Get serial number */ + +/* NAND specific ioctl command */ +#define NAND_FORMAT 30 /* Create physical format */ + +#ifdef __cplusplus +} +#endif + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flash/FatFS/ff.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,3735 @@ +/*----------------------------------------------------------------------------/ +/ FatFs - FAT file system module R0.08a (C)ChaN, 2010 +/-----------------------------------------------------------------------------/ +/ FatFs module is a generic FAT file system module for small embedded systems. +/ This is a free software that opened for education, research and commercial +/ developments under license policy of following terms. +/ +/ Copyright (C) 2010, ChaN, all right reserved. +/ +/ * The FatFs module is a free software and there is NO WARRANTY. +/ * No restriction on use. You can use, modify and redistribute it for +/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. +/ * Redistributions of source code must retain the above copyright notice. +/ +/-----------------------------------------------------------------------------/ +/ Feb 26,'06 R0.00 Prototype. +/ +/ Apr 29,'06 R0.01 First stable version. +/ +/ Jun 01,'06 R0.02 Added FAT12 support. +/ Removed unbuffered mode. +/ Fixed a problem on small (<32M) partition. +/ Jun 10,'06 R0.02a Added a configuration option (_FS_MINIMUM). +/ +/ Sep 22,'06 R0.03 Added f_rename(). +/ Changed option _FS_MINIMUM to _FS_MINIMIZE. +/ Dec 11,'06 R0.03a Improved cluster scan algorithm to write files fast. +/ Fixed f_mkdir() creates incorrect directory on FAT32. +/ +/ Feb 04,'07 R0.04 Supported multiple drive system. +/ Changed some interfaces for multiple drive system. +/ Changed f_mountdrv() to f_mount(). +/ Added f_mkfs(). +/ Apr 01,'07 R0.04a Supported multiple partitions on a physical drive. +/ Added a capability of extending file size to f_lseek(). +/ Added minimization level 3. +/ Fixed an endian sensitive code in f_mkfs(). +/ May 05,'07 R0.04b Added a configuration option _USE_NTFLAG. +/ Added FSInfo support. +/ Fixed DBCS name can result FR_INVALID_NAME. +/ Fixed short seek (<= csize) collapses the file object. +/ +/ Aug 25,'07 R0.05 Changed arguments of f_read(), f_write() and f_mkfs(). +/ Fixed f_mkfs() on FAT32 creates incorrect FSInfo. +/ Fixed f_mkdir() on FAT32 creates incorrect directory. +/ Feb 03,'08 R0.05a Added f_truncate() and f_utime(). +/ Fixed off by one error at FAT sub-type determination. +/ Fixed btr in f_read() can be mistruncated. +/ Fixed cached sector is not flushed when create and close without write. +/ +/ Apr 01,'08 R0.06 Added fputc(), fputs(), fprintf() and fgets(). +/ Improved performance of f_lseek() on moving to the same or following cluster. +/ +/ Apr 01,'09 R0.07 Merged Tiny-FatFs as a buffer configuration option. (_FS_TINY) +/ Added long file name support. +/ Added multiple code page support. +/ Added re-entrancy for multitask operation. +/ Added auto cluster size selection to f_mkfs(). +/ Added rewind option to f_readdir(). +/ Changed result code of critical errors. +/ Renamed string functions to avoid name collision. +/ Apr 14,'09 R0.07a Separated out OS dependent code on reentrant cfg. +/ Added multiple sector size support. +/ Jun 21,'09 R0.07c Fixed f_unlink() can return FR_OK on error. +/ Fixed wrong cache control in f_lseek(). +/ Added relative path feature. +/ Added f_chdir() and f_chdrive(). +/ Added proper case conversion to extended char. +/ Nov 03,'09 R0.07e Separated out configuration options from ff.h to ffconf.h. +/ Fixed f_unlink() fails to remove a sub-dir on _FS_RPATH. +/ Fixed name matching error on the 13 char boundary. +/ Added a configuration option, _LFN_UNICODE. +/ Changed f_readdir() to return the SFN with always upper case on non-LFN cfg. +/ +/ May 15,'10 R0.08 Added a memory configuration option. (_USE_LFN = 3) +/ Added file lock feature. (_FS_SHARE) +/ Added fast seek feature. (_USE_FASTSEEK) +/ Changed some types on the API, XCHAR->TCHAR. +/ Changed fname member in the FILINFO structure on Unicode cfg. +/ String functions support UTF-8 encoding files on Unicode cfg. +/ Aug 16,'10 R0.08a Added f_getcwd(). (_FS_RPATH = 2) +/ Added sector erase feature. (_USE_ERASE) +/ Moved file lock semaphore table from fs object to the bss. +/ Fixed a wrong directory entry is created on non-LFN cfg when the given name contains ';'. +/ Fixed f_mkfs() creates wrong FAT32 volume. +/---------------------------------------------------------------------------*/ + +#include "ff.h" /* FatFs configurations and declarations */ +#include "diskio.h" /* Declarations of low level disk I/O functions */ + + +/*-------------------------------------------------------------------------- + + Module Private Definitions + +---------------------------------------------------------------------------*/ + +#if _FATFS != 8255 +#error Wrong include file (ff.h). +#endif + +/* Definitions on sector size */ +#if _MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096 +#error Wrong sector size. +#endif +#if _MAX_SS != 512 +#define SS(fs) ((fs)->ssize) /* Multiple sector size */ +#else +#define SS(fs) 512U /* Fixed sector size */ +#endif + + +/* Reentrancy related */ +#if _FS_REENTRANT +#if _USE_LFN == 1 +#error Static LFN work area must not be used in re-entrant configuration. +#endif +#define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; } +#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } +#else +#define ENTER_FF(fs) +#define LEAVE_FF(fs, res) return res +#endif + +#define ABORT(fs, res) { fp->flag |= FA__ERROR; LEAVE_FF(fs, res); } + + +/* File shareing feature */ +#if _FS_SHARE +#if _FS_READONLY +#error _FS_SHARE must be 0 on read-only cfg. +#endif +typedef struct { + FATFS *fs; /* File ID 1, volume (NULL:blank entry) */ + DWORD clu; /* File ID 2, directory */ + WORD idx; /* File ID 3, directory index */ + WORD ctr; /* File open counter, 0:none, 0x01..0xFF:read open count, 0x100:write mode */ +} FILESEM; +#endif + + +/* Misc definitions */ +#define LD_CLUST(dir) (((DWORD)LD_WORD(dir+DIR_FstClusHI)<<16) | LD_WORD(dir+DIR_FstClusLO)) +#define ST_CLUST(dir,cl) {ST_WORD(dir+DIR_FstClusLO, cl); ST_WORD(dir+DIR_FstClusHI, (DWORD)cl>>16);} + + +/* Character code support macros */ +#define IsUpper(c) (((c)>='A')&&((c)<='Z')) +#define IsLower(c) (((c)>='a')&&((c)<='z')) +#define IsDigit(c) (((c)>='0')&&((c)<='9')) + +#if _DF1S /* Code page is DBCS */ + +#ifdef _DF2S /* Two 1st byte areas */ +#define IsDBCS1(c) (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E)) +#else /* One 1st byte area */ +#define IsDBCS1(c) ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) +#endif + +#ifdef _DS3S /* Three 2nd byte areas */ +#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E)) +#else /* Two 2nd byte areas */ +#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E)) +#endif + +#else /* Code page is SBCS */ + +#define IsDBCS1(c) 0 +#define IsDBCS2(c) 0 + +#endif /* _DF1S */ + + +/* Name status flags */ +#define NS 11 /* Offset of name status byte */ +#define NS_LOSS 0x01 /* Out of 8.3 format */ +#define NS_LFN 0x02 /* Force to create LFN entry */ +#define NS_LAST 0x04 /* Last segment */ +#define NS_BODY 0x08 /* Lower case flag (body) */ +#define NS_EXT 0x10 /* Lower case flag (ext) */ +#define NS_DOT 0x20 /* Dot entry */ + + +/* FAT sub-type boundaries */ +/* Note that the FAT spec by Microsoft says 4085 but Windows works with 4087! */ +#define MIN_FAT16 4086 /* Minimum number of clusters for FAT16 */ +#define MIN_FAT32 65526 /* Minimum number of clusters for FAT32 */ + + +/* FatFs refers the members in the FAT structures as byte array instead of +/ structure member because there are incompatibility of the packing option +/ between compilers. */ + +#define BS_jmpBoot 0 +#define BS_OEMName 3 +#define BPB_BytsPerSec 11 +#define BPB_SecPerClus 13 +#define BPB_RsvdSecCnt 14 +#define BPB_NumFATs 16 +#define BPB_RootEntCnt 17 +#define BPB_TotSec16 19 +#define BPB_Media 21 +#define BPB_FATSz16 22 +#define BPB_SecPerTrk 24 +#define BPB_NumHeads 26 +#define BPB_HiddSec 28 +#define BPB_TotSec32 32 +#define BS_DrvNum 36 +#define BS_BootSig 38 +#define BS_VolID 39 +#define BS_VolLab 43 +#define BS_FilSysType 54 +#define BPB_FATSz32 36 +#define BPB_ExtFlags 40 +#define BPB_FSVer 42 +#define BPB_RootClus 44 +#define BPB_FSInfo 48 +#define BPB_BkBootSec 50 +#define BS_DrvNum32 64 +#define BS_BootSig32 66 +#define BS_VolID32 67 +#define BS_VolLab32 71 +#define BS_FilSysType32 82 +#define FSI_LeadSig 0 +#define FSI_StrucSig 484 +#define FSI_Free_Count 488 +#define FSI_Nxt_Free 492 +#define MBR_Table 446 +#define BS_55AA 510 + +#define DIR_Name 0 +#define DIR_Attr 11 +#define DIR_NTres 12 +#define DIR_CrtTime 14 +#define DIR_CrtDate 16 +#define DIR_FstClusHI 20 +#define DIR_WrtTime 22 +#define DIR_WrtDate 24 +#define DIR_FstClusLO 26 +#define DIR_FileSize 28 +#define LDIR_Ord 0 +#define LDIR_Attr 11 +#define LDIR_Type 12 +#define LDIR_Chksum 13 +#define LDIR_FstClusLO 26 + + + +/*------------------------------------------------------------*/ +/* Work area */ + +#if _VOLUMES +static +FATFS *FatFs[_VOLUMES]; /* Pointer to the file system objects (logical drives) */ +#else +#error Number of drives must not be 0. +#endif + +static +WORD Fsid; /* File system mount ID */ + +#if _FS_RPATH +static +BYTE CurrVol; /* Current drive */ +#endif + +#if _FS_SHARE +static +FILESEM Files[_FS_SHARE]; /* File lock semaphores */ +#endif + +#if _USE_LFN == 0 /* No LFN */ +#define DEF_NAMEBUF BYTE sfn[12] +#define INIT_BUF(dobj) (dobj).fn = sfn +#define FREE_BUF() + +#elif _USE_LFN == 1 /* LFN with static LFN working buffer */ +static WCHAR LfnBuf[_MAX_LFN+1]; +#define DEF_NAMEBUF BYTE sfn[12] +#define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = LfnBuf; } +#define FREE_BUF() + +#elif _USE_LFN == 2 /* LFN with dynamic LFN working buffer on the stack */ +#define DEF_NAMEBUF BYTE sfn[12]; WCHAR lbuf[_MAX_LFN+1] +#define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = lbuf; } +#define FREE_BUF() + +#elif _USE_LFN == 3 /* LFN with dynamic LFN working buffer on the heap */ +#define DEF_NAMEBUF BYTE sfn[12]; WCHAR *lfn +#define INIT_BUF(dobj) { lfn = ff_memalloc((_MAX_LFN + 1) * 2); \ + if (!lfn) LEAVE_FF((dobj).fs, FR_NOT_ENOUGH_CORE); \ + (dobj).lfn = lfn; (dobj).fn = sfn; } +#define FREE_BUF() ff_memfree(lfn) + +#else +#error Wrong LFN configuration. +#endif + + + + +/*-------------------------------------------------------------------------- + + Module Private Functions + +---------------------------------------------------------------------------*/ + + +/*-----------------------------------------------------------------------*/ +/* String functions */ +/*-----------------------------------------------------------------------*/ + +/* Copy memory to memory */ +static +void mem_cpy (void* dst, const void* src, UINT cnt) { + BYTE *d = (BYTE*)dst; + const BYTE *s = (const BYTE*)src; + +#if _WORD_ACCESS == 1 + while (cnt >= sizeof(int)) { + *(int*)d = *(int*)s; + d += sizeof(int); s += sizeof(int); + cnt -= sizeof(int); + } +#endif + while (cnt--) + *d++ = *s++; +} + +/* Fill memory */ +static +void mem_set (void* dst, int val, UINT cnt) { + BYTE *d = (BYTE*)dst; + + while (cnt--) + *d++ = (BYTE)val; +} + +/* Compare memory to memory */ +static +int mem_cmp (const void* dst, const void* src, UINT cnt) { + const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src; + int r = 0; + + while (cnt-- && (r = *d++ - *s++) == 0) ; + return r; +} + +/* Check if chr is contained in the string */ +static +int chk_chr (const char* str, int chr) { + while (*str && *str != chr) str++; + return *str; +} + + + +/*-----------------------------------------------------------------------*/ +/* Request/Release grant to access the volume */ +/*-----------------------------------------------------------------------*/ +#if _FS_REENTRANT + +static +int lock_fs ( + FATFS *fs /* File system object */ +) +{ + return ff_req_grant(fs->sobj); +} + + +static +void unlock_fs ( + FATFS *fs, /* File system object */ + FRESULT res /* Result code to be returned */ +) +{ + if (res != FR_NOT_ENABLED && + res != FR_INVALID_DRIVE && + res != FR_INVALID_OBJECT && + res != FR_TIMEOUT) { + ff_rel_grant(fs->sobj); + } +} +#endif + + + +/*-----------------------------------------------------------------------*/ +/* File shareing control functions */ +/*-----------------------------------------------------------------------*/ +#if _FS_SHARE + +static +FRESULT chk_lock ( /* Check if the file can be accessed */ + DIR* dj, /* Directory object pointing the file to be checked */ + int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */ +) +{ + UINT i, be; + + /* Search file semaphore table */ + for (i = be = 0; i < _FS_SHARE; i++) { + if (Files[i].fs) { /* Existing entry */ + if (Files[i].fs == dj->fs && /* Check if the file matched with an open file */ + Files[i].clu == dj->sclust && + Files[i].idx == dj->index) break; + } else { /* Blank entry */ + be++; + } + } + if (i == _FS_SHARE) /* The file is not opened */ + return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES; /* Is there a blank entry for new file? */ + + /* The file has been opened. Reject any open against writing file and all write mode open */ + return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK; +} + + +static +int enq_lock ( /* Check if an entry is available for a new file */ + FATFS* fs /* File system object */ +) +{ + UINT i; + + for (i = 0; i < _FS_SHARE && Files[i].fs; i++) ; + return (i == _FS_SHARE) ? 0 : 1; +} + + +static +UINT inc_lock ( /* Increment file open counter and returns its index (0:int error) */ + DIR* dj, /* Directory object pointing the file to register or increment */ + int acc /* Desired access mode (0:Read, !0:Write) */ +) +{ + UINT i; + + + for (i = 0; i < _FS_SHARE; i++) { /* Find the file */ + if (Files[i].fs == dj->fs && + Files[i].clu == dj->sclust && + Files[i].idx == dj->index) break; + } + + if (i == _FS_SHARE) { /* Not opened. Register it as new. */ + for (i = 0; i < _FS_SHARE && Files[i].fs; i++) ; + if (i == _FS_SHARE) return 0; /* No space to register (int err) */ + Files[i].fs = dj->fs; + Files[i].clu = dj->sclust; + Files[i].idx = dj->index; + Files[i].ctr = 0; + } + + if (acc && Files[i].ctr) return 0; /* Access violation (int err) */ + + Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1; /* Set semaphore value */ + + return i + 1; +} + + +static +FRESULT dec_lock ( /* Decrement file open counter */ + UINT i /* Semaphore index */ +) +{ + WORD n; + FRESULT res; + + + if (--i < _FS_SHARE) { + n = Files[i].ctr; + if (n == 0x100) n = 0; + if (n) n--; + Files[i].ctr = n; + if (!n) Files[i].fs = 0; + res = FR_OK; + } else { + res = FR_INT_ERR; + } + return res; +} + + +static +void clear_lock ( /* Clear lock entries of the volume */ + FATFS *fs +) +{ + UINT i; + + for (i = 0; i < _FS_SHARE; i++) { + if (Files[i].fs == fs) Files[i].fs = 0; + } +} +#endif + + + +/*-----------------------------------------------------------------------*/ +/* Change window offset */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT move_window ( + FATFS *fs, /* File system object */ + DWORD sector /* Sector number to make appearance in the fs->win[] */ +) /* Move to zero only writes back dirty window */ +{ + DWORD wsect; + + + wsect = fs->winsect; + if (wsect != sector) { /* Changed current window */ +#if !_FS_READONLY + if (fs->wflag) { /* Write back dirty window if needed */ + if (disk_write(fs->drv, fs->win, wsect, 1) != RES_OK) + return FR_DISK_ERR; + fs->wflag = 0; + if (wsect < (fs->fatbase + fs->fsize)) { /* In FAT area */ + BYTE nf; + for (nf = fs->n_fats; nf > 1; nf--) { /* Reflect the change to all FAT copies */ + wsect += fs->fsize; + disk_write(fs->drv, fs->win, wsect, 1); + } + } + } +#endif + if (sector) { + if (disk_read(fs->drv, fs->win, sector, 1) != RES_OK) + return FR_DISK_ERR; + fs->winsect = sector; + } + } + + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Clean-up cached data */ +/*-----------------------------------------------------------------------*/ +#if !_FS_READONLY +static +FRESULT sync ( /* FR_OK: successful, FR_DISK_ERR: failed */ + FATFS *fs /* File system object */ +) +{ + FRESULT res; + + + res = move_window(fs, 0); + if (res == FR_OK) { + /* Update FSInfo sector if needed */ + if (fs->fs_type == FS_FAT32 && fs->fsi_flag) { + fs->winsect = 0; + mem_set(fs->win, 0, 512); + ST_WORD(fs->win+BS_55AA, 0xAA55); + ST_DWORD(fs->win+FSI_LeadSig, 0x41615252); + ST_DWORD(fs->win+FSI_StrucSig, 0x61417272); + ST_DWORD(fs->win+FSI_Free_Count, fs->free_clust); + ST_DWORD(fs->win+FSI_Nxt_Free, fs->last_clust); + disk_write(fs->drv, fs->win, fs->fsi_sector, 1); + fs->fsi_flag = 0; + } + /* Make sure that no pending write process in the physical drive */ + if (disk_ioctl(fs->drv, CTRL_SYNC, (void*)0) != RES_OK) + res = FR_DISK_ERR; + } + + return res; +} +#endif + + + + +/*-----------------------------------------------------------------------*/ +/* Get sector# from cluster# */ +/*-----------------------------------------------------------------------*/ + + +DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */ + FATFS *fs, /* File system object */ + DWORD clst /* Cluster# to be converted */ +) +{ + clst -= 2; + if (clst >= (fs->n_fatent - 2)) return 0; /* Invalid cluster# */ + return clst * fs->csize + fs->database; +} + + + + +/*-----------------------------------------------------------------------*/ +/* FAT access - Read value of a FAT entry */ +/*-----------------------------------------------------------------------*/ + + +DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, Else:Cluster status */ + FATFS *fs, /* File system object */ + DWORD clst /* Cluster# to get the link information */ +) +{ + UINT wc, bc; + BYTE *p; + + + if (clst < 2 || clst >= fs->n_fatent) /* Chack range */ + return 1; + + switch (fs->fs_type) { + case FS_FAT12 : + bc = (UINT)clst; bc += bc / 2; + if (move_window(fs, fs->fatbase + (bc / SS(fs)))) break; + wc = fs->win[bc % SS(fs)]; bc++; + if (move_window(fs, fs->fatbase + (bc / SS(fs)))) break; + wc |= fs->win[bc % SS(fs)] << 8; + return (clst & 1) ? (wc >> 4) : (wc & 0xFFF); + + case FS_FAT16 : + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)))) break; + p = &fs->win[clst * 2 % SS(fs)]; + return LD_WORD(p); + + case FS_FAT32 : + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)))) break; + p = &fs->win[clst * 4 % SS(fs)]; + return LD_DWORD(p) & 0x0FFFFFFF; + } + + return 0xFFFFFFFF; /* An error occurred at the disk I/O layer */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* FAT access - Change value of a FAT entry */ +/*-----------------------------------------------------------------------*/ +#if !_FS_READONLY + +FRESULT put_fat ( + FATFS *fs, /* File system object */ + DWORD clst, /* Cluster# to be changed in range of 2 to fs->n_fatent - 1 */ + DWORD val /* New value to mark the cluster */ +) +{ + UINT bc; + BYTE *p; + FRESULT res; + + + if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ + res = FR_INT_ERR; + + } else { + switch (fs->fs_type) { + case FS_FAT12 : + bc = clst; bc += bc / 2; + res = move_window(fs, fs->fatbase + (bc / SS(fs))); + if (res != FR_OK) break; + p = &fs->win[bc % SS(fs)]; + *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; + bc++; + fs->wflag = 1; + res = move_window(fs, fs->fatbase + (bc / SS(fs))); + if (res != FR_OK) break; + p = &fs->win[bc % SS(fs)]; + *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); + break; + + case FS_FAT16 : + res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))); + if (res != FR_OK) break; + p = &fs->win[clst * 2 % SS(fs)]; + ST_WORD(p, (WORD)val); + break; + + case FS_FAT32 : + res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))); + if (res != FR_OK) break; + p = &fs->win[clst * 4 % SS(fs)]; + val |= LD_DWORD(p) & 0xF0000000; + ST_DWORD(p, val); + break; + + default : + res = FR_INT_ERR; + } + fs->wflag = 1; + } + + return res; +} +#endif /* !_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* FAT handling - Remove a cluster chain */ +/*-----------------------------------------------------------------------*/ +#if !_FS_READONLY +static +FRESULT remove_chain ( + FATFS *fs, /* File system object */ + DWORD clst /* Cluster# to remove a chain from */ +) +{ + FRESULT res; + DWORD nxt; +#if _USE_ERASE + DWORD scl = clst, ecl = clst, resion[2]; +#endif + + if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ + res = FR_INT_ERR; + + } else { + res = FR_OK; + while (clst < fs->n_fatent) { /* Not a last link? */ + nxt = get_fat(fs, clst); /* Get cluster status */ + if (nxt == 0) break; /* Empty cluster? */ + if (nxt == 1) { res = FR_INT_ERR; break; } /* Internal error? */ + if (nxt == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } /* Disk error? */ + res = put_fat(fs, clst, 0); /* Mark the cluster "empty" */ + if (res != FR_OK) break; + if (fs->free_clust != 0xFFFFFFFF) { /* Update FSInfo */ + fs->free_clust++; + fs->fsi_flag = 1; + } +#if _USE_ERASE + if (ecl + 1 == nxt) { /* Next cluster is contiguous */ + ecl = nxt; + } else { /* End of contiguous clusters */ + resion[0] = clust2sect(fs, scl); /* Start sector */ + resion[1] = clust2sect(fs, ecl) + fs->csize - 1; /* End sector */ + disk_ioctl(fs->drv, CTRL_ERASE_SECTOR, resion); /* Erase the block */ + scl = ecl = nxt; + } +#endif + clst = nxt; /* Next cluster */ + } + } + + return res; +} +#endif + + + + +/*-----------------------------------------------------------------------*/ +/* FAT handling - Stretch or Create a cluster chain */ +/*-----------------------------------------------------------------------*/ +#if !_FS_READONLY +static +DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ + FATFS *fs, /* File system object */ + DWORD clst /* Cluster# to stretch. 0 means create a new chain. */ +) +{ + DWORD cs, ncl, scl; + FRESULT res; + + + if (clst == 0) { /* Create a new chain */ + scl = fs->last_clust; /* Get suggested start point */ + if (!scl || scl >= fs->n_fatent) scl = 1; + } + else { /* Stretch the current chain */ + cs = get_fat(fs, clst); /* Check the cluster status */ + if (cs < 2) return 1; /* It is an invalid cluster */ + if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */ + scl = clst; + } + + ncl = scl; /* Start cluster */ + for (;;) { + ncl++; /* Next cluster */ + if (ncl >= fs->n_fatent) { /* Wrap around */ + ncl = 2; + if (ncl > scl) return 0; /* No free cluster */ + } + cs = get_fat(fs, ncl); /* Get the cluster status */ + if (cs == 0) break; /* Found a free cluster */ + if (cs == 0xFFFFFFFF || cs == 1)/* An error occurred */ + return cs; + if (ncl == scl) return 0; /* No free cluster */ + } + + res = put_fat(fs, ncl, 0x0FFFFFFF); /* Mark the new cluster "last link" */ + if (res == FR_OK && clst != 0) { + res = put_fat(fs, clst, ncl); /* Link it to the previous one if needed */ + } + if (res == FR_OK) { + fs->last_clust = ncl; /* Update FSINFO */ + if (fs->free_clust != 0xFFFFFFFF) { + fs->free_clust--; + fs->fsi_flag = 1; + } + } else { + ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; + } + + return ncl; /* Return new cluster number or error code */ +} +#endif /* !_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Set directory index */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_sdi ( + DIR *dj, /* Pointer to directory object */ + WORD idx /* Directory index number */ +) +{ + DWORD clst; + WORD ic; + + + dj->index = idx; + clst = dj->sclust; + if (clst == 1 || clst >= dj->fs->n_fatent) /* Check start cluster range */ + return FR_INT_ERR; + if (!clst && dj->fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */ + clst = dj->fs->dirbase; + + if (clst == 0) { /* Static table (root-dir in FAT12/16) */ + dj->clust = clst; + if (idx >= dj->fs->n_rootdir) /* Index is out of range */ + return FR_INT_ERR; + dj->sect = dj->fs->dirbase + idx / (SS(dj->fs) / 32); /* Sector# */ + } + else { /* Dynamic table (sub-dirs or root-dir in FAT32) */ + ic = SS(dj->fs) / 32 * dj->fs->csize; /* Entries per cluster */ + while (idx >= ic) { /* Follow cluster chain */ + clst = get_fat(dj->fs, clst); /* Get next cluster */ + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ + if (clst < 2 || clst >= dj->fs->n_fatent) /* Reached to end of table or int error */ + return FR_INT_ERR; + idx -= ic; + } + dj->clust = clst; + dj->sect = clust2sect(dj->fs, clst) + idx / (SS(dj->fs) / 32); /* Sector# */ + } + + dj->dir = dj->fs->win + (idx % (SS(dj->fs) / 32)) * 32; /* Ptr to the entry in the sector */ + + return FR_OK; /* Seek succeeded */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Move directory index next */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT and could not stretch */ + DIR *dj, /* Pointer to directory object */ + int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ +) +{ + DWORD clst; + WORD i; + + + i = dj->index + 1; + if (!i || !dj->sect) /* Report EOT when index has reached 65535 */ + return FR_NO_FILE; + + if (!(i % (SS(dj->fs) / 32))) { /* Sector changed? */ + dj->sect++; /* Next sector */ + + if (dj->clust == 0) { /* Static table */ + if (i >= dj->fs->n_rootdir) /* Report EOT when end of table */ + return FR_NO_FILE; + } + else { /* Dynamic table */ + if (((i / (SS(dj->fs) / 32)) & (dj->fs->csize - 1)) == 0) { /* Cluster changed? */ + clst = get_fat(dj->fs, dj->clust); /* Get next cluster */ + if (clst <= 1) return FR_INT_ERR; + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; + if (clst >= dj->fs->n_fatent) { /* When it reached end of dynamic table */ +#if !_FS_READONLY + BYTE c; + if (!stretch) return FR_NO_FILE; /* When do not stretch, report EOT */ + clst = create_chain(dj->fs, dj->clust); /* Stretch cluster chain */ + if (clst == 0) return FR_DENIED; /* No free cluster */ + if (clst == 1) return FR_INT_ERR; + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; + /* Clean-up stretched table */ + if (move_window(dj->fs, 0)) return FR_DISK_ERR; /* Flush active window */ + mem_set(dj->fs->win, 0, SS(dj->fs)); /* Clear window buffer */ + dj->fs->winsect = clust2sect(dj->fs, clst); /* Cluster start sector */ + for (c = 0; c < dj->fs->csize; c++) { /* Fill the new cluster with 0 */ + dj->fs->wflag = 1; + if (move_window(dj->fs, 0)) return FR_DISK_ERR; + dj->fs->winsect++; + } + dj->fs->winsect -= c; /* Rewind window address */ +#else + return FR_NO_FILE; /* Report EOT */ +#endif + } + dj->clust = clst; /* Initialize data for new cluster */ + dj->sect = clust2sect(dj->fs, clst); + } + } + } + + dj->index = i; + dj->dir = dj->fs->win + (i % (SS(dj->fs) / 32)) * 32; + + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* LFN handling - Test/Pick/Fit an LFN segment from/to directory entry */ +/*-----------------------------------------------------------------------*/ +#if _USE_LFN +static +const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN chars in the directory entry */ + + +static +int cmp_lfn ( /* 1:Matched, 0:Not matched */ + WCHAR *lfnbuf, /* Pointer to the LFN to be compared */ + BYTE *dir /* Pointer to the directory entry containing a part of LFN */ +) +{ + UINT i, s; + WCHAR wc, uc; + + + i = ((dir[LDIR_Ord] & 0xBF) - 1) * 13; /* Get offset in the LFN buffer */ + s = 0; wc = 1; + do { + uc = LD_WORD(dir+LfnOfs[s]); /* Pick an LFN character from the entry */ + if (wc) { /* Last char has not been processed */ + wc = ff_wtoupper(uc); /* Convert it to upper case */ + if (i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++])) /* Compare it */ + return 0; /* Not matched */ + } else { + if (uc != 0xFFFF) return 0; /* Check filler */ + } + } while (++s < 13); /* Repeat until all chars in the entry are checked */ + + if ((dir[LDIR_Ord] & 0x40) && wc && lfnbuf[i]) /* Last segment matched but different length */ + return 0; + + return 1; /* The part of LFN matched */ +} + + + +static +int pick_lfn ( /* 1:Succeeded, 0:Buffer overflow */ + WCHAR *lfnbuf, /* Pointer to the Unicode-LFN buffer */ + BYTE *dir /* Pointer to the directory entry */ +) +{ + UINT i, s; + WCHAR wc, uc; + + + i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ + + s = 0; wc = 1; + do { + uc = LD_WORD(dir+LfnOfs[s]); /* Pick an LFN character from the entry */ + if (wc) { /* Last char has not been processed */ + if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ + lfnbuf[i++] = wc = uc; /* Store it */ + } else { + if (uc != 0xFFFF) return 0; /* Check filler */ + } + } while (++s < 13); /* Read all character in the entry */ + + if (dir[LDIR_Ord] & 0x40) { /* Put terminator if it is the last LFN part */ + if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ + lfnbuf[i] = 0; + } + + return 1; +} + + +#if !_FS_READONLY +static +void fit_lfn ( + const WCHAR *lfnbuf, /* Pointer to the LFN buffer */ + BYTE *dir, /* Pointer to the directory entry */ + BYTE ord, /* LFN order (1-20) */ + BYTE sum /* SFN sum */ +) +{ + UINT i, s; + WCHAR wc; + + + dir[LDIR_Chksum] = sum; /* Set check sum */ + dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */ + dir[LDIR_Type] = 0; + ST_WORD(dir+LDIR_FstClusLO, 0); + + i = (ord - 1) * 13; /* Get offset in the LFN buffer */ + s = wc = 0; + do { + if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective char */ + ST_WORD(dir+LfnOfs[s], wc); /* Put it */ + if (!wc) wc = 0xFFFF; /* Padding chars following last char */ + } while (++s < 13); + if (wc == 0xFFFF || !lfnbuf[i]) ord |= 0x40; /* Bottom LFN part is the start of LFN sequence */ + dir[LDIR_Ord] = ord; /* Set the LFN order */ +} + +#endif +#endif + + + +/*-----------------------------------------------------------------------*/ +/* Create numbered name */ +/*-----------------------------------------------------------------------*/ +#if _USE_LFN +void gen_numname ( + BYTE *dst, /* Pointer to generated SFN */ + const BYTE *src, /* Pointer to source SFN to be modified */ + const WCHAR *lfn, /* Pointer to LFN */ + WORD seq /* Sequence number */ +) +{ + BYTE ns[8], c; + UINT i, j; + + + mem_cpy(dst, src, 11); + + if (seq > 5) { /* On many collisions, generate a hash number instead of sequential number */ + do seq = (seq >> 1) + (seq << 15) + (WORD)*lfn++; while (*lfn); + } + + /* itoa */ + i = 7; + do { + c = (seq % 16) + '0'; + if (c > '9') c += 7; + ns[i--] = c; + seq /= 16; + } while (seq); + ns[i] = '~'; + + /* Append the number */ + for (j = 0; j < i && dst[j] != ' '; j++) { + if (IsDBCS1(dst[j])) { + if (j == i - 1) break; + j++; + } + } + do { + dst[j++] = (i < 8) ? ns[i++] : ' '; + } while (j < 8); +} +#endif + + + + +/*-----------------------------------------------------------------------*/ +/* Calculate sum of an SFN */ +/*-----------------------------------------------------------------------*/ +#if _USE_LFN +static +BYTE sum_sfn ( + const BYTE *dir /* Ptr to directory entry */ +) +{ + BYTE sum = 0; + UINT n = 11; + + do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n); + return sum; +} +#endif + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Find an object in the directory */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_find ( + DIR *dj /* Pointer to the directory object linked to the file name */ +) +{ + FRESULT res; + BYTE c, *dir; +#if _USE_LFN + BYTE a, ord, sum; +#endif + + res = dir_sdi(dj, 0); /* Rewind directory object */ + if (res != FR_OK) return res; + +#if _USE_LFN + ord = sum = 0xFF; +#endif + do { + res = move_window(dj->fs, dj->sect); + if (res != FR_OK) break; + dir = dj->dir; /* Ptr to the directory entry of current index */ + c = dir[DIR_Name]; + if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ +#if _USE_LFN /* LFN configuration */ + a = dir[DIR_Attr] & AM_MASK; + if (c == 0xE5 || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ + ord = 0xFF; + } else { + if (a == AM_LFN) { /* An LFN entry is found */ + if (dj->lfn) { + if (c & 0x40) { /* Is it start of LFN sequence? */ + sum = dir[LDIR_Chksum]; + c &= 0xBF; ord = c; /* LFN start order */ + dj->lfn_idx = dj->index; + } + /* Check validity of the LFN entry and compare it with given name */ + ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF; + } + } else { /* An SFN entry is found */ + if (!ord && sum == sum_sfn(dir)) break; /* LFN matched? */ + ord = 0xFF; dj->lfn_idx = 0xFFFF; /* Reset LFN sequence */ + if (!(dj->fn[NS] & NS_LOSS) && !mem_cmp(dir, dj->fn, 11)) break; /* SFN matched? */ + } + } +#else /* Non LFN configuration */ + if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dj->fn, 11)) /* Is it a valid entry? */ + break; +#endif + res = dir_next(dj, 0); /* Next entry */ + } while (res == FR_OK); + + return res; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Read an object from the directory */ +/*-----------------------------------------------------------------------*/ +#if _FS_MINIMIZE <= 1 +static +FRESULT dir_read ( + DIR *dj /* Pointer to the directory object that pointing the entry to be read */ +) +{ + FRESULT res; + BYTE c, *dir; +#if _USE_LFN + BYTE a, ord = 0xFF, sum = 0xFF; +#endif + + res = FR_NO_FILE; + while (dj->sect) { + res = move_window(dj->fs, dj->sect); + if (res != FR_OK) break; + dir = dj->dir; /* Ptr to the directory entry of current index */ + c = dir[DIR_Name]; + if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ +#if _USE_LFN /* LFN configuration */ + a = dir[DIR_Attr] & AM_MASK; + if (c == 0xE5 || (!_FS_RPATH && c == '.') || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ + ord = 0xFF; + } else { + if (a == AM_LFN) { /* An LFN entry is found */ + if (c & 0x40) { /* Is it start of LFN sequence? */ + sum = dir[LDIR_Chksum]; + c &= 0xBF; ord = c; + dj->lfn_idx = dj->index; + } + /* Check LFN validity and capture it */ + ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF; + } else { /* An SFN entry is found */ + if (ord || sum != sum_sfn(dir)) /* Is there a valid LFN? */ + dj->lfn_idx = 0xFFFF; /* It has no LFN. */ + break; + } + } +#else /* Non LFN configuration */ + if (c != 0xE5 && (_FS_RPATH || c != '.') && !(dir[DIR_Attr] & AM_VOL)) /* Is it a valid entry? */ + break; +#endif + res = dir_next(dj, 0); /* Next entry */ + if (res != FR_OK) break; + } + + if (res != FR_OK) dj->sect = 0; + + return res; +} +#endif + + + +/*-----------------------------------------------------------------------*/ +/* Register an object to the directory */ +/*-----------------------------------------------------------------------*/ +#if !_FS_READONLY +static +FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many SFN collision, FR_DISK_ERR:Disk error */ + DIR *dj /* Target directory with object name to be created */ +) +{ + FRESULT res; + BYTE c, *dir; +#if _USE_LFN /* LFN configuration */ + WORD n, ne, is; + BYTE sn[12], *fn, sum; + WCHAR *lfn; + + + fn = dj->fn; lfn = dj->lfn; + mem_cpy(sn, fn, 12); + + if (_FS_RPATH && (sn[NS] & NS_DOT)) /* Cannot create dot entry */ + return FR_INVALID_NAME; + + if (sn[NS] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ + fn[NS] = 0; dj->lfn = 0; /* Find only SFN */ + for (n = 1; n < 100; n++) { + gen_numname(fn, sn, lfn, n); /* Generate a numbered name */ + res = dir_find(dj); /* Check if the name collides with existing SFN */ + if (res != FR_OK) break; + } + if (n == 100) return FR_DENIED; /* Abort if too many collisions */ + if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */ + fn[NS] = sn[NS]; dj->lfn = lfn; + } + + if (sn[NS] & NS_LFN) { /* When LFN is to be created, reserve an SFN + LFN entries. */ + for (ne = 0; lfn[ne]; ne++) ; + ne = (ne + 25) / 13; + } else { /* Otherwise reserve only an SFN entry. */ + ne = 1; + } + + /* Reserve contiguous entries */ + res = dir_sdi(dj, 0); + if (res != FR_OK) return res; + n = is = 0; + do { + res = move_window(dj->fs, dj->sect); + if (res != FR_OK) break; + c = *dj->dir; /* Check the entry status */ + if (c == 0xE5 || c == 0) { /* Is it a blank entry? */ + if (n == 0) is = dj->index; /* First index of the contiguous entry */ + if (++n == ne) break; /* A contiguous entry that required count is found */ + } else { + n = 0; /* Not a blank entry. Restart to search */ + } + res = dir_next(dj, 1); /* Next entry with table stretch */ + } while (res == FR_OK); + + if (res == FR_OK && ne > 1) { /* Initialize LFN entry if needed */ + res = dir_sdi(dj, is); + if (res == FR_OK) { + sum = sum_sfn(dj->fn); /* Sum of the SFN tied to the LFN */ + ne--; + do { /* Store LFN entries in bottom first */ + res = move_window(dj->fs, dj->sect); + if (res != FR_OK) break; + fit_lfn(dj->lfn, dj->dir, (BYTE)ne, sum); + dj->fs->wflag = 1; + res = dir_next(dj, 0); /* Next entry */ + } while (res == FR_OK && --ne); + } + } + +#else /* Non LFN configuration */ + res = dir_sdi(dj, 0); + if (res == FR_OK) { + do { /* Find a blank entry for the SFN */ + res = move_window(dj->fs, dj->sect); + if (res != FR_OK) break; + c = *dj->dir; + if (c == 0xE5 || c == 0) break; /* Is it a blank entry? */ + res = dir_next(dj, 1); /* Next entry with table stretch */ + } while (res == FR_OK); + } +#endif + + if (res == FR_OK) { /* Initialize the SFN entry */ + res = move_window(dj->fs, dj->sect); + if (res == FR_OK) { + dir = dj->dir; + mem_set(dir, 0, 32); /* Clean the entry */ + mem_cpy(dir, dj->fn, 11); /* Put SFN */ +#if _USE_LFN + dir[DIR_NTres] = *(dj->fn+NS) & (NS_BODY | NS_EXT); /* Put NT flag */ +#endif + dj->fs->wflag = 1; + } + } + + return res; +} +#endif /* !_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* Remove an object from the directory */ +/*-----------------------------------------------------------------------*/ +#if !_FS_READONLY && !_FS_MINIMIZE +static +FRESULT dir_remove ( /* FR_OK: Successful, FR_DISK_ERR: A disk error */ + DIR *dj /* Directory object pointing the entry to be removed */ +) +{ + FRESULT res; +#if _USE_LFN /* LFN configuration */ + WORD i; + + i = dj->index; /* SFN index */ + res = dir_sdi(dj, (WORD)((dj->lfn_idx == 0xFFFF) ? i : dj->lfn_idx)); /* Goto the SFN or top of the LFN entries */ + if (res == FR_OK) { + do { + res = move_window(dj->fs, dj->sect); + if (res != FR_OK) break; + *dj->dir = 0xE5; /* Mark the entry "deleted" */ + dj->fs->wflag = 1; + if (dj->index >= i) break; /* When reached SFN, all entries of the object has been deleted. */ + res = dir_next(dj, 0); /* Next entry */ + } while (res == FR_OK); + if (res == FR_NO_FILE) res = FR_INT_ERR; + } + +#else /* Non LFN configuration */ + res = dir_sdi(dj, dj->index); + if (res == FR_OK) { + res = move_window(dj->fs, dj->sect); + if (res == FR_OK) { + *dj->dir = 0xE5; /* Mark the entry "deleted" */ + dj->fs->wflag = 1; + } + } +#endif + + return res; +} +#endif /* !_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* Pick a segment and create the object name in directory form */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT create_name ( + DIR *dj, /* Pointer to the directory object */ + const TCHAR **path /* Pointer to pointer to the segment in the path string */ +) +{ +#ifdef _EXCVT + static const BYTE excvt[] = _EXCVT; /* Upper conversion table for extended chars */ +#endif + +#if _USE_LFN /* LFN configuration */ + BYTE b, cf; + WCHAR w, *lfn; + UINT i, ni, si, di; + const TCHAR *p; + + /* Create LFN in Unicode */ + si = di = 0; + p = *path; + lfn = dj->lfn; + for (;;) { + w = p[si++]; /* Get a character */ + if (w < ' ' || w == '/' || w == '\\') break; /* Break on end of segment */ + if (di >= _MAX_LFN) /* Reject too long name */ + return FR_INVALID_NAME; +#if !_LFN_UNICODE + w &= 0xFF; + if (IsDBCS1(w)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */ + b = (BYTE)p[si++]; /* Get 2nd byte */ + if (!IsDBCS2(b)) + return FR_INVALID_NAME; /* Reject invalid sequence */ + w = (w << 8) + b; /* Create a DBC */ + } + w = ff_convert(w, 1); /* Convert ANSI/OEM to Unicode */ + if (!w) return FR_INVALID_NAME; /* Reject invalid code */ +#endif + if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal chars for LFN */ + return FR_INVALID_NAME; + lfn[di++] = w; /* Store the Unicode char */ + } + *path = &p[si]; /* Return pointer to the next segment */ + cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */ +#if _FS_RPATH + if ((di == 1 && lfn[di-1] == '.') || /* Is this a dot entry? */ + (di == 2 && lfn[di-1] == '.' && lfn[di-2] == '.')) { + lfn[di] = 0; + for (i = 0; i < 11; i++) + dj->fn[i] = (i < di) ? '.' : ' '; + dj->fn[i] = cf | NS_DOT; /* This is a dot entry */ + return FR_OK; + } +#endif + while (di) { /* Strip trailing spaces and dots */ + w = lfn[di-1]; + if (w != ' ' && w != '.') break; + di--; + } + if (!di) return FR_INVALID_NAME; /* Reject nul string */ + + lfn[di] = 0; /* LFN is created */ + + /* Create SFN in directory form */ + mem_set(dj->fn, ' ', 11); + for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ; /* Strip leading spaces and dots */ + if (si) cf |= NS_LOSS | NS_LFN; + while (di && lfn[di - 1] != '.') di--; /* Find extension (di<=si: no extension) */ + + b = i = 0; ni = 8; + for (;;) { + w = lfn[si++]; /* Get an LFN char */ + if (!w) break; /* Break on end of the LFN */ + if (w == ' ' || (w == '.' && si != di)) { /* Remove spaces and dots */ + cf |= NS_LOSS | NS_LFN; continue; + } + + if (i >= ni || si == di) { /* Extension or end of SFN */ + if (ni == 11) { /* Long extension */ + cf |= NS_LOSS | NS_LFN; break; + } + if (si != di) cf |= NS_LOSS | NS_LFN; /* Out of 8.3 format */ + if (si > di) break; /* No extension */ + si = di; i = 8; ni = 11; /* Enter extension section */ + b <<= 2; continue; + } + + if (w >= 0x80) { /* Non ASCII char */ +#ifdef _EXCVT + w = ff_convert(w, 0); /* Unicode -> OEM code */ + if (w) w = excvt[w - 0x80]; /* Convert extended char to upper (SBCS) */ +#else + w = ff_convert(ff_wtoupper(w), 0); /* Upper converted Unicode -> OEM code */ +#endif + cf |= NS_LFN; /* Force create LFN entry */ + } + + if (_DF1S && w >= 0x100) { /* Double byte char (always false on SBCS cfg) */ + if (i >= ni - 1) { + cf |= NS_LOSS | NS_LFN; i = ni; continue; + } + dj->fn[i++] = (BYTE)(w >> 8); + } else { /* Single byte char */ + if (!w || chk_chr("+,;=[]", w)) { /* Replace illegal chars for SFN */ + w = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */ + } else { + if (IsUpper(w)) { /* ASCII large capital */ + b |= 2; + } else { + if (IsLower(w)) { /* ASCII small capital */ + b |= 1; w -= 0x20; + } + } + } + } + dj->fn[i++] = (BYTE)w; + } + + if (dj->fn[0] == 0xE5) dj->fn[0] = 0x05; /* If the first char collides with deleted mark, replace it with 0x05 */ + + if (ni == 8) b <<= 2; + if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */ + cf |= NS_LFN; + if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended char, NT flags are created */ + if ((b & 0x03) == 0x01) cf |= NS_EXT; /* NT flag (Extension has only small capital) */ + if ((b & 0x0C) == 0x04) cf |= NS_BODY; /* NT flag (Filename has only small capital) */ + } + + dj->fn[NS] = cf; /* SFN is created */ + + return FR_OK; + + +#else /* Non-LFN configuration */ + BYTE b, c, d, *sfn; + UINT ni, si, i; + const char *p; + + /* Create file name in directory form */ + sfn = dj->fn; + mem_set(sfn, ' ', 11); + si = i = b = 0; ni = 8; + p = *path; +#if _FS_RPATH + if (p[si] == '.') { /* Is this a dot entry? */ + for (;;) { + c = (BYTE)p[si++]; + if (c != '.' || si >= 3) break; + sfn[i++] = c; + } + if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME; + *path = &p[si]; /* Return pointer to the next segment */ + sfn[NS] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of path */ + return FR_OK; + } +#endif + for (;;) { + c = (BYTE)p[si++]; + if (c <= ' ' || c == '/' || c == '\\') break; /* Break on end of segment */ + if (c == '.' || i >= ni) { + if (ni != 8 || c != '.') return FR_INVALID_NAME; + i = 8; ni = 11; + b <<= 2; continue; + } + if (c >= 0x80) { /* Extended char? */ + b |= 3; /* Eliminate NT flag */ +#ifdef _EXCVT + c = excvt[c-0x80]; /* Upper conversion (SBCS) */ +#else +#if !_DF1S /* ASCII only cfg */ + return FR_INVALID_NAME; +#endif +#endif + } + if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */ + d = (BYTE)p[si++]; /* Get 2nd byte */ + if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */ + return FR_INVALID_NAME; + sfn[i++] = c; + sfn[i++] = d; + } else { /* Single byte code */ + if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) /* Reject illegal chrs for SFN */ + return FR_INVALID_NAME; + if (IsUpper(c)) { /* ASCII large capital? */ + b |= 2; + } else { + if (IsLower(c)) { /* ASCII small capital? */ + b |= 1; c -= 0x20; + } + } + sfn[i++] = c; + } + } + *path = &p[si]; /* Return pointer to the next segment */ + c = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */ + + if (!i) return FR_INVALID_NAME; /* Reject nul string */ + if (sfn[0] == 0xE5) sfn[0] = 0x05; /* When first char collides with 0xE5, replace it with 0x05 */ + + if (ni == 8) b <<= 2; + if ((b & 0x03) == 0x01) c |= NS_EXT; /* NT flag (Name extension has only small capital) */ + if ((b & 0x0C) == 0x04) c |= NS_BODY; /* NT flag (Name body has only small capital) */ + + sfn[NS] = c; /* Store NT flag, File name is created */ + + return FR_OK; +#endif +} + + + + +/*-----------------------------------------------------------------------*/ +/* Get file information from directory entry */ +/*-----------------------------------------------------------------------*/ +#if _FS_MINIMIZE <= 1 +static +void get_fileinfo ( /* No return code */ + DIR *dj, /* Pointer to the directory object */ + FILINFO *fno /* Pointer to the file information to be filled */ +) +{ + UINT i; + BYTE nt, *dir; + TCHAR *p, c; + + + p = fno->fname; + if (dj->sect) { + dir = dj->dir; + nt = dir[DIR_NTres]; /* NT flag */ + for (i = 0; i < 8; i++) { /* Copy name body */ + c = dir[i]; + if (c == ' ') break; + if (c == 0x05) c = (TCHAR)0xE5; + if (_USE_LFN && (nt & NS_BODY) && IsUpper(c)) c += 0x20; +#if _LFN_UNICODE + if (IsDBCS1(c) && i < 7 && IsDBCS2(dir[i+1])) + c = (c << 8) | dir[++i]; + c = ff_convert(c, 1); + if (!c) c = '?'; +#endif + *p++ = c; + } + if (dir[8] != ' ') { /* Copy name extension */ + *p++ = '.'; + for (i = 8; i < 11; i++) { + c = dir[i]; + if (c == ' ') break; + if (_USE_LFN && (nt & NS_EXT) && IsUpper(c)) c += 0x20; +#if _LFN_UNICODE + if (IsDBCS1(c) && i < 10 && IsDBCS2(dir[i+1])) + c = (c << 8) | dir[++i]; + c = ff_convert(c, 1); + if (!c) c = '?'; +#endif + *p++ = c; + } + } + fno->fattrib = dir[DIR_Attr]; /* Attribute */ + fno->fsize = LD_DWORD(dir+DIR_FileSize); /* Size */ + fno->fdate = LD_WORD(dir+DIR_WrtDate); /* Date */ + fno->ftime = LD_WORD(dir+DIR_WrtTime); /* Time */ + } + *p = 0; /* Terminate SFN str by a \0 */ + +#if _USE_LFN + if (fno->lfname && fno->lfsize) { + TCHAR *tp = fno->lfname; + WCHAR w, *lfn; + + i = 0; + if (dj->sect && dj->lfn_idx != 0xFFFF) {/* Get LFN if available */ + lfn = dj->lfn; + while ((w = *lfn++) != 0) { /* Get an LFN char */ +#if !_LFN_UNICODE + w = ff_convert(w, 0); /* Unicode -> OEM conversion */ + if (!w) { i = 0; break; } /* Could not convert, no LFN */ + if (_DF1S && w >= 0x100) /* Put 1st byte if it is a DBC (always false on SBCS cfg) */ + tp[i++] = (TCHAR)(w >> 8); +#endif + if (i >= fno->lfsize - 1) { i = 0; break; } /* Buffer overflow, no LFN */ + tp[i++] = (TCHAR)w; + } + } + tp[i] = 0; /* Terminate the LFN str by a \0 */ + } +#endif +} +#endif /* _FS_MINIMIZE <= 1 */ + + + + +/*-----------------------------------------------------------------------*/ +/* Follow a file path */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ + DIR *dj, /* Directory object to return last directory and found object */ + const TCHAR *path /* Full-path string to find a file or directory */ +) +{ + FRESULT res; + BYTE *dir, ns; + + +#if _FS_RPATH + if (*path == '/' || *path == '\\') { /* There is a heading separator */ + path++; dj->sclust = 0; /* Strip it and start from the root dir */ + } else { /* No heading separator */ + dj->sclust = dj->fs->cdir; /* Start from the current dir */ + } +#else + if (*path == '/' || *path == '\\') /* Strip heading separator if exist */ + path++; + dj->sclust = 0; /* Start from the root dir */ +#endif + + if ((UINT)*path < ' ') { /* Nul path means the start directory itself */ + res = dir_sdi(dj, 0); + dj->dir = 0; + + } else { /* Follow path */ + for (;;) { + res = create_name(dj, &path); /* Get a segment */ + if (res != FR_OK) break; + res = dir_find(dj); /* Find it */ + ns = *(dj->fn+NS); + if (res != FR_OK) { /* Failed to find the object */ + if (res != FR_NO_FILE) break; /* Abort if any hard error occured */ + /* Object not found */ + if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exit */ + dj->sclust = 0; dj->dir = 0; /* It is the root dir */ + res = FR_OK; + if (!(ns & NS_LAST)) continue; + } else { /* Could not find the object */ + if (!(ns & NS_LAST)) res = FR_NO_PATH; + } + break; + } + if (ns & NS_LAST) break; /* Last segment match. Function completed. */ + dir = dj->dir; /* There is next segment. Follow the sub directory */ + if (!(dir[DIR_Attr] & AM_DIR)) { /* Cannot follow because it is a file */ + res = FR_NO_PATH; break; + } + dj->sclust = LD_CLUST(dir); + } + } + + return res; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Load boot record and check if it is an FAT boot record */ +/*-----------------------------------------------------------------------*/ + +static +BYTE check_fs ( /* 0:The FAT BR, 1:Valid BR but not an FAT, 2:Not a BR, 3:Disk error */ + FATFS *fs, /* File system object */ + DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */ +) +{ + if (disk_read(fs->drv, fs->win, sect, 1) != RES_OK) /* Load boot record */ + return 3; + if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check record signature (always placed at offset 510 even if the sector size is >512) */ + return 2; + + if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */ + return 0; + if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146) + return 0; + + return 1; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Check if the file system object is valid or not */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT chk_mounted ( /* FR_OK(0): successful, !=0: any error occurred */ + const TCHAR **path, /* Pointer to pointer to the path name (drive number) */ + FATFS **rfs, /* Pointer to pointer to the found file system object */ + BYTE chk_wp /* !=0: Check media write protection for write access */ +) +{ + BYTE fmt, b, *tbl; + UINT vol; + DSTATUS stat; + DWORD bsect, fasize, tsect, sysect, nclst, szbfat; + WORD nrsv; + const TCHAR *p = *path; + FATFS *fs; + + /* Get logical drive number from the path name */ + vol = p[0] - '0'; /* Is there a drive number? */ + if (vol <= 9 && p[1] == ':') { /* Found a drive number, get and strip it */ + p += 2; *path = p; /* Return pointer to the path name */ + } else { /* No drive number is given */ +#if _FS_RPATH + vol = CurrVol; /* Use current drive */ +#else + vol = 0; /* Use drive 0 */ +#endif + } + + /* Check if the logical drive is valid or not */ + if (vol >= _VOLUMES) /* Is the drive number valid? */ + return FR_INVALID_DRIVE; + *rfs = fs = FatFs[vol]; /* Return pointer to the corresponding file system object */ + if (!fs) return FR_NOT_ENABLED; /* Is the file system object available? */ + + ENTER_FF(fs); /* Lock file system */ + + if (fs->fs_type) { /* If the logical drive has been mounted */ + stat = disk_status(fs->drv); + if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized (has not been changed), */ +#if !_FS_READONLY + if (chk_wp && (stat & STA_PROTECT)) /* Check write protection if needed */ + return FR_WRITE_PROTECTED; +#endif + return FR_OK; /* The file system object is valid */ + } + } + + /* The logical drive must be mounted. */ + /* Following code attempts to mount a volume. (analyze BPB and initialize the fs object) */ + + fs->fs_type = 0; /* Clear the file system object */ + fs->drv = (BYTE)LD2PD(vol); /* Bind the logical drive and a physical drive */ + stat = disk_initialize(fs->drv); /* Initialize low level disk I/O layer */ + if (stat & STA_NOINIT) /* Check if the initialization succeeded */ + return FR_NOT_READY; /* Failed to initialize due to no media or hard error */ +#if _MAX_SS != 512 /* Get disk sector size (variable sector size cfg only) */ + if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &fs->ssize) != RES_OK) + return FR_DISK_ERR; +#endif +#if !_FS_READONLY + if (chk_wp && (stat & STA_PROTECT)) /* Check disk write protection if needed */ + return FR_WRITE_PROTECTED; +#endif + /* Search FAT partition on the drive. Supports only generic partitionings, FDISK and SFD. */ + fmt = check_fs(fs, bsect = 0); /* Check sector 0 if it is a VBR */ + if (fmt == 1) { /* Not an FAT-VBR, the disk may be partitioned */ + /* Check the partition listed in top of the partition table */ + tbl = &fs->win[MBR_Table + LD2PT(vol) * 16]; /* Partition table */ + if (tbl[4]) { /* Is the partition existing? */ + bsect = LD_DWORD(&tbl[8]); /* Partition offset in LBA */ + fmt = check_fs(fs, bsect); /* Check the partition */ + } + } + if (fmt == 3) return FR_DISK_ERR; + if (fmt) return FR_NO_FILESYSTEM; /* No FAT volume is found */ + + /* Following code initializes the file system object */ + + if (LD_WORD(fs->win+BPB_BytsPerSec) != SS(fs)) /* (BPB_BytsPerSec must be equal to the physical sector size) */ + return FR_NO_FILESYSTEM; + + fasize = LD_WORD(fs->win+BPB_FATSz16); /* Number of sectors per FAT */ + if (!fasize) fasize = LD_DWORD(fs->win+BPB_FATSz32); + fs->fsize = fasize; + + fs->n_fats = b = fs->win[BPB_NumFATs]; /* Number of FAT copies */ + if (b != 1 && b != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */ + fasize *= b; /* Number of sectors for FAT area */ + + fs->csize = b = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */ + if (!b || (b & (b - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */ + + fs->n_rootdir = LD_WORD(fs->win+BPB_RootEntCnt); /* Number of root directory entries */ + if (fs->n_rootdir % (SS(fs) / 32)) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be sector aligned) */ + + tsect = LD_WORD(fs->win+BPB_TotSec16); /* Number of sectors on the volume */ + if (!tsect) tsect = LD_DWORD(fs->win+BPB_TotSec32); + + nrsv = LD_WORD(fs->win+BPB_RsvdSecCnt); /* Number of reserved sectors */ + if (!nrsv) return FR_NO_FILESYSTEM; /* (BPB_RsvdSecCnt must not be 0) */ + + /* Determine the FAT sub type */ + sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / 32); /* RSV+FAT+DIR */ + if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ + if (!nclst) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + fmt = FS_FAT12; + if (nclst >= MIN_FAT16) fmt = FS_FAT16; + if (nclst >= MIN_FAT32) fmt = FS_FAT32; + + /* Boundaries and Limits */ + fs->n_fatent = nclst + 2; /* Number of FAT entries */ + fs->database = bsect + sysect; /* Data start sector */ + fs->fatbase = bsect + nrsv; /* FAT start sector */ + if (fmt == FS_FAT32) { + if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ + fs->dirbase = LD_DWORD(fs->win+BPB_RootClus); /* Root directory start cluster */ + szbfat = fs->n_fatent * 4; /* (Required FAT size) */ + } else { + if (!fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must not be 0) */ + fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ + szbfat = (fmt == FS_FAT16) ? /* (Required FAT size) */ + fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); + } + if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) /* (FAT size must not be less than FAT sectors */ + return FR_NO_FILESYSTEM; + +#if !_FS_READONLY + /* Initialize cluster allocation information */ + fs->free_clust = 0xFFFFFFFF; + fs->last_clust = 0; + + /* Get fsinfo if available */ + if (fmt == FS_FAT32) { + fs->fsi_flag = 0; + fs->fsi_sector = bsect + LD_WORD(fs->win+BPB_FSInfo); + if (disk_read(fs->drv, fs->win, fs->fsi_sector, 1) == RES_OK && + LD_WORD(fs->win+BS_55AA) == 0xAA55 && + LD_DWORD(fs->win+FSI_LeadSig) == 0x41615252 && + LD_DWORD(fs->win+FSI_StrucSig) == 0x61417272) { + fs->last_clust = LD_DWORD(fs->win+FSI_Nxt_Free); + fs->free_clust = LD_DWORD(fs->win+FSI_Free_Count); + } + } +#endif + fs->fs_type = fmt; /* FAT sub-type */ + fs->id = ++Fsid; /* File system mount ID */ + fs->winsect = 0; /* Invalidate sector cache */ + fs->wflag = 0; +#if _FS_RPATH + fs->cdir = 0; /* Current directory (root dir) */ +#endif +#if _FS_SHARE /* Clear file lock semaphores */ + clear_lock(fs); +#endif + + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Check if the file/dir object is valid or not */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */ + FATFS *fs, /* Pointer to the file system object */ + WORD id /* Member id of the target object to be checked */ +) +{ + if (!fs || !fs->fs_type || fs->id != id) + return FR_INVALID_OBJECT; + + ENTER_FF(fs); /* Lock file system */ + + if (disk_status(fs->drv) & STA_NOINIT) + return FR_NOT_READY; + + return FR_OK; +} + + + + +/*-------------------------------------------------------------------------- + + Public Functions + +--------------------------------------------------------------------------*/ + + + +/*-----------------------------------------------------------------------*/ +/* Mount/Unmount a Logical Drive */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_mount ( + BYTE vol, /* Logical drive number to be mounted/unmounted */ + FATFS *fs /* Pointer to new file system object (NULL for unmount)*/ +) +{ + FATFS *rfs; + + + if (vol >= _VOLUMES) /* Check if the drive number is valid */ + return FR_INVALID_DRIVE; + rfs = FatFs[vol]; /* Get current fs object */ + + if (rfs) { +#if _FS_SHARE + clear_lock(rfs); +#endif +#if _FS_REENTRANT /* Discard sync object of the current volume */ + if (!ff_del_syncobj(rfs->sobj)) return FR_INT_ERR; +#endif + rfs->fs_type = 0; /* Clear old fs object */ + } + + if (fs) { + fs->fs_type = 0; /* Clear new fs object */ +#if _FS_REENTRANT /* Create sync object for the new volume */ + if (!ff_cre_syncobj(vol, &fs->sobj)) return FR_INT_ERR; +#endif + } + FatFs[vol] = fs; /* Register new fs object */ + + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Open or Create a File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_open ( + FIL *fp, /* Pointer to the blank file object */ + const TCHAR *path, /* Pointer to the file name */ + BYTE mode /* Access mode and file open mode flags */ +) +{ + FRESULT res; + DIR dj; + BYTE *dir; + DEF_NAMEBUF; + + + fp->fs = 0; /* Clear file object */ + +#if !_FS_READONLY + mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW; + res = chk_mounted(&path, &dj.fs, (BYTE)(mode & ~FA_READ)); +#else + mode &= FA_READ; + res = chk_mounted(&path, &dj.fs, 0); +#endif + INIT_BUF(dj); + if (res == FR_OK) + res = follow_path(&dj, path); /* Follow the file path */ + dir = dj.dir; + +#if !_FS_READONLY /* R/W configuration */ + if (res == FR_OK) { + if (!dir) /* Current dir itself */ + res = FR_INVALID_NAME; +#if _FS_SHARE + else + res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); +#endif + } + /* Create or Open a file */ + if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { + DWORD dw, cl; + + if (res != FR_OK) { /* No file, create new */ + if (res == FR_NO_FILE) /* There is no file to open, create a new entry */ +#if _FS_SHARE + res = enq_lock(dj.fs) ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; +#else + res = dir_register(&dj); +#endif + mode |= FA_CREATE_ALWAYS; /* File is created */ + dir = dj.dir; /* New entry */ + } + else { /* Any object is already existing */ + if (mode & FA_CREATE_NEW) { /* Cannot create new */ + res = FR_EXIST; + } else { + if (dir[DIR_Attr] & (AM_RDO | AM_DIR)) /* Cannot overwrite it (R/O or DIR) */ + res = FR_DENIED; + } + } + if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */ + dw = get_fattime(); /* Created time */ + ST_DWORD(dir+DIR_CrtTime, dw); + dir[DIR_Attr] = 0; /* Reset attribute */ + ST_DWORD(dir+DIR_FileSize, 0); /* size = 0 */ + cl = LD_CLUST(dir); /* Get start cluster */ + ST_CLUST(dir, 0); /* cluster = 0 */ + dj.fs->wflag = 1; + if (cl) { /* Remove the cluster chain if exist */ + dw = dj.fs->winsect; + res = remove_chain(dj.fs, cl); + if (res == FR_OK) { + dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */ + res = move_window(dj.fs, dw); + } + } + } + } + else { /* Open an existing file */ + if (res == FR_OK) { /* Follow succeeded */ + if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */ + res = FR_NO_FILE; + } else { + if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */ + res = FR_DENIED; + } + } + } + if (res == FR_OK) { + if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */ + mode |= FA__WRITTEN; + fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */ + fp->dir_ptr = dir; +#if _FS_SHARE + fp->lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); + if (!fp->lockid) res = FR_INT_ERR; +#endif + } + +#else /* R/O configuration */ + if (res == FR_OK) { /* Follow succeeded */ + if (!dir) { /* Current dir itself */ + res = FR_INVALID_NAME; + } else { + if (dir[DIR_Attr] & AM_DIR) /* It is a directory */ + res = FR_NO_FILE; + } + } +#endif + FREE_BUF(); + + if (res == FR_OK) { + fp->flag = mode; /* File access mode */ + fp->org_clust = LD_CLUST(dir); /* File start cluster */ + fp->fsize = LD_DWORD(dir+DIR_FileSize); /* File size */ + fp->fptr = 0; /* File pointer */ + fp->dsect = 0; +#if _USE_FASTSEEK + fp->cltbl = 0; /* No cluster link map table */ +#endif + fp->fs = dj.fs; fp->id = dj.fs->id; /* Validate file object */ + } + + LEAVE_FF(dj.fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Read File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_read ( + FIL *fp, /* Pointer to the file object */ + void *buff, /* Pointer to data buffer */ + UINT btr, /* Number of bytes to read */ + UINT *br /* Pointer to number of bytes read */ +) +{ + FRESULT res; + DWORD clst, sect, remain; + UINT rcnt, cc; + BYTE csect, *rbuff = (BYTE *)buff; + + + *br = 0; /* Initialize byte counter */ + + res = validate(fp->fs, fp->id); /* Check validity of the object */ + if (res != FR_OK) LEAVE_FF(fp->fs, res); + if (fp->flag & FA__ERROR) /* Check abort flag */ + LEAVE_FF(fp->fs, FR_INT_ERR); + if (!(fp->flag & FA_READ)) /* Check access mode */ + LEAVE_FF(fp->fs, FR_DENIED); + remain = fp->fsize - fp->fptr; + if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ + + for ( ; btr; /* Repeat until all data transferred */ + rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) { + if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ + csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ + if (!csect) { /* On the cluster boundary? */ + clst = (fp->fptr == 0) ? /* On the top of the file? */ + fp->org_clust : get_fat(fp->fs, fp->curr_clust); + if (clst <= 1) ABORT(fp->fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + fp->curr_clust = clst; /* Update current cluster */ + } + sect = clust2sect(fp->fs, fp->curr_clust); /* Get current sector */ + if (!sect) ABORT(fp->fs, FR_INT_ERR); + sect += csect; + cc = btr / SS(fp->fs); /* When remaining bytes >= sector size, */ + if (cc) { /* Read maximum contiguous sectors directly */ + if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */ + cc = fp->fs->csize - csect; + if (disk_read(fp->fs->drv, rbuff, sect, (BYTE)cc) != RES_OK) + ABORT(fp->fs, FR_DISK_ERR); +#if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ +#if _FS_TINY + if (fp->fs->wflag && fp->fs->winsect - sect < cc) + mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs)); +#else + if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc) + mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs)); +#endif +#endif + rcnt = SS(fp->fs) * cc; /* Number of bytes transferred */ + continue; + } +#if !_FS_TINY +#if !_FS_READONLY + if (fp->flag & FA__DIRTY) { /* Write sector I/O buffer if needed */ + if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) + ABORT(fp->fs, FR_DISK_ERR); + fp->flag &= ~FA__DIRTY; + } +#endif + if (fp->dsect != sect) { /* Fill sector buffer with file data */ + if (disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) + ABORT(fp->fs, FR_DISK_ERR); + } +#endif + fp->dsect = sect; + } + rcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs)); /* Get partial sector data from sector buffer */ + if (rcnt > btr) rcnt = btr; +#if _FS_TINY + if (move_window(fp->fs, fp->dsect)) /* Move sector window */ + ABORT(fp->fs, FR_DISK_ERR); + mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */ +#else + mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */ +#endif + } + + LEAVE_FF(fp->fs, FR_OK); +} + + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Write File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_write ( + FIL *fp, /* Pointer to the file object */ + const void *buff, /* Pointer to the data to be written */ + UINT btw, /* Number of bytes to write */ + UINT *bw /* Pointer to number of bytes written */ +) +{ + FRESULT res; + DWORD clst, sect; + UINT wcnt, cc; + const BYTE *wbuff = (const BYTE *)buff; + BYTE csect; + + + *bw = 0; /* Initialize byte counter */ + + res = validate(fp->fs, fp->id); /* Check validity of the object */ + if (res != FR_OK) LEAVE_FF(fp->fs, res); + if (fp->flag & FA__ERROR) /* Check abort flag */ + LEAVE_FF(fp->fs, FR_INT_ERR); + if (!(fp->flag & FA_WRITE)) /* Check access mode */ + LEAVE_FF(fp->fs, FR_DENIED); + if (fp->fsize + btw < fp->fsize) btw = 0; /* File size cannot reach 4GB */ + + for ( ; btw; /* Repeat until all data transferred */ + wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) { + if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ + csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ + if (!csect) { /* On the cluster boundary? */ + if (fp->fptr == 0) { /* On the top of the file? */ + clst = fp->org_clust; /* Follow from the origin */ + if (clst == 0) /* When there is no cluster chain, */ + fp->org_clust = clst = create_chain(fp->fs, 0); /* Create a new cluster chain */ + } else { /* Middle or end of the file */ + clst = create_chain(fp->fs, fp->curr_clust); /* Follow or stretch cluster chain */ + } + if (clst == 0) break; /* Could not allocate a new cluster (disk full) */ + if (clst == 1) ABORT(fp->fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + fp->curr_clust = clst; /* Update current cluster */ + } +#if _FS_TINY + if (fp->fs->winsect == fp->dsect && move_window(fp->fs, 0)) /* Write back data buffer prior to following direct transfer */ + ABORT(fp->fs, FR_DISK_ERR); +#else + if (fp->flag & FA__DIRTY) { /* Write back data buffer prior to following direct transfer */ + if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) + ABORT(fp->fs, FR_DISK_ERR); + fp->flag &= ~FA__DIRTY; + } +#endif + sect = clust2sect(fp->fs, fp->curr_clust); /* Get current sector */ + if (!sect) ABORT(fp->fs, FR_INT_ERR); + sect += csect; + cc = btw / SS(fp->fs); /* When remaining bytes >= sector size, */ + if (cc) { /* Write maximum contiguous sectors directly */ + if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */ + cc = fp->fs->csize - csect; + if (disk_write(fp->fs->drv, wbuff, sect, (BYTE)cc) != RES_OK) + ABORT(fp->fs, FR_DISK_ERR); +#if _FS_TINY + if (fp->fs->winsect - sect < cc) { /* Refill sector cache if it gets dirty by the direct write */ + mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs)); + fp->fs->wflag = 0; + } +#else + if (fp->dsect - sect < cc) { /* Refill sector cache if it gets dirty by the direct write */ + mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs)); + fp->flag &= ~FA__DIRTY; + } +#endif + wcnt = SS(fp->fs) * cc; /* Number of bytes transferred */ + continue; + } +#if _FS_TINY + if (fp->fptr >= fp->fsize) { /* Avoid silly buffer filling at growing edge */ + if (move_window(fp->fs, 0)) ABORT(fp->fs, FR_DISK_ERR); + fp->fs->winsect = sect; + } +#else + if (fp->dsect != sect) { /* Fill sector buffer with file data */ + if (fp->fptr < fp->fsize && + disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) + ABORT(fp->fs, FR_DISK_ERR); + } +#endif + fp->dsect = sect; + } + wcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs));/* Put partial sector into file I/O buffer */ + if (wcnt > btw) wcnt = btw; +#if _FS_TINY + if (move_window(fp->fs, fp->dsect)) /* Move sector window */ + ABORT(fp->fs, FR_DISK_ERR); + mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */ + fp->fs->wflag = 1; +#else + mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */ + fp->flag |= FA__DIRTY; +#endif + } + + if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */ + fp->flag |= FA__WRITTEN; /* Set file change flag */ + + LEAVE_FF(fp->fs, FR_OK); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Synchronize the File Object */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_sync ( + FIL *fp /* Pointer to the file object */ +) +{ + FRESULT res; + DWORD tim; + BYTE *dir; + + + res = validate(fp->fs, fp->id); /* Check validity of the object */ + if (res == FR_OK) { + if (fp->flag & FA__WRITTEN) { /* Has the file been written? */ +#if !_FS_TINY /* Write-back dirty buffer */ + if (fp->flag & FA__DIRTY) { + if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) + LEAVE_FF(fp->fs, FR_DISK_ERR); + fp->flag &= ~FA__DIRTY; + } +#endif + /* Update the directory entry */ + res = move_window(fp->fs, fp->dir_sect); + if (res == FR_OK) { + dir = fp->dir_ptr; + dir[DIR_Attr] |= AM_ARC; /* Set archive bit */ + ST_DWORD(dir+DIR_FileSize, fp->fsize); /* Update file size */ + ST_CLUST(dir, fp->org_clust); /* Update start cluster */ + tim = get_fattime(); /* Update updated time */ + ST_DWORD(dir+DIR_WrtTime, tim); + fp->flag &= ~FA__WRITTEN; + fp->fs->wflag = 1; + res = sync(fp->fs); + } + } + } + + LEAVE_FF(fp->fs, res); +} + +#endif /* !_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* Close File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_close ( + FIL *fp /* Pointer to the file object to be closed */ +) +{ + FRESULT res; + +#if _FS_READONLY + FATFS *fs = fp->fs; + res = validate(fs, fp->id); + if (res == FR_OK) fp->fs = 0; /* Discard file object */ + LEAVE_FF(fs, res); + +#else + res = f_sync(fp); /* Flush cached data */ +#if _FS_SHARE + if (res == FR_OK) { /* Decrement open counter */ +#if _FS_REENTRANT + res = validate(fp->fs, fp->id); + if (res == FR_OK) { + res = dec_lock(fp->lockid); + unlock_fs(fp->fs, FR_OK); + } +#else + res = dec_lock(fp->lockid); +#endif + } +#endif + if (res == FR_OK) fp->fs = 0; /* Discard file object */ + return res; +#endif +} + + + + +/*-----------------------------------------------------------------------*/ +/* Current Drive/Directory Handlings */ +/*-----------------------------------------------------------------------*/ + +#if _FS_RPATH >= 1 + +FRESULT f_chdrive ( + BYTE drv /* Drive number */ +) +{ + if (drv >= _VOLUMES) return FR_INVALID_DRIVE; + + CurrVol = drv; + + return FR_OK; +} + + + +FRESULT f_chdir ( + const TCHAR *path /* Pointer to the directory path */ +) +{ + FRESULT res; + DIR dj; + DEF_NAMEBUF; + + + res = chk_mounted(&path, &dj.fs, 0); + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the path */ + FREE_BUF(); + if (res == FR_OK) { /* Follow completed */ + if (!dj.dir) { + dj.fs->cdir = dj.sclust; /* Start directory itself */ + } else { + if (dj.dir[DIR_Attr] & AM_DIR) /* Reached to the directory */ + dj.fs->cdir = LD_CLUST(dj.dir); + else + res = FR_NO_PATH; /* Reached but a file */ + } + } + if (res == FR_NO_FILE) res = FR_NO_PATH; + } + + LEAVE_FF(dj.fs, res); +} + + +#if _FS_RPATH >= 2 +FRESULT f_getcwd ( + TCHAR *path, /* Pointer to the directory path */ + UINT sz_path /* Size of path */ +) +{ + FRESULT res; + DIR dj; + UINT i, n; + DWORD ccl; + TCHAR *tp; + FILINFO fno; + DEF_NAMEBUF; + + + *path = 0; + res = chk_mounted((const TCHAR**)&path, &dj.fs, 0); /* Get current volume */ + if (res == FR_OK) { + INIT_BUF(dj); + i = sz_path; /* Bottom of buffer (dir stack base) */ + dj.sclust = dj.fs->cdir; /* Start to follow upper dir from current dir */ + while ((ccl = dj.sclust) != 0) { /* Repeat while current dir is a sub-dir */ + res = dir_sdi(&dj, 1); /* Get parent dir */ + if (res != FR_OK) break; + res = dir_read(&dj); + if (res != FR_OK) break; + dj.sclust = LD_CLUST(dj.dir); /* Goto parent dir */ + res = dir_sdi(&dj, 0); + if (res != FR_OK) break; + do { /* Find the entry links to the child dir */ + res = dir_read(&dj); + if (res != FR_OK) break; + if (ccl == LD_CLUST(dj.dir)) break; /* Found the entry */ + res = dir_next(&dj, 0); + } while (res == FR_OK); + if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */ + if (res != FR_OK) break; +#if _USE_LFN + fno.lfname = path; + fno.lfsize = i; +#endif + get_fileinfo(&dj, &fno); /* Get the dir name and push it to the buffer */ + tp = fno.fname; + if (_USE_LFN && *path) tp = path; + for (n = 0; tp[n]; n++) ; + if (i < n + 3) { + res = FR_NOT_ENOUGH_CORE; break; + } + while (n) path[--i] = tp[--n]; + path[--i] = '/'; + } + tp = path; + if (res == FR_OK) { + *tp++ = '0' + CurrVol; /* Put drive number */ + *tp++ = ':'; + if (i == sz_path) { /* Root-dir */ + *tp++ = '/'; + } else { /* Sub-dir */ + do /* Add stacked path str */ + *tp++ = path[i++]; + while (i < sz_path); + } + } + *tp = 0; + FREE_BUF(); + } + + LEAVE_FF(dj.fs, res); +} +#endif /* _FS_RPATH >= 2 */ +#endif /* _FS_RPATH >= 1 */ + + + +#if _FS_MINIMIZE <= 2 +/*-----------------------------------------------------------------------*/ +/* Seek File R/W Pointer */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_lseek ( + FIL *fp, /* Pointer to the file object */ + DWORD ofs /* File pointer from top of file */ +) +{ + FRESULT res; + + + res = validate(fp->fs, fp->id); /* Check validity of the object */ + if (res != FR_OK) LEAVE_FF(fp->fs, res); + if (fp->flag & FA__ERROR) /* Check abort flag */ + LEAVE_FF(fp->fs, FR_INT_ERR); + +#if _USE_FASTSEEK + if (fp->cltbl) { /* Fast seek */ + DWORD cl, pcl, ncl, tcl, dsc, tlen, *tbl = fp->cltbl; + BYTE csc; + + tlen = *tbl++; + if (ofs == CREATE_LINKMAP) { /* Create link map table */ + cl = fp->org_clust; + if (cl) { + do { + if (tlen < 4) { /* Not enough table items */ + res = FR_NOT_ENOUGH_CORE; break; + } + tcl = cl; ncl = 0; + do { /* Get a fragment and store the top and length */ + pcl = cl; ncl++; + cl = get_fat(fp->fs, cl); + if (cl <= 1) ABORT(fp->fs, FR_INT_ERR); + if (cl == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + } while (cl == pcl + 1); + *tbl++ = ncl; *tbl++ = tcl; + tlen -= 2; + } while (cl < fp->fs->n_fatent); + } + *tbl = 0; /* Terminate table */ + + } else { /* Fast seek */ + if (ofs > fp->fsize) /* Clip offset at the file size */ + ofs = fp->fsize; + fp->fptr = ofs; /* Set file pointer */ + if (ofs) { + dsc = (ofs - 1) / SS(fp->fs); + cl = dsc / fp->fs->csize; + for (;;) { + ncl = *tbl++; + if (!ncl) ABORT(fp->fs, FR_INT_ERR); + if (cl < ncl) break; + cl -= ncl; tbl++; + } + fp->curr_clust = cl + *tbl; + csc = (BYTE)(dsc & (fp->fs->csize - 1)); + dsc = clust2sect(fp->fs, fp->curr_clust); + if (!dsc) ABORT(fp->fs, FR_INT_ERR); + dsc += csc; + if (fp->fptr % SS(fp->fs) && dsc != fp->dsect) { +#if !_FS_TINY +#if !_FS_READONLY + if (fp->flag & FA__DIRTY) { /* Flush dirty buffer if needed */ + if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) + ABORT(fp->fs, FR_DISK_ERR); + fp->flag &= ~FA__DIRTY; + } +#endif + if (disk_read(fp->fs->drv, fp->buf, dsc, 1) != RES_OK) + ABORT(fp->fs, FR_DISK_ERR); +#endif + fp->dsect = dsc; + } + } + } + } else +#endif + + /* Normal Seek */ + { + DWORD clst, bcs, nsect, ifptr; + + if (ofs > fp->fsize /* In read-only mode, clip offset with the file size */ +#if !_FS_READONLY + && !(fp->flag & FA_WRITE) +#endif + ) ofs = fp->fsize; + + ifptr = fp->fptr; + fp->fptr = nsect = 0; + if (ofs) { + bcs = (DWORD)fp->fs->csize * SS(fp->fs); /* Cluster size (byte) */ + if (ifptr > 0 && + (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ + fp->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */ + ofs -= fp->fptr; + clst = fp->curr_clust; + } else { /* When seek to back cluster, */ + clst = fp->org_clust; /* start from the first cluster */ +#if !_FS_READONLY + if (clst == 0) { /* If no cluster chain, create a new chain */ + clst = create_chain(fp->fs, 0); + if (clst == 1) ABORT(fp->fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + fp->org_clust = clst; + } +#endif + fp->curr_clust = clst; + } + if (clst != 0) { + while (ofs > bcs) { /* Cluster following loop */ +#if !_FS_READONLY + if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ + clst = create_chain(fp->fs, clst); /* Force stretch if in write mode */ + if (clst == 0) { /* When disk gets full, clip file size */ + ofs = bcs; break; + } + } else +#endif + clst = get_fat(fp->fs, clst); /* Follow cluster chain if not in write mode */ + if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + if (clst <= 1 || clst >= fp->fs->n_fatent) ABORT(fp->fs, FR_INT_ERR); + fp->curr_clust = clst; + fp->fptr += bcs; + ofs -= bcs; + } + fp->fptr += ofs; + if (ofs % SS(fp->fs)) { + nsect = clust2sect(fp->fs, clst); /* Current sector */ + if (!nsect) ABORT(fp->fs, FR_INT_ERR); + nsect += ofs / SS(fp->fs); + } + } + } + if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) { +#if !_FS_TINY +#if !_FS_READONLY + if (fp->flag & FA__DIRTY) { /* Flush dirty buffer if needed */ + if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) + ABORT(fp->fs, FR_DISK_ERR); + fp->flag &= ~FA__DIRTY; + } +#endif + if (disk_read(fp->fs->drv, fp->buf, nsect, 1) != RES_OK) + ABORT(fp->fs, FR_DISK_ERR); +#endif + fp->dsect = nsect; + } +#if !_FS_READONLY + if (fp->fptr > fp->fsize) { /* Set change flag if the file size is extended */ + fp->fsize = fp->fptr; + fp->flag |= FA__WRITTEN; + } +#endif + } + + LEAVE_FF(fp->fs, res); +} + + + +#if _FS_MINIMIZE <= 1 +/*-----------------------------------------------------------------------*/ +/* Create a Directroy Object */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_opendir ( + DIR *dj, /* Pointer to directory object to create */ + const TCHAR *path /* Pointer to the directory path */ +) +{ + FRESULT res; + DEF_NAMEBUF; + + + res = chk_mounted(&path, &dj->fs, 0); + if (res == FR_OK) { + INIT_BUF(*dj); + res = follow_path(dj, path); /* Follow the path to the directory */ + FREE_BUF(); + if (res == FR_OK) { /* Follow completed */ + if (dj->dir) { /* It is not the root dir */ + if (dj->dir[DIR_Attr] & AM_DIR) { /* The object is a directory */ + dj->sclust = LD_CLUST(dj->dir); + } else { /* The object is not a directory */ + res = FR_NO_PATH; + } + } + if (res == FR_OK) { + dj->id = dj->fs->id; + res = dir_sdi(dj, 0); /* Rewind dir */ + } + } + if (res == FR_NO_FILE) res = FR_NO_PATH; + } + + LEAVE_FF(dj->fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Read Directory Entry in Sequense */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_readdir ( + DIR *dj, /* Pointer to the open directory object */ + FILINFO *fno /* Pointer to file information to return */ +) +{ + FRESULT res; + DEF_NAMEBUF; + + + res = validate(dj->fs, dj->id); /* Check validity of the object */ + if (res == FR_OK) { + if (!fno) { + res = dir_sdi(dj, 0); /* Rewind the directory object */ + } else { + INIT_BUF(*dj); + res = dir_read(dj); /* Read an directory item */ + if (res == FR_NO_FILE) { /* Reached end of dir */ + dj->sect = 0; + res = FR_OK; + } + if (res == FR_OK) { /* A valid entry is found */ + get_fileinfo(dj, fno); /* Get the object information */ + res = dir_next(dj, 0); /* Increment index for next */ + if (res == FR_NO_FILE) { + dj->sect = 0; + res = FR_OK; + } + } + FREE_BUF(); + } + } + + LEAVE_FF(dj->fs, res); +} + + + +#if _FS_MINIMIZE == 0 +/*-----------------------------------------------------------------------*/ +/* Get File Status */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_stat ( + const TCHAR *path, /* Pointer to the file path */ + FILINFO *fno /* Pointer to file information to return */ +) +{ + FRESULT res; + DIR dj; + DEF_NAMEBUF; + + + res = chk_mounted(&path, &dj.fs, 0); + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK) { /* Follow completed */ + if (dj.dir) /* Found an object */ + get_fileinfo(&dj, fno); + else /* It is root dir */ + res = FR_INVALID_NAME; + } + FREE_BUF(); + } + + LEAVE_FF(dj.fs, res); +} + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Get Number of Free Clusters */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_getfree ( + const TCHAR *path, /* Pointer to the logical drive number (root dir) */ + DWORD *nclst, /* Pointer to the variable to return number of free clusters */ + FATFS **fatfs /* Pointer to pointer to corresponding file system object to return */ +) +{ + FRESULT res; + DWORD n, clst, sect, stat; + UINT i; + BYTE fat, *p; + + + /* Get drive number */ + res = chk_mounted(&path, fatfs, 0); + if (res == FR_OK) { + /* If free_clust is valid, return it without full cluster scan */ + if ((*fatfs)->free_clust <= (*fatfs)->n_fatent - 2) { + *nclst = (*fatfs)->free_clust; + } else { + /* Get number of free clusters */ + fat = (*fatfs)->fs_type; + n = 0; + if (fat == FS_FAT12) { + clst = 2; + do { + stat = get_fat(*fatfs, clst); + if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } + if (stat == 1) { res = FR_INT_ERR; break; } + if (stat == 0) n++; + } while (++clst < (*fatfs)->n_fatent); + } else { + clst = (*fatfs)->n_fatent; + sect = (*fatfs)->fatbase; + i = 0; p = 0; + do { + if (!i) { + res = move_window(*fatfs, sect++); + if (res != FR_OK) break; + p = (*fatfs)->win; + i = SS(*fatfs); + } + if (fat == FS_FAT16) { + if (LD_WORD(p) == 0) n++; + p += 2; i -= 2; + } else { + if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) n++; + p += 4; i -= 4; + } + } while (--clst); + } + (*fatfs)->free_clust = n; + if (fat == FS_FAT32) (*fatfs)->fsi_flag = 1; + *nclst = n; + } + } + LEAVE_FF(*fatfs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Truncate File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_truncate ( + FIL *fp /* Pointer to the file object */ +) +{ + FRESULT res; + DWORD ncl; + + + res = validate(fp->fs, fp->id); /* Check validity of the object */ + if (res == FR_OK) { + if (fp->flag & FA__ERROR) { /* Check abort flag */ + res = FR_INT_ERR; + } else { + if (!(fp->flag & FA_WRITE)) /* Check access mode */ + res = FR_DENIED; + } + } + if (res == FR_OK) { + if (fp->fsize > fp->fptr) { + fp->fsize = fp->fptr; /* Set file size to current R/W point */ + fp->flag |= FA__WRITTEN; + if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */ + res = remove_chain(fp->fs, fp->org_clust); + fp->org_clust = 0; + } else { /* When truncate a part of the file, remove remaining clusters */ + ncl = get_fat(fp->fs, fp->curr_clust); + res = FR_OK; + if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR; + if (ncl == 1) res = FR_INT_ERR; + if (res == FR_OK && ncl < fp->fs->n_fatent) { + res = put_fat(fp->fs, fp->curr_clust, 0x0FFFFFFF); + if (res == FR_OK) res = remove_chain(fp->fs, ncl); + } + } + } + if (res != FR_OK) fp->flag |= FA__ERROR; + } + + LEAVE_FF(fp->fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Delete a File or Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_unlink ( + const TCHAR *path /* Pointer to the file or directory path */ +) +{ + FRESULT res; + DIR dj, sdj; + BYTE *dir; + DWORD dclst; + DEF_NAMEBUF; + + + res = chk_mounted(&path, &dj.fs, 1); + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the file path */ + if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT)) + res = FR_INVALID_NAME; /* Cannot remove dot entry */ +#if _FS_SHARE + if (res == FR_OK) res = chk_lock(&dj, 2); /* Cannot remove open file */ +#endif + if (res == FR_OK) { /* The object is accessible */ + dir = dj.dir; + if (!dir) { + res = FR_INVALID_NAME; /* Cannot remove the start directory */ + } else { + if (dir[DIR_Attr] & AM_RDO) + res = FR_DENIED; /* Cannot remove R/O object */ + } + dclst = LD_CLUST(dir); + if (res == FR_OK && (dir[DIR_Attr] & AM_DIR)) { /* Is it a sub-dir? */ + if (dclst < 2) { + res = FR_INT_ERR; + } else { + mem_cpy(&sdj, &dj, sizeof(DIR)); /* Check if the sub-dir is empty or not */ + sdj.sclust = dclst; + res = dir_sdi(&sdj, 2); /* Exclude dot entries */ + if (res == FR_OK) { + res = dir_read(&sdj); + if (res == FR_OK /* Not empty dir */ +#if _FS_RPATH + || dclst == sdj.fs->cdir /* Current dir */ +#endif + ) res = FR_DENIED; + if (res == FR_NO_FILE) res = FR_OK; /* Empty */ + } + } + } + if (res == FR_OK) { + res = dir_remove(&dj); /* Remove the directory entry */ + if (res == FR_OK) { + if (dclst) /* Remove the cluster chain if exist */ + res = remove_chain(dj.fs, dclst); + if (res == FR_OK) res = sync(dj.fs); + } + } + } + FREE_BUF(); + } + LEAVE_FF(dj.fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Create a Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_mkdir ( + const TCHAR *path /* Pointer to the directory path */ +) +{ + FRESULT res; + DIR dj; + BYTE *dir, n; + DWORD dsc, dcl, pcl, tim = get_fattime(); + DEF_NAMEBUF; + + + res = chk_mounted(&path, &dj.fs, 1); + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */ + if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NS] & NS_DOT)) + res = FR_INVALID_NAME; + if (res == FR_NO_FILE) { /* Can create a new directory */ + dcl = create_chain(dj.fs, 0); /* Allocate a cluster for the new directory table */ + res = FR_OK; + if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */ + if (dcl == 1) res = FR_INT_ERR; + if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; + if (res == FR_OK) /* Flush FAT */ + res = move_window(dj.fs, 0); + if (res == FR_OK) { /* Initialize the new directory table */ + dsc = clust2sect(dj.fs, dcl); + dir = dj.fs->win; + mem_set(dir, 0, SS(dj.fs)); + mem_set(dir+DIR_Name, ' ', 8+3); /* Create "." entry */ + dir[DIR_Name] = '.'; + dir[DIR_Attr] = AM_DIR; + ST_DWORD(dir+DIR_WrtTime, tim); + ST_CLUST(dir, dcl); + mem_cpy(dir+32, dir, 32); /* Create ".." entry */ + dir[33] = '.'; pcl = dj.sclust; + if (dj.fs->fs_type == FS_FAT32 && pcl == dj.fs->dirbase) + pcl = 0; + ST_CLUST(dir+32, pcl); + for (n = dj.fs->csize; n; n--) { /* Write dot entries and clear following sectors */ + dj.fs->winsect = dsc++; + dj.fs->wflag = 1; + res = move_window(dj.fs, 0); + if (res != FR_OK) break; + mem_set(dir, 0, SS(dj.fs)); + } + } + if (res == FR_OK) res = dir_register(&dj); /* Register the object to the directoy */ + if (res != FR_OK) { + remove_chain(dj.fs, dcl); /* Could not register, remove cluster chain */ + } else { + dir = dj.dir; + dir[DIR_Attr] = AM_DIR; /* Attribute */ + ST_DWORD(dir+DIR_WrtTime, tim); /* Created time */ + ST_CLUST(dir, dcl); /* Table start cluster */ + dj.fs->wflag = 1; + res = sync(dj.fs); + } + } + FREE_BUF(); + } + + LEAVE_FF(dj.fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Change Attribute */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_chmod ( + const TCHAR *path, /* Pointer to the file path */ + BYTE value, /* Attribute bits */ + BYTE mask /* Attribute mask to change */ +) +{ + FRESULT res; + DIR dj; + BYTE *dir; + DEF_NAMEBUF; + + + res = chk_mounted(&path, &dj.fs, 1); + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the file path */ + FREE_BUF(); + if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT)) + res = FR_INVALID_NAME; + if (res == FR_OK) { + dir = dj.dir; + if (!dir) { /* Is it a root directory? */ + res = FR_INVALID_NAME; + } else { /* File or sub directory */ + mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ + dir[DIR_Attr] = (value & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ + dj.fs->wflag = 1; + res = sync(dj.fs); + } + } + } + + LEAVE_FF(dj.fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Change Timestamp */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_utime ( + const TCHAR *path, /* Pointer to the file/directory name */ + const FILINFO *fno /* Pointer to the time stamp to be set */ +) +{ + FRESULT res; + DIR dj; + BYTE *dir; + DEF_NAMEBUF; + + + res = chk_mounted(&path, &dj.fs, 1); + if (res == FR_OK) { + INIT_BUF(dj); + res = follow_path(&dj, path); /* Follow the file path */ + FREE_BUF(); + if (_FS_RPATH && res == FR_OK && (dj.fn[NS] & NS_DOT)) + res = FR_INVALID_NAME; + if (res == FR_OK) { + dir = dj.dir; + if (!dir) { /* Root directory */ + res = FR_INVALID_NAME; + } else { /* File or sub-directory */ + ST_WORD(dir+DIR_WrtTime, fno->ftime); + ST_WORD(dir+DIR_WrtDate, fno->fdate); + dj.fs->wflag = 1; + res = sync(dj.fs); + } + } + } + + LEAVE_FF(dj.fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Rename File/Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_rename ( + const TCHAR *path_old, /* Pointer to the old name */ + const TCHAR *path_new /* Pointer to the new name */ +) +{ + FRESULT res; + DIR djo, djn; + BYTE buf[21], *dir; + DWORD dw; + DEF_NAMEBUF; + + + res = chk_mounted(&path_old, &djo.fs, 1); + if (res == FR_OK) { + djn.fs = djo.fs; + INIT_BUF(djo); + res = follow_path(&djo, path_old); /* Check old object */ + if (_FS_RPATH && res == FR_OK && (djo.fn[NS] & NS_DOT)) + res = FR_INVALID_NAME; +#if _FS_SHARE + if (res == FR_OK) res = chk_lock(&djo, 2); +#endif + if (res == FR_OK) { /* Old object is found */ + if (!djo.dir) { /* Is root dir? */ + res = FR_NO_FILE; + } else { + mem_cpy(buf, djo.dir+DIR_Attr, 21); /* Save the object information except for name */ + mem_cpy(&djn, &djo, sizeof(DIR)); /* Check new object */ + res = follow_path(&djn, path_new); + if (res == FR_OK) res = FR_EXIST; /* The new object name is already existing */ + if (res == FR_NO_FILE) { /* Is it a valid path and no name collision? */ +/* Start critical section that any interruption or error can cause cross-link */ + res = dir_register(&djn); /* Register the new entry */ + if (res == FR_OK) { + dir = djn.dir; /* Copy object information except for name */ + mem_cpy(dir+13, buf+2, 19); + dir[DIR_Attr] = buf[0] | AM_ARC; + djo.fs->wflag = 1; + if (djo.sclust != djn.sclust && (dir[DIR_Attr] & AM_DIR)) { /* Update .. entry in the directory if needed */ + dw = clust2sect(djn.fs, LD_CLUST(dir)); + if (!dw) { + res = FR_INT_ERR; + } else { + res = move_window(djn.fs, dw); + dir = djn.fs->win+32; /* .. entry */ + if (res == FR_OK && dir[1] == '.') { + dw = (djn.fs->fs_type == FS_FAT32 && djn.sclust == djn.fs->dirbase) ? 0 : djn.sclust; + ST_CLUST(dir, dw); + djn.fs->wflag = 1; + } + } + } + if (res == FR_OK) { + res = dir_remove(&djo); /* Remove old entry */ + if (res == FR_OK) + res = sync(djo.fs); + } + } +/* End critical section */ + } + } + } + FREE_BUF(); + } + LEAVE_FF(djo.fs, res); +} + +#endif /* !_FS_READONLY */ +#endif /* _FS_MINIMIZE == 0 */ +#endif /* _FS_MINIMIZE <= 1 */ +#endif /* _FS_MINIMIZE <= 2 */ + + + +/*-----------------------------------------------------------------------*/ +/* Forward data to the stream directly (available on only tiny cfg) */ +/*-----------------------------------------------------------------------*/ +#if _USE_FORWARD && _FS_TINY + +FRESULT f_forward ( + FIL *fp, /* Pointer to the file object */ + UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */ + UINT btr, /* Number of bytes to forward */ + UINT *bf /* Pointer to number of bytes forwarded */ +) +{ + FRESULT res; + DWORD remain, clst, sect; + UINT rcnt; + BYTE csect; + + + *bf = 0; /* Initialize byte counter */ + + res = validate(fp->fs, fp->id); /* Check validity of the object */ + if (res != FR_OK) LEAVE_FF(fp->fs, res); + if (fp->flag & FA__ERROR) /* Check error flag */ + LEAVE_FF(fp->fs, FR_INT_ERR); + if (!(fp->flag & FA_READ)) /* Check access mode */ + LEAVE_FF(fp->fs, FR_DENIED); + + remain = fp->fsize - fp->fptr; + if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ + + for ( ; btr && (*func)(0, 0); /* Repeat until all data transferred or stream becomes busy */ + fp->fptr += rcnt, *bf += rcnt, btr -= rcnt) { + csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ + if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ + if (!csect) { /* On the cluster boundary? */ + clst = (fp->fptr == 0) ? /* On the top of the file? */ + fp->org_clust : get_fat(fp->fs, fp->curr_clust); + if (clst <= 1) ABORT(fp->fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fp->fs, FR_DISK_ERR); + fp->curr_clust = clst; /* Update current cluster */ + } + } + sect = clust2sect(fp->fs, fp->curr_clust); /* Get current data sector */ + if (!sect) ABORT(fp->fs, FR_INT_ERR); + sect += csect; + if (move_window(fp->fs, sect)) /* Move sector window */ + ABORT(fp->fs, FR_DISK_ERR); + fp->dsect = sect; + rcnt = SS(fp->fs) - (WORD)(fp->fptr % SS(fp->fs)); /* Forward data from sector window */ + if (rcnt > btr) rcnt = btr; + rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % SS(fp->fs)], rcnt); + if (!rcnt) ABORT(fp->fs, FR_INT_ERR); + } + + LEAVE_FF(fp->fs, FR_OK); +} +#endif /* _USE_FORWARD */ + + + +#if _USE_MKFS && !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Create File System on the Drive */ +/*-----------------------------------------------------------------------*/ +#define N_ROOTDIR 512 /* Multiple of 32 */ +#define N_FATS 1 /* 1 or 2 */ + + +FRESULT f_mkfs ( + BYTE drv, /* Logical drive number */ + BYTE sfd, /* Partitioning rule 0:FDISK, 1:SFD */ + UINT au /* Allocation unit size [bytes] */ +) +{ + static const WORD vst[] = { 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 0}; + static const WORD cst[] = {32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512}; + BYTE fmt, md, *tbl; + DWORD n_clst, vs, n, wsect; + UINT i; + DWORD b_vol, b_fat, b_dir, b_data; /* Offset (LBA) */ + DWORD n_vol, n_rsv, n_fat, n_dir; /* Size */ + FATFS *fs; + DSTATUS stat; + + + /* Check mounted drive and clear work area */ + if (drv >= _VOLUMES) return FR_INVALID_DRIVE; + fs = FatFs[drv]; + if (!fs) return FR_NOT_ENABLED; + fs->fs_type = 0; + drv = LD2PD(drv); + + /* Get disk statics */ + stat = disk_initialize(drv); + if (stat & STA_NOINIT) return FR_NOT_READY; + if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; +#if _MAX_SS != 512 /* Get disk sector size */ + if (disk_ioctl(drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) + return FR_DISK_ERR; +#endif + if (disk_ioctl(drv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128) + return FR_DISK_ERR; + b_vol = (sfd) ? 0 : 63; /* Volume start sector */ + n_vol -= b_vol; + if (au & (au - 1)) au = 0; /* Check validity of the allocation unit size */ + if (!au) { /* AU auto selection */ + vs = n_vol / (2000 / (SS(fs) / 512)); + for (i = 0; vs < vst[i]; i++) ; + au = cst[i]; + } + au /= SS(fs); /* Number of sectors per cluster */ + if (au == 0) au = 1; + if (au > 128) au = 128; + + /* Pre-compute number of clusters and FAT syb-type */ + n_clst = n_vol / au; + fmt = FS_FAT12; + if (n_clst >= MIN_FAT16) fmt = FS_FAT16; + if (n_clst >= MIN_FAT32) fmt = FS_FAT32; + + /* Determine offset and size of FAT structure */ + if (fmt == FS_FAT32) { + n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs); + n_rsv = 32; + n_dir = 0; + } else { + n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4; + n_fat = (n_fat + SS(fs) - 1) / SS(fs); + n_rsv = 1; + n_dir = N_ROOTDIR * 32UL / SS(fs); + } + b_fat = b_vol + n_rsv; /* FAT area start sector */ + b_dir = b_fat + n_fat * N_FATS; /* Directory area start sector */ + b_data = b_dir + n_dir; /* Data area start sector */ + if (n_vol < b_data + au) return FR_MKFS_ABORTED; /* Too small volume */ + + /* Align data start sector to erase block boundary (for flash memory media) */ + if (disk_ioctl(drv, GET_BLOCK_SIZE, &n) != RES_OK || !n || n > 32768) n = 1; + n = (b_data + n - 1) & ~(n - 1); /* Next nearest erase block from current data start */ + n = (n - b_data) / N_FATS; + if (fmt == FS_FAT32) { /* FAT32: Move FAT offset */ + n_rsv += n; + b_fat += n; + } else { /* FAT12/16: Expand FAT size */ + n_fat += n; + } + + /* Determine number of cluster and final check of validity of the FAT sub-type */ + n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au; + if ( (fmt == FS_FAT16 && n_clst < MIN_FAT16) + || (fmt == FS_FAT32 && n_clst < MIN_FAT32)) + return FR_MKFS_ABORTED; + + /* Create partition table if required */ + if (sfd) { + md = 0xF0; + } else { + DWORD n_disk = b_vol + n_vol; + + mem_set(fs->win, 0, SS(fs)); + tbl = fs->win+MBR_Table; + ST_DWORD(tbl, 0x00010180); /* Partition start in CHS */ + if (n_disk < 63UL * 255 * 1024) { /* Partition end in CHS */ + n_disk = n_disk / 63 / 255; + tbl[7] = (BYTE)n_disk; + tbl[6] = (BYTE)((n_disk >> 2) | 63); + } else { + ST_WORD(&tbl[6], 0xFFFF); + } + tbl[5] = 254; + if (fmt != FS_FAT32) /* System ID */ + tbl[4] = (n_vol < 0x10000) ? 0x04 : 0x06; + else + tbl[4] = 0x0c; + ST_DWORD(tbl+8, 63); /* Partition start in LBA */ + ST_DWORD(tbl+12, n_vol); /* Partition size in LBA */ + ST_WORD(tbl+64, 0xAA55); /* Signature */ + if (disk_write(drv, fs->win, 0, 1) != RES_OK) + return FR_DISK_ERR; + md = 0xF8; + } + + /* Create volume boot record */ + tbl = fs->win; /* Clear sector */ + mem_set(tbl, 0, SS(fs)); + mem_cpy(tbl, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot code, OEM name */ + i = SS(fs); /* Sector size */ + ST_WORD(tbl+BPB_BytsPerSec, i); + tbl[BPB_SecPerClus] = (BYTE)au; /* Sectors per cluster */ + ST_WORD(tbl+BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */ + tbl[BPB_NumFATs] = N_FATS; /* Number of FATs */ + i = (fmt == FS_FAT32) ? 0 : N_ROOTDIR; /* Number of rootdir entries */ + ST_WORD(tbl+BPB_RootEntCnt, i); + if (n_vol < 0x10000) { /* Number of total sectors */ + ST_WORD(tbl+BPB_TotSec16, n_vol); + } else { + ST_DWORD(tbl+BPB_TotSec32, n_vol); + } + tbl[BPB_Media] = md; /* Media descriptor */ + ST_WORD(tbl+BPB_SecPerTrk, 63); /* Number of sectors per track */ + ST_WORD(tbl+BPB_NumHeads, 255); /* Number of heads */ + ST_DWORD(tbl+BPB_HiddSec, b_vol); /* Hidden sectors */ + n = get_fattime(); /* Use current time as VSN */ + if (fmt == FS_FAT32) { + ST_DWORD(tbl+BS_VolID32, n); /* VSN */ + ST_DWORD(tbl+BPB_FATSz32, n_fat); /* Number of sectors per FAT */ + ST_DWORD(tbl+BPB_RootClus, 2); /* Root directory start cluster (2) */ + ST_WORD(tbl+BPB_FSInfo, 1); /* FSInfo record offset (VBR+1) */ + ST_WORD(tbl+BPB_BkBootSec, 6); /* Backup boot record offset (VBR+6) */ + tbl[BS_DrvNum32] = 0x80; /* Drive number */ + tbl[BS_BootSig32] = 0x29; /* Extended boot signature */ + mem_cpy(tbl+BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ + } else { + ST_DWORD(tbl+BS_VolID, n); /* VSN */ + ST_WORD(tbl+BPB_FATSz16, n_fat); /* Number of sectors per FAT */ + tbl[BS_DrvNum] = 0x80; /* Drive number */ + tbl[BS_BootSig] = 0x29; /* Extended boot signature */ + mem_cpy(tbl+BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ + } + ST_WORD(tbl+BS_55AA, 0xAA55); /* Signature (Offset is fixed here regardless of sector size) */ + if (disk_write(drv, tbl, b_vol, 1) != RES_OK)/* Write original (VBR) */ + return FR_DISK_ERR; + if (fmt == FS_FAT32) /* Write backup (VBR+6) */ + disk_write(drv, tbl, b_vol + 6, 1); + + /* Initialize FAT area */ + wsect = b_fat; + for (i = 0; i < N_FATS; i++) { + mem_set(tbl, 0, SS(fs)); /* 1st sector of the FAT */ + n = md; /* Media descriptor byte */ + if (fmt != FS_FAT32) { + n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00; + ST_DWORD(tbl+0, n); /* Reserve cluster #0-1 (FAT12/16) */ + } else { + n |= 0xFFFFFF00; + ST_DWORD(tbl+0, n); /* Reserve cluster #0-1 (FAT32) */ + ST_DWORD(tbl+4, 0xFFFFFFFF); + ST_DWORD(tbl+8, 0x0FFFFFFF); /* Reserve cluster #2 for root dir */ + } + if (disk_write(drv, tbl, wsect++, 1) != RES_OK) + return FR_DISK_ERR; + mem_set(tbl, 0, SS(fs)); /* Fill following FAT entries with zero */ + for (n = 1; n < n_fat; n++) { /* This loop may take a time on FAT32 volume due to many single sector write */ + if (disk_write(drv, tbl, wsect++, 1) != RES_OK) + return FR_DISK_ERR; + } + } + + /* Initialize root directory */ + i = (fmt == FS_FAT32) ? au : n_dir; + do { + if (disk_write(drv, tbl, wsect++, 1) != RES_OK) + return FR_DISK_ERR; + } while (--i); + +#if _USE_ERASE /* Erase data area if needed */ + { + DWORD eb[2]; + + eb[0] = wsect; eb[1] = wsect + n_clst * au - 1; + disk_ioctl(drv, CTRL_ERASE_SECTOR, eb); + } +#endif + + /* Create FSInfo if needed */ + if (fmt == FS_FAT32) { + ST_WORD(tbl+BS_55AA, 0xAA55); + ST_DWORD(tbl+FSI_LeadSig, 0x41615252); + ST_DWORD(tbl+FSI_StrucSig, 0x61417272); + ST_DWORD(tbl+FSI_Free_Count, n_clst - 1); + ST_DWORD(tbl+FSI_Nxt_Free, 0xFFFFFFFF); + disk_write(drv, tbl, b_vol + 1, 1); /* Write original (VBR+1) */ + disk_write(drv, tbl, b_vol + 7, 1); /* Write backup (VBR+7) */ + } + + return (disk_ioctl(drv, CTRL_SYNC, (void*)0) == RES_OK) ? FR_OK : FR_DISK_ERR; +} + +#endif /* _USE_MKFS && !_FS_READONLY */ + + + + +#if _USE_STRFUNC +/*-----------------------------------------------------------------------*/ +/* Get a string from the file */ +/*-----------------------------------------------------------------------*/ +TCHAR* f_gets ( + TCHAR* buff, /* Pointer to the string buffer to read */ + int len, /* Size of string buffer (characters) */ + FIL* fil /* Pointer to the file object */ +) +{ + int n = 0; + TCHAR c, *p = buff; + BYTE s[2]; + UINT rc; + + + while (n < len - 1) { /* Read bytes until buffer gets filled */ + f_read(fil, s, 1, &rc); + if (rc != 1) break; /* Break on EOF or error */ + c = s[0]; +#if _LFN_UNICODE /* Read a character in UTF-8 encoding */ + if (c >= 0x80) { + if (c < 0xC0) continue; /* Skip stray trailer */ + if (c < 0xE0) { /* Two-byte sequense */ + f_read(fil, s, 1, &rc); + if (rc != 1) break; + c = ((c & 0x1F) << 6) | (s[0] & 0x3F); + if (c < 0x80) c = '?'; + } else { + if (c < 0xF0) { /* Three-byte sequense */ + f_read(fil, s, 2, &rc); + if (rc != 2) break; + c = (c << 12) | ((s[0] & 0x3F) << 6) | (s[1] & 0x3F); + if (c < 0x800) c = '?'; + } else { /* Reject four-byte sequense */ + c = '?'; + } + } + } +#endif +#if _USE_STRFUNC >= 2 + if (c == '\r') continue; /* Strip '\r' */ +#endif + *p++ = c; + n++; + if (c == '\n') break; /* Break on EOL */ + } + *p = 0; + return n ? buff : 0; /* When no data read (eof or error), return with error. */ +} + + + +#if !_FS_READONLY +#include <stdarg.h> +/*-----------------------------------------------------------------------*/ +/* Put a character to the file */ +/*-----------------------------------------------------------------------*/ +int f_putc ( + TCHAR c, /* A character to be output */ + FIL* fil /* Pointer to the file object */ +) +{ + UINT bw, btw; + BYTE s[3]; + + +#if _USE_STRFUNC >= 2 + if (c == '\n') f_putc ('\r', fil); /* LF -> CRLF conversion */ +#endif + +#if _LFN_UNICODE /* Write the character in UTF-8 encoding */ + if (c < 0x80) { /* 7-bit */ + s[0] = (BYTE)c; + btw = 1; + } else { + if (c < 0x800) { /* 11-bit */ + s[0] = (BYTE)(0xC0 | (c >> 6)); + s[1] = (BYTE)(0x80 | (c & 0x3F)); + btw = 2; + } else { /* 16-bit */ + s[0] = (BYTE)(0xE0 | (c >> 12)); + s[1] = (BYTE)(0x80 | ((c >> 6) & 0x3F)); + s[2] = (BYTE)(0x80 | (c & 0x3F)); + btw = 3; + } + } +#else /* Write the character without conversion */ + s[0] = (BYTE)c; + btw = 1; +#endif + f_write(fil, s, btw, &bw); /* Write the char to the file */ + return (bw == btw) ? 1 : EOF; /* Return the result */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* Put a string to the file */ +/*-----------------------------------------------------------------------*/ +int f_puts ( + const TCHAR* str, /* Pointer to the string to be output */ + FIL* fil /* Pointer to the file object */ +) +{ + int n; + + + for (n = 0; *str; str++, n++) { + if (f_putc(*str, fil) == EOF) return EOF; + } + return n; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Put a formatted string to the file */ +/*-----------------------------------------------------------------------*/ +int f_printf ( + FIL* fil, /* Pointer to the file object */ + const TCHAR* str, /* Pointer to the format string */ + ... /* Optional arguments... */ +) +{ + va_list arp; + BYTE f, r; + UINT i, w; + ULONG val; + TCHAR c, d, s[16]; + int res, cc; + + + va_start(arp, str); + + for (cc = res = 0; cc != EOF; res += cc) { + c = *str++; + if (c == 0) break; /* End of string */ + if (c != '%') { /* Non escape character */ + cc = f_putc(c, fil); + if (cc != EOF) cc = 1; + continue; + } + w = f = 0; + c = *str++; + if (c == '0') { /* Flag: '0' padding */ + f = 1; c = *str++; + } + while (IsDigit(c)) { /* Precision */ + w = w * 10 + c - '0'; + c = *str++; + } + if (c == 'l' || c == 'L') { /* Prefix: Size is long int */ + f |= 2; c = *str++; + } + if (!c) break; + d = c; + if (IsLower(d)) d -= 0x20; + switch (d) { /* Type is... */ + case 'S' : /* String */ + cc = f_puts(va_arg(arp, TCHAR*), fil); continue; + case 'C' : /* Character */ + cc = f_putc((TCHAR)va_arg(arp, int), fil); continue; + case 'B' : /* Binary */ + r = 2; break; + case 'O' : /* Octal */ + r = 8; break; + case 'D' : /* Signed decimal */ + case 'U' : /* Unsigned decimal */ + r = 10; break; + case 'X' : /* Hexdecimal */ + r = 16; break; + default: /* Unknown */ + cc = f_putc(c, fil); continue; + } + + /* Get an argument */ + val = (f & 2) ? va_arg(arp, long) : ((d == 'D') ? (long)va_arg(arp, int) : va_arg(arp, unsigned int)); + if (d == 'D' && (val & 0x80000000)) { + val = 0 - val; + f |= 4; + } + /* Put it in numeral string */ + i = 0; + do { + d = (TCHAR)(val % r); val /= r; + if (d > 9) { + d += 7; + if (c == 'x') d += 0x20; + } + s[i++] = d + '0'; + } while (val && i < sizeof(s) / sizeof(s[0])); + if (f & 4) s[i++] = '-'; + cc = 0; + while (i < w-- && cc != EOF) { + cc = f_putc((TCHAR)((f & 1) ? '0' : ' '), fil); + res++; + } + do { + cc = f_putc(s[--i], fil); + res++; + } while (i && cc != EOF); + if (cc != EOF) cc = 0; + } + + va_end(arp); + return (cc == EOF) ? cc : res; +} + +#endif /* !_FS_READONLY */ +#endif /* _USE_STRFUNC */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flash/FatFS/ff.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,541 @@ +/*---------------------------------------------------------------------------/ +/ FatFs - FAT file system module include file R0.08a (C)ChaN, 2010 +/----------------------------------------------------------------------------/ +/ FatFs module is a generic FAT file system module for small embedded systems. +/ This is a free software that opened for education, research and commercial +/ developments under license policy of following trems. +/ +/ Copyright (C) 2010, ChaN, all right reserved. +/ +/ * The FatFs module is a free software and there is NO WARRANTY. +/ * No restriction on use. You can use, modify and redistribute it for +/ personal, non-profit or commercial product UNDER YOUR RESPONSIBILITY. +/ * Redistributions of source code must retain the above copyright notice. +/ +/----------------------------------------------------------------------------*/ + +#ifndef _FATFS +#define _FATFS 8255 /* Revision ID */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "integer.h" /* Basic integer types */ +#include "ffconf.h" /* FatFs configuration options */ + +#if _FATFS != _FFCONF +#error Wrong configuration file (ffconf.h). +#endif + + +/* DBCS code ranges and SBCS extend char conversion table */ + +#if _CODE_PAGE == 932 /* Japanese Shift-JIS */ +#define _DF1S 0x81 /* DBC 1st byte range 1 start */ +#define _DF1E 0x9F /* DBC 1st byte range 1 end */ +#define _DF2S 0xE0 /* DBC 1st byte range 2 start */ +#define _DF2E 0xFC /* DBC 1st byte range 2 end */ +#define _DS1S 0x40 /* DBC 2nd byte range 1 start */ +#define _DS1E 0x7E /* DBC 2nd byte range 1 end */ +#define _DS2S 0x80 /* DBC 2nd byte range 2 start */ +#define _DS2E 0xFC /* DBC 2nd byte range 2 end */ + +#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */ +#define _DF1S 0x81 +#define _DF1E 0xFE +#define _DS1S 0x40 +#define _DS1E 0x7E +#define _DS2S 0x80 +#define _DS2E 0xFE + +#elif _CODE_PAGE == 949 /* Korean */ +#define _DF1S 0x81 +#define _DF1E 0xFE +#define _DS1S 0x41 +#define _DS1E 0x5A +#define _DS2S 0x61 +#define _DS2E 0x7A +#define _DS3S 0x81 +#define _DS3E 0xFE + +#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */ +#define _DF1S 0x81 +#define _DF1E 0xFE +#define _DS1S 0x40 +#define _DS1E 0x7E +#define _DS2S 0xA1 +#define _DS2E 0xFE + +#elif _CODE_PAGE == 437 /* U.S. (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F,0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 720 /* Arabic (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x45,0x41,0x84,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x49,0x49,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 737 /* Greek (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \ + 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xE7,0xE8,0xF1,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 775 /* Baltic (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 850 /* Multilingual Latin 1 (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 852 /* Latin 2 (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F,0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0x9F, \ + 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF} + +#elif _CODE_PAGE == 855 /* Cyrillic (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F,0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \ + 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \ + 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 857 /* Turkish (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x98,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \ + 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0x59,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 858 /* Multilingual Latin 1 + Euro (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 862 /* Hebrew (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 866 /* Russian (OEM) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 874 /* Thai (OEM, Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 1250 /* Central Europe (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xA3,0xB4,0xB5,0xB6,0xB7,0xB8,0xA5,0xAA,0xBB,0xBC,0xBD,0xBC,0xAF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF} + +#elif _CODE_PAGE == 1251 /* Cyrillic (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x82,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x80,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \ + 0xA0,0xA2,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB2,0xA5,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xA3,0xBD,0xBD,0xAF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF} + +#elif _CODE_PAGE == 1252 /* Latin 1 (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0xAd,0x9B,0x8C,0x9D,0xAE,0x9F, \ + 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F} + +#elif _CODE_PAGE == 1253 /* Greek (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xA2,0xB8,0xB9,0xBA, \ + 0xE0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xFB,0xBC,0xFD,0xBF,0xFF} + +#elif _CODE_PAGE == 1254 /* Turkish (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x9D,0x9E,0x9F, \ + 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F} + +#elif _CODE_PAGE == 1255 /* Hebrew (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 1256 /* Arabic (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x8C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0x41,0xE1,0x41,0xE3,0xE4,0xE5,0xE6,0x43,0x45,0x45,0x45,0x45,0xEC,0xED,0x49,0x49,0xF0,0xF1,0xF2,0xF3,0x4F,0xF5,0xF6,0xF7,0xF8,0x55,0xFA,0x55,0x55,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 1257 /* Baltic (Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xBC,0xBD,0xBE,0xAF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF} + +#elif _CODE_PAGE == 1258 /* Vietnam (OEM, Windows) */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0xAC,0x9D,0x9E,0x9F, \ + 0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xEC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xFE,0x9F} + +#elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */ +#define _DF1S 0 + +#else +#error Unknown code page + +#endif + + + +/* Definitions of volume management */ + +#if _MULTI_PARTITION /* Multiple partition configuration */ +#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive# */ +#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition# */ +typedef struct { + BYTE pd; /* Physical drive# */ + BYTE pt; /* Partition # (0-3) */ +} PARTITION; +extern const PARTITION VolToPart[]; /* Volume - Physical location resolution table */ + +#else /* Single partition configuration */ +#define LD2PD(vol) (vol) /* Logical drive# is bound to the same physical drive# */ +#define LD2PT(vol) 0 /* Always mounts the 1st partition */ + +#endif + + + +/* Type of path name strings on FatFs API */ + +#if _LFN_UNICODE /* Unicode string */ +#if !_USE_LFN +#error _LFN_UNICODE must be 0 in non-LFN cfg. +#endif +#ifndef _INC_TCHAR +typedef WCHAR TCHAR; +#define _T(x) L ## x +#define _TEXT(x) L ## x +#endif + +#else /* ANSI/OEM string */ +#ifndef _INC_TCHAR +typedef char TCHAR; +#define _T(x) x +#define _TEXT(x) x +#endif + +#endif + + + +/* File system object structure (FATFS) */ + +typedef struct { + BYTE fs_type; /* FAT sub-type (0:Not mounted) */ + BYTE drv; /* Physical drive number */ + BYTE csize; /* Sectors per cluster (1,2,4...128) */ + BYTE n_fats; /* Number of FAT copies (1,2) */ + BYTE wflag; /* win[] dirty flag (1:must be written back) */ + BYTE fsi_flag; /* fsinfo dirty flag (1:must be written back) */ + WORD id; /* File system mount ID */ + WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ +#if _MAX_SS != 512 + WORD ssize; /* Bytes per sector (512,1024,2048,4096) */ +#endif +#if _FS_REENTRANT + _SYNC_t sobj; /* Identifier of sync object */ +#endif +#if !_FS_READONLY + DWORD last_clust; /* Last allocated cluster */ + DWORD free_clust; /* Number of free clusters */ + DWORD fsi_sector; /* fsinfo sector (FAT32) */ +#endif +#if _FS_RPATH + DWORD cdir; /* Current directory start cluster (0:root) */ +#endif + DWORD n_fatent; /* Number of FAT entries (= number of clusters + 2) */ + DWORD fsize; /* Sectors per FAT */ + DWORD fatbase; /* FAT start sector */ + DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */ + DWORD database; /* Data start sector */ + DWORD winsect; /* Current sector appearing in the win[] */ + BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and Data on tiny cfg) */ +} FATFS; + + + +/* File object structure (FIL) */ + +typedef struct { + FATFS* fs; /* Pointer to the owner file system object */ + WORD id; /* Owner file system mount ID */ + BYTE flag; /* File status flags */ + BYTE pad1; + DWORD fptr; /* File read/write pointer (0 on file open) */ + DWORD fsize; /* File size */ + DWORD org_clust; /* File start cluster (0 when fsize==0) */ + DWORD curr_clust; /* Current cluster */ + DWORD dsect; /* Current data sector */ +#if !_FS_READONLY + DWORD dir_sect; /* Sector containing the directory entry */ + BYTE* dir_ptr; /* Ponter to the directory entry in the window */ +#endif +#if _USE_FASTSEEK + DWORD* cltbl; /* Pointer to the cluster link map table (null on file open) */ +#endif +#if _FS_SHARE + UINT lockid; /* File lock ID (index of file semaphore table) */ +#endif +#if !_FS_TINY + BYTE buf[_MAX_SS]; /* File data read/write buffer */ +#endif +} FIL; + + + +/* Directory object structure (DIR) */ + +typedef struct { + FATFS* fs; /* Pointer to the owner file system object */ + WORD id; /* Owner file system mount ID */ + WORD index; /* Current read/write index number */ + DWORD sclust; /* Table start cluster (0:Root dir) */ + DWORD clust; /* Current cluster */ + DWORD sect; /* Current sector */ + BYTE* dir; /* Pointer to the current SFN entry in the win[] */ + BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */ +#if _USE_LFN + WCHAR* lfn; /* Pointer to the LFN working buffer */ + WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */ +#endif +} DIR; + + + +/* File status structure (FILINFO) */ + +typedef struct { + DWORD fsize; /* File size */ + WORD fdate; /* Last modified date */ + WORD ftime; /* Last modified time */ + BYTE fattrib; /* Attribute */ + TCHAR fname[13]; /* Short file name (8.3 format) */ +#if _USE_LFN + TCHAR* lfname; /* Pointer to the LFN buffer */ + UINT lfsize; /* Size of LFN buffer in TCHAR */ +#endif +} FILINFO; + + + +/* File function return code (FRESULT) */ + +typedef enum { + FR_OK = 0, /* (0) Succeeded */ + FR_DISK_ERR, /* (1) A hard error occured in the low level disk I/O layer */ + FR_INT_ERR, /* (2) Assertion failed */ + FR_NOT_READY, /* (3) The physical drive cannot work */ + FR_NO_FILE, /* (4) Could not find the file */ + FR_NO_PATH, /* (5) Could not find the path */ + FR_INVALID_NAME, /* (6) The path name format is invalid */ + FR_DENIED, /* (7) Acces denied due to prohibited access or directory full */ + FR_EXIST, /* (8) Acces denied due to prohibited access */ + FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */ + FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */ + FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */ + FR_NOT_ENABLED, /* (12) The volume has no work area */ + FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume on the physical drive */ + FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */ + FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ + FR_LOCKED, /* (16) The operation is rejected according to the file shareing policy */ + FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ + FR_TOO_MANY_OPEN_FILES /* (18) Number of open files > _FS_SHARE */ +} FRESULT; + + + +/*--------------------------------------------------------------*/ +/* FatFs module application interface */ + +FRESULT f_mount (BYTE, FATFS*); /* Mount/Unmount a logical drive */ +FRESULT f_open (FIL*, const TCHAR*, BYTE); /* Open or create a file */ +FRESULT f_read (FIL*, void*, UINT, UINT*); /* Read data from a file */ +FRESULT f_lseek (FIL*, DWORD); /* Move file pointer of a file object */ +FRESULT f_close (FIL*); /* Close an open file object */ +FRESULT f_opendir (DIR*, const TCHAR*); /* Open an existing directory */ +FRESULT f_readdir (DIR*, FILINFO*); /* Read a directory item */ +FRESULT f_stat (const TCHAR*, FILINFO*); /* Get file status */ + +#if !_FS_READONLY +FRESULT f_write (FIL*, const void*, UINT, UINT*); /* Write data to a file */ +FRESULT f_getfree (const TCHAR*, DWORD*, FATFS**); /* Get number of free clusters on the drive */ +FRESULT f_truncate (FIL*); /* Truncate file */ +FRESULT f_sync (FIL*); /* Flush cached data of a writing file */ +FRESULT f_unlink (const TCHAR*); /* Delete an existing file or directory */ +FRESULT f_mkdir (const TCHAR*); /* Create a new directory */ +FRESULT f_chmod (const TCHAR*, BYTE, BYTE); /* Change attriburte of the file/dir */ +FRESULT f_utime (const TCHAR*, const FILINFO*); /* Change timestamp of the file/dir */ +FRESULT f_rename (const TCHAR*, const TCHAR*); /* Rename/Move a file or directory */ +#endif + +#if _USE_FORWARD +FRESULT f_forward (FIL*, UINT(*)(const BYTE*,UINT), UINT, UINT*); /* Forward data to the stream */ +#endif + +#if _USE_MKFS +FRESULT f_mkfs (BYTE, BYTE, UINT); /* Create a file system on the drive */ +#endif + +#if _FS_RPATH +FRESULT f_chdrive (BYTE); /* Change current drive */ +FRESULT f_chdir (const TCHAR*); /* Change current directory */ +FRESULT f_getcwd (TCHAR*, UINT); /* Get current directory */ +#endif + +#if _USE_STRFUNC +int f_putc (TCHAR, FIL*); /* Put a character to the file */ +int f_puts (const TCHAR*, FIL*); /* Put a string to the file */ +int f_printf (FIL*, const TCHAR*, ...); /* Put a formatted string to the file */ +TCHAR* f_gets (TCHAR*, int, FIL*); /* Get a string from the file */ +#ifndef EOF +#define EOF (-1) +#endif +#endif + +#define f_eof(fp) (((fp)->fptr == (fp)->fsize) ? 1 : 0) +#define f_error(fp) (((fp)->flag & FA__ERROR) ? 1 : 0) +#define f_tell(fp) ((fp)->fptr) +#define f_size(fp) ((fp)->fsize) + + + +/*--------------------------------------------------------------*/ +/* Additional user defined functions */ + +/* RTC function */ +#if !_FS_READONLY +DWORD get_fattime (void); +#endif + +/* Unicode support functions */ +#if _USE_LFN /* Unicode - OEM code conversion */ +WCHAR ff_convert (WCHAR, UINT); /* OEM-Unicode bidirectional conversion */ +WCHAR ff_wtoupper (WCHAR); /* Unicode upper-case conversion */ +#if _USE_LFN == 3 /* Memory functions */ +void* ff_memalloc (UINT); /* Allocate memory block */ +void ff_memfree (void*); /* Free memory block */ +#endif +#endif + +/* Sync functions */ +#if _FS_REENTRANT +int ff_cre_syncobj (BYTE, _SYNC_t*);/* Create a sync object */ +int ff_del_syncobj (_SYNC_t); /* Delete a sync object */ +int ff_req_grant (_SYNC_t); /* Lock sync object */ +void ff_rel_grant (_SYNC_t); /* Unlock sync object */ +#endif + + + + +/*--------------------------------------------------------------*/ +/* Flags and offset address */ + + +/* File access control and file status flags (FIL.flag) */ + +#define FA_READ 0x01 +#define FA_OPEN_EXISTING 0x00 +#define FA__ERROR 0x80 + +#if !_FS_READONLY +#define FA_WRITE 0x02 +#define FA_CREATE_NEW 0x04 +#define FA_CREATE_ALWAYS 0x08 +#define FA_OPEN_ALWAYS 0x10 +#define FA__WRITTEN 0x20 +#define FA__DIRTY 0x40 +#endif + + +/* FAT sub type (FATFS.fs_type) */ + +#define FS_FAT12 1 +#define FS_FAT16 2 +#define FS_FAT32 3 + + +/* File attribute bits for directory entry */ + +#define AM_RDO 0x01 /* Read only */ +#define AM_HID 0x02 /* Hidden */ +#define AM_SYS 0x04 /* System */ +#define AM_VOL 0x08 /* Volume label */ +#define AM_LFN 0x0F /* LFN entry */ +#define AM_DIR 0x10 /* Directory */ +#define AM_ARC 0x20 /* Archive */ +#define AM_MASK 0x3F /* Mask of defined bits */ + + +/* Fast seek function */ +#define CREATE_LINKMAP 0xFFFFFFFF + + +/*--------------------------------*/ +/* Multi-byte word access macros */ + +#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */ +#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr)) +#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr)) +#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val) +#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val) +#else /* Use byte-by-byte access to the FAT structure */ +#define LD_WORD(ptr) (WORD)(((WORD)*(BYTE*)((ptr)+1)<<8)|(WORD)*(BYTE*)(ptr)) +#define LD_DWORD(ptr) (DWORD)(((DWORD)*(BYTE*)((ptr)+3)<<24)|((DWORD)*(BYTE*)((ptr)+2)<<16)|((WORD)*(BYTE*)((ptr)+1)<<8)|*(BYTE*)(ptr)) +#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *(BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8) +#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *(BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8); *(BYTE*)((ptr)+2)=(BYTE)((DWORD)(val)>>16); *(BYTE*)((ptr)+3)=(BYTE)((DWORD)(val)>>24) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _FATFS */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flash/FatFS/ffconf.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,188 @@ +/*---------------------------------------------------------------------------/ +/ FatFs - FAT file system module configuration file R0.08a (C)ChaN, 2010 +/----------------------------------------------------------------------------/ +/ +/ CAUTION! Do not forget to make clean the project after any changes to +/ the configuration options. +/ +/----------------------------------------------------------------------------*/ +#ifndef _FFCONF +#define _FFCONF 8255 /* Revision ID */ + + +/*---------------------------------------------------------------------------/ +/ Function and Buffer Configurations +/----------------------------------------------------------------------------*/ + +#define _FS_TINY 0 /* 0:Normal or 1:Tiny */ +/* When _FS_TINY is set to 1, FatFs uses the sector buffer in the file system +/ object instead of the sector buffer in the individual file object for file +/ data transfer. This reduces memory consumption 512 bytes each file object. */ + + +#define _FS_READONLY 0 /* 0:Read/Write or 1:Read only */ +/* Setting _FS_READONLY to 1 defines read only configuration. This removes +/ writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename, +/ f_truncate and useless f_getfree. */ + + +#define _FS_MINIMIZE 0 /* 0 to 3 */ +/* The _FS_MINIMIZE option defines minimization level to remove some functions. +/ +/ 0: Full function. +/ 1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod, f_truncate and f_rename +/ are removed. +/ 2: f_opendir and f_readdir are removed in addition to 1. +/ 3: f_lseek is removed in addition to 2. */ + + +#define _USE_STRFUNC 1 /* 0:Disable or 1/2:Enable */ +/* To enable string functions, set _USE_STRFUNC to 1 or 2. */ + + +#define _USE_MKFS 0 /* 0:Disable or 1:Enable */ +/* To enable f_mkfs function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */ + + +#define _USE_FORWARD 0 /* 0:Disable or 1:Enable */ +/* To enable f_forward function, set _USE_FORWARD to 1 and set _FS_TINY to 1. */ + + +#define _USE_FASTSEEK 0 /* 0:Disable or 1:Enable */ +/* To enable fast seek feature, set _USE_FASTSEEK to 1. */ + + + +/*---------------------------------------------------------------------------/ +/ Locale and Namespace Configurations +/----------------------------------------------------------------------------*/ + +#define _CODE_PAGE 437 +/* The _CODE_PAGE specifies the OEM code page to be used on the target system. +/ Incorrect setting of the code page can cause a file open failure. +/ +/ 932 - Japanese Shift-JIS (DBCS, OEM, Windows) +/ 936 - Simplified Chinese GBK (DBCS, OEM, Windows) +/ 949 - Korean (DBCS, OEM, Windows) +/ 950 - Traditional Chinese Big5 (DBCS, OEM, Windows) +/ 1250 - Central Europe (Windows) +/ 1251 - Cyrillic (Windows) +/ 1252 - Latin 1 (Windows) +/ 1253 - Greek (Windows) +/ 1254 - Turkish (Windows) +/ 1255 - Hebrew (Windows) +/ 1256 - Arabic (Windows) +/ 1257 - Baltic (Windows) +/ 1258 - Vietnam (OEM, Windows) +/ 437 - U.S. (OEM) +/ 720 - Arabic (OEM) +/ 737 - Greek (OEM) +/ 775 - Baltic (OEM) +/ 850 - Multilingual Latin 1 (OEM) +/ 858 - Multilingual Latin 1 + Euro (OEM) +/ 852 - Latin 2 (OEM) +/ 855 - Cyrillic (OEM) +/ 866 - Russian (OEM) +/ 857 - Turkish (OEM) +/ 862 - Hebrew (OEM) +/ 874 - Thai (OEM, Windows) +/ 1 - ASCII only (Valid for non LFN cfg.) +*/ + + +#define _USE_LFN 1 /* 0 to 3 */ +#define _MAX_LFN 255 /* Maximum LFN length to handle (12 to 255) */ +/* The _USE_LFN option switches the LFN support. +/ +/ 0: Disable LFN feature. _MAX_LFN and _LFN_UNICODE have no effect. +/ 1: Enable LFN with static working buffer on the BSS. Always NOT reentrant. +/ 2: Enable LFN with dynamic working buffer on the STACK. +/ 3: Enable LFN with dynamic working buffer on the HEAP. +/ +/ The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. To enable LFN, +/ Unicode handling functions ff_convert() and ff_wtoupper() must be added +/ to the project. When enable to use heap, memory control functions +/ ff_memalloc() and ff_memfree() must be added to the project. */ + + +#define _LFN_UNICODE 0 /* 0:ANSI/OEM or 1:Unicode */ +/* To switch the character code set on FatFs API to Unicode, +/ enable LFN feature and set _LFN_UNICODE to 1. */ + + +#define _FS_RPATH 0 /* 0 to 2 */ +/* The _FS_RPATH option configures relative path feature. +/ +/ 0: Disable relative path feature and remove related functions. +/ 1: Enable relative path. f_chdrive() and f_chdir() are available. +/ 2: f_getcwd() is available in addition to 1. +/ +/ Note that output of the f_readdir fnction is affected by this option. */ + + + +/*---------------------------------------------------------------------------/ +/ Physical Drive Configurations +/----------------------------------------------------------------------------*/ + +#define _VOLUMES 1 +/* Number of volumes (logical drives) to be used. */ + + +#define _MAX_SS 512 /* 512, 1024, 2048 or 4096 */ +/* Maximum sector size to be handled. +/ Always set 512 for memory card and hard disk but a larger value may be +/ required for floppy disk (512/1024) and optical disk (512/2048). +/ When _MAX_SS is larger than 512, GET_SECTOR_SIZE command must be implememted +/ to the disk_ioctl function. */ + + +#define _MULTI_PARTITION 0 /* 0:Single partition or 1:Multiple partition */ +/* When set to 0, each volume is bound to the same physical drive number and +/ it can mount only first primaly partition. When it is set to 1, each volume +/ is tied to the partitions listed in VolToPart[]. */ + + +#define _USE_ERASE 0 /* 0:Disable or 1:Enable */ +/* To enable sector erase feature, set _USE_ERASE to 1. */ + + + +/*---------------------------------------------------------------------------/ +/ System Configurations +/----------------------------------------------------------------------------*/ + +#define _WORD_ACCESS 0 /* 0 or 1 */ +/* Set 0 first and it is always compatible with all platforms. The _WORD_ACCESS +/ option defines which access method is used to the word data on the FAT volume. +/ +/ 0: Byte-by-byte access. +/ 1: Word access. Do not choose this unless following condition is met. +/ +/ When the byte order on the memory is big-endian or address miss-aligned word +/ access results incorrect behavior, the _WORD_ACCESS must be set to 0. +/ If it is not the case, the value can also be set to 1 to improve the +/ performance and code size. */ + + +/* Include a header file here to define sync object types on the O/S */ +/* #include <windows.h>, <ucos_ii.h.h>, <semphr.h> or ohters. */ + +#define _FS_REENTRANT 0 /* 0:Disable or 1:Enable */ +#define _FS_TIMEOUT 1000 /* Timeout period in unit of time ticks */ +#define _SYNC_t HANDLE /* O/S dependent type of sync object. e.g. HANDLE, OS_EVENT*, ID and etc.. */ + +/* The _FS_REENTRANT option switches the reentrancy of the FatFs module. +/ +/ 0: Disable reentrancy. _SYNC_t and _FS_TIMEOUT have no effect. +/ 1: Enable reentrancy. Also user provided synchronization handlers, +/ ff_req_grant, ff_rel_grant, ff_del_syncobj and ff_cre_syncobj +/ function must be added to the project. */ + + +#define _FS_SHARE 0 /* 0:Disable or >=1:Enable */ +/* To enable file shareing feature, set _FS_SHARE to 1 or greater. The value + defines how many files can be opened simultaneously. */ + + +#endif /* _FFCONFIG */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flash/FatFS/integer.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,37 @@ +/*-------------------------------------------*/ +/* Integer type definitions for FatFs module */ +/*-------------------------------------------*/ + +#ifndef _INTEGER +#define _INTEGER + +#ifdef _WIN32 /* FatFs development platform */ + +#include <windows.h> +#include <tchar.h> + +#else /* Embedded platform */ + +/* These types must be 16-bit, 32-bit or larger integer */ +typedef int INT; +typedef unsigned int UINT; + +/* These types must be 8-bit integer */ +typedef char CHAR; +typedef unsigned char UCHAR; +typedef unsigned char BYTE; + +/* These types must be 16-bit integer */ +typedef short SHORT; +typedef unsigned short USHORT; +typedef unsigned short WORD; +typedef unsigned short WCHAR; + +/* These types must be 32-bit integer */ +typedef long LONG; +typedef unsigned long ULONG; +typedef unsigned long DWORD; + +#endif + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flash/FatFS/option/ccsbcs.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,542 @@ + + +/* (SBCS code pages) */ +/*------------------------------------------------------------------------*/ +/* 437 U.S. (OEM) +/ 720 Arabic (OEM) +/ 1256 Arabic (Windows) +/ 737 Greek (OEM) +/ 1253 Greek (Windows) +/ 1250 Central Europe (Windows) +/ 775 Baltic (OEM) +/ 1257 Baltic (Windows) +/ 850 Multilingual Latin 1 (OEM) +/ 852 Latin 2 (OEM) +/ 1252 Latin 1 (Windows) +/ 855 Cyrillic (OEM) +/ 1251 Cyrillic (Windows) AjK Patched http://elm-chan.org/fsw/ff/patches.html +/ 866 Russian (OEM) +/ 857 Turkish (OEM) +/ 1254 Turkish (Windows) +/ 858 Multilingual Latin 1 + Euro (OEM) +/ 862 Hebrew (OEM) +/ 1255 Hebrew (Windows) +/ 874 Thai (OEM, Windows) +/ 1258 Vietnam (OEM, Windows) +*/ + +#include "../ff.h" + + +#if _CODE_PAGE == 437 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, + 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, + 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, + 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 720 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP720(0x80-0xFF) to Unicode conversion table */ + 0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, + 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, + 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642, + 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A, + 0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0xO650, 0x2248, + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 737 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP737(0x80-0xFF) to Unicode conversion table */ + 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, + 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, + 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, + 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, + 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, + 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD, + 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E, + 0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248, + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 775 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP775(0x80-0xFF) to Unicode conversion table */ + 0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, + 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, + 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4, + 0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, + 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118, + 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D, + 0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B, + 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144, + 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019, + 0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E, + 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 850 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP850(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, + 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, + 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, + 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, + 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, + 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, + 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, + 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 852 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP852(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, + 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106, + 0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, + 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, + 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A, + 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE, + 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, + 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4, + 0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, + 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 855 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP855(0x80-0xFF) to Unicode conversion table */ + 0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, + 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408, + 0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, + 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A, + 0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, + 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, + 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E, + 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580, + 0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, + 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116, + 0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D, + 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 857 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP857(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, + 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, + 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, + 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE, + 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000, + 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4, + 0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, + 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 858 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP858(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, + 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, + 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, + 0x00A9, 0x2563, 0x2551, 0x2557, 0x2550, 0x00A2, 0x00A5, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x20AC, 0x00CD, 0x00CE, + 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00C6, 0x00CC, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, + 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, + 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, + 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 862 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP862(0x80-0xFF) to Unicode conversion table */ + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, + 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, + 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, + 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, + 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 866 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP866(0x80-0xFF) to Unicode conversion table */ + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + 0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 874 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP874(0x80-0xFF) to Unicode conversion table */ + 0x20AC, 0x0000, 0x0000, 0x0000, 0x0000, 0x2026, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07, + 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F, + 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17, + 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F, + 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27, + 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F, + 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37, + 0x0E38, 0x0E39, 0x0E3A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0E3F, + 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47, + 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F, + 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57, + 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0x0000, 0x0000, 0x0000, 0x0000 +}; + +#elif _CODE_PAGE == 1250 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP1250(0x80-0xFF) to Unicode conversion table */ + 0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021, + 0x0000, 0x2030, 0x0160, 0x2039, 0x015A, 0x0164, 0x017D, 0x0179, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x0000, 0x2122, 0x0161, 0x203A, 0x015B, 0x0165, 0x017E, 0x017A, + 0x00A0, 0x02C7, 0x02D8, 0x0141, 0x00A4, 0x0104, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x015E, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x017B, + 0x00B0, 0x00B1, 0x02DB, 0x0142, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x0105, 0x015F, 0x00BB, 0x013D, 0x02DD, 0x013E, 0x017C, + 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, + 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, + 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, + 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, + 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, + 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9 +}; + +#elif _CODE_PAGE == 1251 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP1251(0x80-0xFF) to Unicode conversion table */ + 0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021, + 0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F, + 0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x0000, 0x2111, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F, + 0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7, + 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407, + 0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7, + 0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F +}; + +#elif _CODE_PAGE == 1252 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP1252(0x80-0xFF) to Unicode conversion table */ + 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x017D, 0x0000, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x017E, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00BD, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF +}; + +#elif _CODE_PAGE == 1253 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP1253(0x80-0xFF) to Unicode conversion table */ + 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x0000, 0x2030, 0x0000, 0x2039, 0x000C, 0x0000, 0x0000, 0x0000, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x0000, 0x2122, 0x0000, 0x203A, 0x0000, 0x0000, 0x0000, 0x0000, + 0x00A0, 0x0385, 0x0386, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x0000, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x2015, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x00B5, 0x00B6, 0x00B7, + 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F, + 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, + 0x03A0, 0x03A1, 0x0000, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, + 0x03A8, 0x03A9, 0x03AA, 0x03AD, 0x03AC, 0x03AD, 0x03AE, 0x03AF, + 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, + 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, + 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, + 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x0000 +}; + +#elif _CODE_PAGE == 1254 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP1254(0x80-0xFF) to Unicode conversion table */ + 0x20AC, 0x0000, 0x210A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x0000, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00BD, 0x00DC, 0x0130, 0x015E, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF +}; + +#elif _CODE_PAGE == 1255 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP1255(0x80-0xFF) to Unicode conversion table */ + 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0000, 0x2039, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0000, 0x203A, 0x0000, 0x0000, 0x0000, 0x0000, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, + 0x05B8, 0x05B9, 0x0000, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF, + 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05F0, 0x05F1, 0x05F2, 0x05F3, + 0x05F4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, + 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, + 0x05E8, 0x05E9, 0x05EA, 0x0000, 0x0000, 0x200E, 0x200F, 0x0000 +}; + +#elif _CODE_PAGE == 1256 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP1256(0x80-0xFF) to Unicode conversion table */ + 0x20AC, 0x067E, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688, + 0x06AF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x06A9, 0x2122, 0x0691, 0x203A, 0x0153, 0x200C, 0x200D, 0x06BA, + 0x00A0, 0x060C, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x06BE, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x061B, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x061F, + 0x06C1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, + 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7, + 0x0637, 0x0638, 0x0639, 0x063A, 0x0640, 0x0640, 0x0642, 0x0643, + 0x00E0, 0x0644, 0x00E2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0649, 0x064A, 0x00EE, 0x00EF, + 0x064B, 0x064C, 0x064D, 0x064E, 0x00F4, 0x064F, 0x0650, 0x00F7, + 0x0651, 0x00F9, 0x0652, 0x00FB, 0x00FC, 0x200E, 0x200F, 0x06D2 +} + +#elif _CODE_PAGE == 1257 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP1257(0x80-0xFF) to Unicode conversion table */ + 0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021, + 0x0000, 0x2030, 0x0000, 0x2039, 0x0000, 0x00A8, 0x02C7, 0x00B8, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x0000, 0x2122, 0x0000, 0x203A, 0x0000, 0x00AF, 0x02DB, 0x0000, + 0x00A0, 0x0000, 0x00A2, 0x00A3, 0x00A4, 0x0000, 0x00A6, 0x00A7, + 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6, + 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, + 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B, + 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, + 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF, + 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, + 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C, + 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7, + 0x0173, 0x014E, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x02D9 +}; + +#elif _CODE_PAGE == 1258 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP1258(0x80-0xFF) to Unicode conversion table */ + 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0000, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0000, 0x203A, 0x0153, 0x0000, 0x0000, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x0300, 0x00CD, 0x00CE, 0x00CF, + 0x0110, 0x00D1, 0x0309, 0x00D3, 0x00D4, 0x01A0, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x01AF, 0x0303, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0301, 0x00ED, 0x00EE, 0x00EF, + 0x0111, 0x00F1, 0x0323, 0x00F3, 0x00F4, 0x01A1, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x01B0, 0x20AB, 0x00FF +}; + +#endif + + +#if !_TBLDEF || !_USE_LFN +#error This file is not needed in current configuration +#endif + + +WCHAR ff_convert ( /* Converted character, Returns zero on error */ + WCHAR src, /* Character code to be converted */ + UINT dir /* 0: Unicode to OEMCP, 1: OEMCP to Unicode */ +) +{ + WCHAR c; + + + if (src < 0x80) { /* ASCII */ + c = src; + + } else { + if (dir) { /* OEMCP to Unicode */ + c = (src >= 0x100) ? 0 : Tbl[src - 0x80]; + + } else { /* Unicode to OEMCP */ + for (c = 0; c < 0x80; c++) { + if (src == Tbl[c]) break; + } + c = (c + 0x80) & 0xFF; + } + } + + return c; +} + + +WCHAR ff_wtoupper ( /* Upper converted character */ + WCHAR chr /* Input character */ +) +{ + static const WCHAR tbl_lower[] = { 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0xA1, 0x00A2, 0x00A3, 0x00A5, 0x00AC, 0x00AF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0x0FF, 0x101, 0x103, 0x105, 0x107, 0x109, 0x10B, 0x10D, 0x10F, 0x111, 0x113, 0x115, 0x117, 0x119, 0x11B, 0x11D, 0x11F, 0x121, 0x123, 0x125, 0x127, 0x129, 0x12B, 0x12D, 0x12F, 0x131, 0x133, 0x135, 0x137, 0x13A, 0x13C, 0x13E, 0x140, 0x142, 0x144, 0x146, 0x148, 0x14B, 0x14D, 0x14F, 0x151, 0x153, 0x155, 0x157, 0x159, 0x15B, 0x15D, 0x15F, 0x161, 0x163, 0x165, 0x167, 0x169, 0x16B, 0x16D, 0x16F, 0x171, 0x173, 0x175, 0x177, 0x17A, 0x17C, 0x17E, 0x192, 0x3B1, 0x3B2, 0x3B3, 0x3B4, 0x3B5, 0x3B6, 0x3B7, 0x3B8, 0x3B9, 0x3BA, 0x3BB, 0x3BC, 0x3BD, 0x3BE, 0x3BF, 0x3C0, 0x3C1, 0x3C3, 0x3C4, 0x3C5, 0x3C6, 0x3C7, 0x3C8, 0x3C9, 0x3CA, 0x430, 0x431, 0x432, 0x433, 0x434, 0x435, 0x436, 0x437, 0x438, 0x439, 0x43A, 0x43B, 0x43C, 0x43D, 0x43E, 0x43F, 0x440, 0x441, 0x442, 0x443, 0x444, 0x445, 0x446, 0x447, 0x448, 0x449, 0x44A, 0x44B, 0x44C, 0x44D, 0x44E, 0x44F, 0x451, 0x452, 0x453, 0x454, 0x455, 0x456, 0x457, 0x458, 0x459, 0x45A, 0x45B, 0x45C, 0x45E, 0x45F, 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F, 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0 }; + static const WCHAR tbl_upper[] = { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x21, 0xFFE0, 0xFFE1, 0xFFE5, 0xFFE2, 0xFFE3, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0x178, 0x100, 0x102, 0x104, 0x106, 0x108, 0x10A, 0x10C, 0x10E, 0x110, 0x112, 0x114, 0x116, 0x118, 0x11A, 0x11C, 0x11E, 0x120, 0x122, 0x124, 0x126, 0x128, 0x12A, 0x12C, 0x12E, 0x130, 0x132, 0x134, 0x136, 0x139, 0x13B, 0x13D, 0x13F, 0x141, 0x143, 0x145, 0x147, 0x14A, 0x14C, 0x14E, 0x150, 0x152, 0x154, 0x156, 0x158, 0x15A, 0x15C, 0x15E, 0x160, 0x162, 0x164, 0x166, 0x168, 0x16A, 0x16C, 0x16E, 0x170, 0x172, 0x174, 0x176, 0x179, 0x17B, 0x17D, 0x191, 0x391, 0x392, 0x393, 0x394, 0x395, 0x396, 0x397, 0x398, 0x399, 0x39A, 0x39B, 0x39C, 0x39D, 0x39E, 0x39F, 0x3A0, 0x3A1, 0x3A3, 0x3A4, 0x3A5, 0x3A6, 0x3A7, 0x3A8, 0x3A9, 0x3AA, 0x410, 0x411, 0x412, 0x413, 0x414, 0x415, 0x416, 0x417, 0x418, 0x419, 0x41A, 0x41B, 0x41C, 0x41D, 0x41E, 0x41F, 0x420, 0x421, 0x422, 0x423, 0x424, 0x425, 0x426, 0x427, 0x428, 0x429, 0x42A, 0x42B, 0x42C, 0x42D, 0x42E, 0x42F, 0x401, 0x402, 0x403, 0x404, 0x405, 0x406, 0x407, 0x408, 0x409, 0x40A, 0x40B, 0x40C, 0x40E, 0x40F, 0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x216A, 0x216B, 0x216C, 0x216D, 0x216E, 0x216F, 0xFF21, 0xFF22, 0xFF23, 0xFF24, 0xFF25, 0xFF26, 0xFF27, 0xFF28, 0xFF29, 0xFF2A, 0xFF2B, 0xFF2C, 0xFF2D, 0xFF2E, 0xFF2F, 0xFF30, 0xFF31, 0xFF32, 0xFF33, 0xFF34, 0xFF35, 0xFF36, 0xFF37, 0xFF38, 0xFF39, 0xFF3A, 0 }; + int i; + + + for (i = 0; tbl_lower[i] && chr != tbl_lower[i]; i++) ; + + return tbl_lower[i] ? tbl_upper[i] : chr; +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flash/flash.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,112 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#include "sowb.h" +#include "debug.h" +#include "ssp0.h" +#include "gpio.h" +#include "flash.h" +#include "user.h" + +extern bool sector_erase_in_progress; +extern bool page_write_in_progress; + +char flash_buffer[2][FLASH_PAGE_SIZE]; +int current_buffer; +unsigned int flash_address; + +/** flash_init + */ +void flash_init(void) { + + /* Initialise the SSP0 to talk to the flash device. */ + SSP0_init(); + + DEBUG_INIT_START; + + /* Clear out the page buffers. */ + memset(flash_buffer, 0, 2 * FLASH_PAGE_SIZE); + + /* Default the buffer in use. */ + current_buffer = 0; + + /* Default pointer set-up. */ + flash_address = 0; + + /* Prime our buffers for expected future access. */ + flash_read_page(0, flash_buffer[0], true); + flash_read_page(1, flash_buffer[1], true); + + /* Although not part of the flash system, SOWB includes + a 25AA02E48 device from Microchip that holds a globally + unique 48bit (6byte) MAC address. We use this for the + SOWB "STL authentic product" serial number and in future + may be used as the ethernet MAC address if we ever write + code to support Ethernet. This device is also connected + to SSP1 and so we'll _init() it here now. */ + //_25AA02E48_init(); + + DEBUG_INIT_END; +} + +/** flash_process + */ +void flash_process(void) { + /* Currently does nothing. */ +} + +/** flash_getc + */ +char flash_getc(bool peek) { + char c; + + /* Flash being deleted, undefined memory. */ + if (sector_erase_in_progress) return 0xFF; + + /* Wait for any page loads to complete. */ + while (page_write_in_progress) user_call_process(); + + /* Get the character from the internal buffer. */ + c = flash_buffer[current_buffer][flash_address]; + + /* If this is just a peek then return the character without + incrementing the memory pointers etc etc. */ + if (peek) return c; + + /* Inc the address pointer and load a new page if needed. Note, + we load the page in background using DMA. */ + flash_address++; + if ((flash_address & 0xFF) == 0) { + flash_read_page(current_buffer >> 8, flash_buffer[current_buffer], false); + current_buffer = current_buffer ? 0 : 1; + } + + return c; +} + +/** flash_seek + */ +void flash_seek(unsigned int addr) { + flash_read_page((addr >> 8) + 0, flash_buffer[0], true); + flash_read_page((addr >> 8) + 1, flash_buffer[1], true); + flash_address = addr; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flash/flash.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,113 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef FLASH_H +#define FLASH_H + +#define FLASH_PAGE_SIZE 256 + +#define FLASH_WIP_TEST_TIME 2 + +#define FLASH_WREN 0x06 +#define FLASH_WRDI 0x04 +#define FLASH_RDID 0x9F +#define FLASH_RDSR 0x05 +#define FLASH_WRSR 0x01 +#define FLASH_READ 0x03 +#define FLASH_FAST_READ 0x0B +#define FLASH_PP 0x02 +#define FLASH_SE 0xD8 +#define FLASH_BE 0xC7 + +#define DMA_CHANNEL_ENABLE 1 +//#define DMA_CHANNEL_SRC_PERIPHERAL_SSP1_RX (3UL << 1) +//#define DMA_CHANNEL_SRC_PERIPHERAL_SSP1_TX (2UL << 1) +//#define DMA_CHANNEL_DST_PERIPHERAL_SSP1_RX (3UL << 6) +//#define DMA_CHANNEL_DST_PERIPHERAL_SSP1_TX (2UL << 6) +#define DMA_CHANNEL_SRC_PERIPHERAL_SSP0_RX (1UL << 1) +#define DMA_CHANNEL_SRC_PERIPHERAL_SSP0_TX (0UL << 1) +#define DMA_CHANNEL_DST_PERIPHERAL_SSP0_RX (1UL << 6) +#define DMA_CHANNEL_DST_PERIPHERAL_SSP0_TX (0UL << 6) +#define DMA_CHANNEL_SRC_INC (1UL << 26) +#define DMA_CHANNEL_DST_INC (1UL << 27) +#define DMA_CHANNEL_TCIE (1UL << 31) +#define DMA_TRANSFER_TYPE_M2M (0UL << 11) +#define DMA_TRANSFER_TYPE_M2P (1UL << 11) +#define DMA_TRANSFER_TYPE_P2M (2UL << 11) +#define DMA_TRANSFER_TYPE_P2P (3UL << 11) +#define DMA_MASK_IE (1UL << 14) +#define DMA_MASK_ITC (1UL << 15) +#define DMA_LOCK (1UL << 16) +#define DMA_ACTIVE (1UL << 17) +#define DMA_HALT (1UL << 18) + +#define FLASH_SHORT_COMMAND(x) \ + SSP0_WRITE_BYTE(x); \ + while(SSP0_IS_BUSY); \ + SSP0_FLUSH_RX_FIFO; + +#define FLASH_LONG_COMMAND(x,y) \ + SSP0_WRITE_BYTE(x); \ + SSP0_WRITE_BYTE((y >> 8) & (0xFF)); \ + SSP0_WRITE_BYTE(y & 0xFF); \ + SSP0_WRITE_BYTE(0); \ + while(SSP0_IS_BUSY); \ + SSP0_FLUSH_RX_FIFO; + +#define FLASH_WAIT_WHILE_WIP \ + SSP0_CS_ASSERT; \ + FLASH_SHORT_COMMAND(FLASH_RDSR); \ + SSP0_FLUSH_RX_FIFO; \ + do { \ + SSP0_WRITE_BYTE(0); \ + } \ + while (LPC_SSP0->DR & 0x1); \ + SSP0_CS_DEASSERT; + + +/* Defined in flash.c */ +void flash_init(void); +void flash_process(void); +char flash_getc(bool peek); +void flash_seek(unsigned int addr); + +/* Defined in flash_read.c */ +bool flash_read_in_progress(void); +void flash_read_page(unsigned int page_address, char *buffer, bool block); + +/* Defined in flash_write.c */ +int flash_erase_sector(int sector); +bool flash_write_in_progress(void); +bool flash_sector_erase_in_progress(void); +int flash_page_write(int page, char *buffer); + +/* Defined in flash_erase.c */ +bool flash_sector_erase_in_progress(void); +int flash_erase_sector(int sector); +int flash_erase_bulk(void); + +/* Defined in 25AA02E44.c */ +void _25AA02E48_init(void); +void _25AA02E48_mac_addr(char *); +void _25AA02E48_mac_addr_printable(char *, char); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flash/flash_erase.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,141 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#include "sowb.h" +#include "flash.h" +#include "ssp0.h" +#include "dma.h" +#include "gpio.h" +#include "rit.h" +#include "user.h" +#include "utils.h" +#include "debug.h" + +/* Flags to show what state we are in. */ +bool sector_erase_in_progress = false; +extern bool page_write_in_progress; + +bool flash_sector_erase_in_progress(void) { + return sector_erase_in_progress; +} + +/** flash_erase_sector + */ +int flash_erase_sector(int sector) { + + /* If a sector erase is in progress already + we return zero rather than wait (block) + because an erase can take so long to complete + we don't want to hang around waiting. Let the + caller reschedule it sometime later. */ + if (sector_erase_in_progress) { + return 0; + } + + /* Request use of SSP0. */ + while(!SSP0_request()) WHILE_WAITING_DO_PROCESS_FUNCTIONS; + + sector_erase_in_progress = true; + + FLASH_CS_ASSERT; + FLASH_SHORT_COMMAND(FLASH_WREN); + FLASH_CS_DEASSERT; + + SSP0_FLUSH_RX_FIFO; + + /* Wait until the flash device has the WEL bit on. */ + while ((LPC_SSP0->DR & 0x2) == 0) { + FLASH_CS_ASSERT; + FLASH_SHORT_COMMAND(FLASH_RDSR); + SSP0_FLUSH_RX_FIFO; + SSP0_WRITE_BYTE(0); + while (SSP0_IS_BUSY); + FLASH_CS_DEASSERT; + } + + SSP0_FLUSH_RX_FIFO; + + FLASH_CS_ASSERT; + FLASH_LONG_COMMAND(FLASH_SE, sector); + FLASH_CS_DEASSERT; + + /* Note, a sector erase takes much longer than + a page write (typical 600ms by the datasheet) + so there's no point making the first timeout + very short and producing a lot of uneeded + interrupts. So we set the first timeout to + be 600 and then it'll switch to a much shorter + time in the ISR. */ + rit_timer_set_counter(FLASH_WRITE_CB, 600); + return 1; +} + +/** flash_erase_bulk + */ +int flash_erase_bulk(void) { + + /* If a sector erase is in progress already + we return zero rather than wait (block) + because an erase can take so long to complete + we don't want to hang around waiting. Let the + caller reschedule it sometime later. */ + + if (sector_erase_in_progress || page_write_in_progress) { + return 0; + } + + /* Request use of SSP0. */ + while(!SSP0_request()) WHILE_WAITING_DO_PROCESS_FUNCTIONS; + + sector_erase_in_progress = true; + + FLASH_CS_ASSERT; + FLASH_SHORT_COMMAND(FLASH_WREN); + FLASH_CS_DEASSERT; + + SSP0_FLUSH_RX_FIFO; + + /* Wait until the flash device has the WEL bit on. */ + while ((LPC_SSP0->DR & 0x2) == 0) { + FLASH_CS_ASSERT; + FLASH_SHORT_COMMAND(FLASH_RDSR); + SSP0_FLUSH_RX_FIFO; + SSP0_WRITE_BYTE(0); + while (SSP0_IS_BUSY); + FLASH_CS_DEASSERT; + } + + FLASH_CS_ASSERT; + FLASH_SHORT_COMMAND(FLASH_BE); + FLASH_CS_DEASSERT; + + /* Note, a bulk erase takes much longer than + a page write (typical 8s by the datasheet) + so there's no point making the first timeout + very short and producing a lot of uneeded + interrupts. So we set the first timeout to + be 8000 and then it'll switch to a much shorter + time in the ISR. */ + rit_timer_set_counter(FLASH_WRITE_CB, 8000); + return 1; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flash/flash_read.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,177 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#include "sowb.h" +#include "flash.h" +#include "dma.h" +#include "ssp0.h" +#include "gpio.h" +#include "user.h" +#include "debug.h" + +bool page_read_in_progress = false; + +/* Local function prototypes. */ +static int _flash_read_page(unsigned int page_address, char *buffer); + +void flash_read_page(unsigned int page_address, char *buffer, bool block) { + _flash_read_page(page_address, buffer); + + if (block) { + while(page_read_in_progress) { + WHILE_WAITING_DO_PROCESS_FUNCTIONS; + } + } +} + +/** flash_read_in_progress + */ +bool flash_read_in_progress(void) { + return page_read_in_progress; +} + +/** flash_read_page + * + * Load the given flash page into the supplied buffer. + * + * @param unsigned int the page to load, between 0 and 4095 + * @param char * buffer The RAM buffer to load the page to. + */ +static int _flash_read_page(unsigned int page_address, char *buffer) { + + /* We can't read a page while a write or erase is in progress. */ + if (flash_write_in_progress() || flash_sector_erase_in_progress()) { + return 0; + } + + /* Wait for any previous read operation to complete. */ + while (page_read_in_progress) WHILE_WAITING_DO_PROCESS_FUNCTIONS; + + /* Mark a read is in operation. */ + page_read_in_progress = true; + + /* Request use of SSP0. */ + while(!SSP0_request()) WHILE_WAITING_DO_PROCESS_FUNCTIONS; + + /* Ensure the SSP1 RX FIFO is empty. */ + SSP0_FLUSH_RX_FIFO; + + /* Send the command and page read to the flash device. */ + FLASH_CS_ASSERT; + FLASH_LONG_COMMAND(FLASH_READ, page_address); + + /* We use two DMA channels to achieve the required results. + The higher priority channel0 is used to drive the SSP0 + SCLK0 pin with "don't care" bytes. We do this to flush + the bytes out of the flash device. We then use Channel1 + to transfer the incoming bytes to RAM. */ + + while(!DMA_request_channel(0)) WHILE_WAITING_DO_PROCESS_FUNCTIONS; + while(!DMA_request_channel(1)) WHILE_WAITING_DO_PROCESS_FUNCTIONS; + + LPC_GPDMA->DMACIntTCClear = 0x3; + LPC_GPDMA->DMACSoftSReq = 0xC; + + /* Prep Channel1 to receive the incoming byte stream. */ + LPC_GPDMACH1->DMACCSrcAddr = (uint32_t)&LPC_SSP0->DR; + LPC_GPDMACH1->DMACCDestAddr = (uint32_t)buffer; + LPC_GPDMACH1->DMACCLLI = 0; + LPC_GPDMACH1->DMACCControl = DMA_CHANNEL_TCIE | DMA_CHANNEL_DST_INC | (uint32_t)FLASH_PAGE_SIZE; + + /* Prep Channel0 to send "don't care" bytes in order to clock out the data from the flash device. */ + LPC_GPDMACH0->DMACCSrcAddr = (uint32_t)buffer; /* don't care data. */ + LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP0->DR; + LPC_GPDMACH0->DMACCLLI = 0; + LPC_GPDMACH0->DMACCControl = DMA_CHANNEL_TCIE | (uint32_t)FLASH_PAGE_SIZE; + + /* Enable SSP0 DMA. */ + LPC_SSP0->DMACR = 0x3; + + /* Enable Channel0 */ + LPC_GPDMACH0->DMACCConfig = DMA_CHANNEL_ENABLE | + DMA_CHANNEL_DST_PERIPHERAL_SSP0_TX | + DMA_TRANSFER_TYPE_M2P | + DMA_MASK_IE | + DMA_MASK_ITC; + + /* Wait until at least one byte has arrived into the RX FIFO + and then start-up the Channel1 DMA to begin transferring them. */ + while((LPC_SSP0->SR & (1UL << 2)) == 0); + + /* Enable Channel1 */ + LPC_GPDMACH1->DMACCConfig = DMA_CHANNEL_ENABLE | + DMA_CHANNEL_SRC_PERIPHERAL_SSP0_RX | + DMA_TRANSFER_TYPE_P2M | + DMA_MASK_IE | + DMA_MASK_ITC; + + /* SSP0 CS line and "page_read_in_progress" flag are now + under DMA/SSP0 interrupt control. See the DMA ISR handlers + and SSP0 ISR handlers for more information. */ + + return 1; +} + +/** flash_read_ssp0_irq + * + * Called by the SSP0 ISR handler. + */ +int flash_read_ssp0_irq(void) { + if (page_read_in_progress) { + if (LPC_SSP0->MIS & (1UL << 3)) { + LPC_SSP0->IMSC &= ~(1UL << 3); + while(SSP0_IS_BUSY); + FLASH_CS_DEASSERT; + SSP0_release(); + page_read_in_progress = false; + return 1; + } + } + return 0; +} + +/* The following two functions are the DMA ISR handlers. They are + called from dma.c so see that module for more details. */ + +/** flash_read_dma0_irq + */ +int flash_read_dma0_irq(int channel_number) { + if (page_read_in_progress) { + LPC_GPDMACH0->DMACCConfig = 0; + DMA_release_channel(0); + return 1; + } + return 0; +} + +/** flash_read_dma1_irq + */ +int flash_read_dma1_irq(int channel_number) { + if (page_read_in_progress) { + LPC_GPDMACH1->DMACCConfig = 0; + DMA_release_channel(1); + LPC_SSP0->IMSC = (1UL << 3); + return 1; + } + return 0; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flash/flash_write.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,224 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#include "sowb.h" +#include "flash.h" +#include "ssp0.h" +#include "dma.h" +#include "gpio.h" +#include "rit.h" +#include "user.h" +#include "utils.h" +#include "debug.h" + +/* Flags to show what state we are in. */ +bool page_write_in_progress = false; +bool page_write_buffer_in_use = false; + +/* Flag used by the flash_erase.c file. */ +extern bool sector_erase_in_progress; + +/* Buffer used to hold a copy of the page to write. Used + to ensure the DMA has a valid buffer to copy. */ +char flash_page_write_buffer[FLASH_PAGE_SIZE]; + +/** flash_write_in_progress + */ +bool flash_write_in_progress(void) { + return page_write_in_progress; +} + +/** flash_page_write + */ +int flash_page_write(int page, char *buffer) { + + /* Wait for the write page buffer to be released by + the DMA ISR handler, if in use, then make a copy + of the source buffer for the DMA. */ + while (page_write_buffer_in_use) WHILE_WAITING_DO_PROCESS_FUNCTIONS; + memcpy(flash_page_write_buffer, buffer, FLASH_PAGE_SIZE); + page_write_buffer_in_use = true; + + + /* Below this we check for conditions that should stall + us before continuing. However, sector erase is different, + it can take quite some time to complete. If this is the + case, rather than block (wait), we'll return zero (not + done) and allow the caller to schedule a write later. */ + if (sector_erase_in_progress) return 0; + + /* Do not start a page write while another page write + is in progress. This flag is released by the RIT + timer callback when the WIP flag shows a previous + write has completed. */ + while(page_write_in_progress) WHILE_WAITING_DO_PROCESS_FUNCTIONS; + + /* Do not start a page write while a page read is in operation. */ + while (flash_read_in_progress()) WHILE_WAITING_DO_PROCESS_FUNCTIONS; + + /* Request DMA channel0. */ + while(!DMA_request_channel(0)) WHILE_WAITING_DO_PROCESS_FUNCTIONS; + + /* Request the use of SSP0. */ + while(!SSP0_request()) WHILE_WAITING_DO_PROCESS_FUNCTIONS; + + /* Flag a write is in progress. */ + page_write_in_progress = true; + + /* Switch on WIP/WEL. */ + FLASH_CS_ASSERT; + FLASH_SHORT_COMMAND(FLASH_WREN); + FLASH_CS_DEASSERT; + + /* Originally I dropped into a do { ... } while(); here but + found the time between the CS deassert and reassert inside + the loop was *very* short and the flash device wasn't to + keen on this. So, I switched to a "flush rx fifo" and the + use a while() { ... } loop, just puts some delay between + the CS manipulation. */ + SSP0_FLUSH_RX_FIFO; + + /* Wait until the flash device has the WEL bit on. */ + while ((LPC_SSP0->DR & 0x2) == 0) { + FLASH_CS_ASSERT; + FLASH_SHORT_COMMAND(FLASH_RDSR); + SSP0_FLUSH_RX_FIFO; + SSP0_WRITE_BYTE(0); + while (SSP0_IS_BUSY); + FLASH_CS_DEASSERT; + } + + FLASH_CS_ASSERT; + FLASH_LONG_COMMAND(FLASH_PP, page); + + LPC_GPDMA->DMACIntTCClear = 0x1; + LPC_GPDMA->DMACSoftSReq = 0xC; + + /* Prep Channel0 to send the buffer to the flash device. */ + LPC_GPDMACH0->DMACCSrcAddr = (uint32_t)flash_page_write_buffer; + LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP0->DR; + LPC_GPDMACH0->DMACCLLI = 0; + LPC_GPDMACH0->DMACCControl = DMA_CHANNEL_TCIE | DMA_CHANNEL_SRC_INC | (uint32_t)FLASH_PAGE_SIZE; + + /* Enable SSP0 DMA. */ + LPC_SSP0->DMACR = 0x2; + + /* Enable Channel0 */ + LPC_GPDMACH0->DMACCConfig = DMA_CHANNEL_ENABLE | + DMA_CHANNEL_DST_PERIPHERAL_SSP0_TX | + DMA_TRANSFER_TYPE_M2P | + DMA_MASK_IE | + DMA_MASK_ITC; + + + /* SSP0 CS line and "page_write_in_progress" flag are now + under DMA/SSP0 interrupt control. See ISR handlers for + more information. */ + + return 1; +} + +/** _flash_write_timer_callback + * + * RIT timer callback. + * + * After the write operation is complete this callback + * is used to examine the WIP flag in the flash status + * register. If it's still set then we reset the timer + * and try again in the future. If it's clear then we + * can mark the process as complete. + * + * @param int index The index of the timer the RIT modulr used. + */ +void _flash_write_timer_callback(int index) { + uint32_t sr = 1; + + /* Read the WIP flag from the flash device status + register and if the write cycle is complete mark + the operation as complete. Otherwise, reset the + timer to test again in the future. */ + FLASH_CS_ASSERT; + FLASH_SHORT_COMMAND(FLASH_RDSR); + SSP0_WRITE_BYTE(0); + while (SSP0_IS_BUSY); + FLASH_CS_DEASSERT; + while(LPC_SSP0->SR & (1UL << 2)) { + /* This loop ensures we read the last byte in the + RX FIFO and test that. */ + sr = LPC_SSP0->DR; + } + if (sr & 0x1) { + if (sector_erase_in_progress) rit_timer_set_counter(index, 100); + else rit_timer_set_counter(index, FLASH_WIP_TEST_TIME); + } + else { + FLASH_CS_ASSERT; + FLASH_SHORT_COMMAND(FLASH_WRDI); + SSP0_FLUSH_RX_FIFO; + FLASH_CS_DEASSERT; + if (sector_erase_in_progress) sector_erase_in_progress = false; + if (page_write_in_progress) page_write_in_progress = false; + SSP0_release(); + } +} + +/** flash_write_dma0_irq + * + * DMA transfer irq callback. + */ +int flash_write_dma0_irq(int channel) { + int rval = 0; + + /* If we were using DMA to transfer our buffer to the flash + device then mark the buffer as "released" and no longer + in use, release the DMA channel and start the "detect WIP + indicates complete" timer. */ + if (page_write_buffer_in_use) { + page_write_buffer_in_use = false; + LPC_GPDMACH0->DMACCConfig = 0; + DMA_release_channel(0); + LPC_SSP0->IMSC = (1UL << 3); + rit_timer_set_counter(FLASH_WRITE_CB, FLASH_WIP_TEST_TIME); + rval = 1; + } + + return rval; +} + +/** flash_read_ssp0_irq + * + * Called by the SSP0 ISR handler. + */ +int flash_write_ssp0_irq(void) { + if (page_write_in_progress) { + if (LPC_SSP0->MIS & (1UL << 3)) { + LPC_SSP0->IMSC &= ~(1UL << 3); + while(SSP0_IS_BUSY); + FLASH_CS_DEASSERT; + SSP0_release(); + return 1; + } + } + return 0; +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flash/ssp0.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,124 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#include "sowb.h" +#include "debug.h" +#include "ssp0.h" + +bool ssp0_in_use; + +bool SSP0_request(void) { + if (!ssp0_in_use) { + ssp0_in_use = true; + return true; + } + return false; +} + +void SSP0_release(void) { + ssp0_in_use = false; +} + +/* Declare ISR callbacks. */ +extern int flash_read_ssp0_irq(void); +extern int flash_write_ssp0_irq(void); + +/* Function pointer type for the following table. */ +typedef int (*SSP0_callback)(void); + +/* Define an array of callbacks to make. */ +const SSP0_callback ssp0_callbacks[] = { + flash_read_ssp0_irq, + flash_write_ssp0_irq, + NULL +}; + +/** SSP0_IRQHandler + */ +extern "C" void SSP0_IRQHandler(void) __irq { + for (int i = 0; ssp0_callbacks[i] != NULL; i++) { + if ((ssp0_callbacks[i])() != 0) { + break; + } + } +} + +/** SSP0_init + */ +void SSP0_init(void) { + + DEBUG_INIT_START; + + ssp0_in_use = false; + + /* The flash device is connected to SSP1 via the Mbed pins. + So this init is about configuring just the SSP1. */ + + /* Enable the SSP1 peripheral. */ + //LPC_SC->PCONP |= (1UL << 10); + LPC_SC->PCONP |= (1UL << 21); + + /* Select the clock required for SSP1. */ + LPC_SC->PCLKSEL1 &= ~(3UL << 10); + LPC_SC->PCLKSEL1 |= (3UL << 10); + //LPC_SC->PCLKSEL0 &= ~(3UL << 20); + //LPC_SC->PCLKSEL0 |= (3UL << 20); + + /* Select the GPIO pins for the SSP0 functions. */ + /* SCK0 */ + LPC_PINCON->PINSEL0 &= ~(3UL << 30); + LPC_PINCON->PINSEL0 |= (2UL << 30); + /* MISO0 */ + LPC_PINCON->PINSEL1 &= ~(3UL << 2); + LPC_PINCON->PINSEL1 |= (2UL << 2); + /* MISI0 */ + LPC_PINCON->PINSEL1 &= ~(3UL << 4); + LPC_PINCON->PINSEL1 |= (2UL << 4); + + /* Select the GPIO pins for the SSP1 functions. */ + /* SCK1 */ + //LPC_PINCON->PINSEL0 &= ~(3UL << 14); + //LPC_PINCON->PINSEL0 |= (2UL << 14); + /* MISO1 */ + //LPC_PINCON->PINSEL0 &= ~(3UL << 16); + //LPC_PINCON->PINSEL0 |= (2UL << 16); + /* MOSI1 */ + //LPC_PINCON->PINSEL0 &= ~(3UL << 18); + //LPC_PINCON->PINSEL0 |= (2UL << 18); + + /* Note, we don't use SSEL1 in our design, we just use a standard GPIO + because writing multi-byte data is simpler. */ + + /* Setup the interrupt system. Note however, the SSP1 interrupt + is only actually activated within the DMA ISR and is self disabling. */ + NVIC_SetVector(SSP0_IRQn, (uint32_t)SSP0_IRQHandler); + NVIC_EnableIRQ(SSP0_IRQn); + + /* Setup the control registers for SSP1 */ + LPC_SSP0->IMSC = 0; + LPC_SSP0->CR0 = 0x7; + LPC_SSP0->CPSR = FLASH_SSP_INIT_CPSR; + LPC_SSP0->CR1 = 0x2; + + DEBUG_INIT_END; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flash/ssp0.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,53 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef SSP0_H +#define SSP0_H + +#define FLASH_SSP_INIT_CPSR 2 +#define _25AA02E48_SSP_INIT_CPSR 0x64 + + +#define SSP0_TX_FIFO_SPACE_AVAILABLE \ + LPC_SSP0->SR & (1UL << 1) + +#define SSP0_TX_FIFO_NOT_EMPTY \ + (!(SSP0_TX_FIFO_SPACE_AVAILABLE)) + +#define SSP0_IS_BUSY \ + LPC_SSP0->SR & (1UL << 4) + +#define SSP0_FLUSH_RX_FIFO \ + while(LPC_SSP0->SR & (1UL << 2)) { \ + unsigned int dev_null = LPC_SSP0->DR; \ + } + +#define SSP0_WRITE_BYTE(byte) \ + while(!SSP0_TX_FIFO_SPACE_AVAILABLE); \ + LPC_SSP0->DR=(uint32_t)(byte&0xFF) + + +void SSP0_init(void); +bool SSP0_request(void); +void SSP0_release(void); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gpio/gpio.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,115 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + + #include "sowb.h" + #include "debug.h" + #include "gpio.h" + + + /** gpio_init + */ + void gpio_init(void) { + + DEBUG_INIT_START; + + /* The following code could be condensed into a single set of + and/or statements. However, for code clarity they are laid + out on a "use case" way to see each pin being defined. Since + this is "init" code and only called once at start-up, the + extra overhead isn't worth the effort over cleaner to read + code. */ + + /* The MAX7456 module uses p0.23 (p15) for it's chip select + output. Define it's setup here and use the macros in gpio.h + to assert, deassert or read the pin. */ + //LPC_PINCON->PINSEL1 &= ~(3UL << 14); /* Function GPIO. */ + //LPC_GPIO0->FIODIR |= (1UL << 23); /* P0.23 as output. */ + + /* The MAX7456 module uses p0.16 (p14) for it's chip select + output. Define it's setup here and use the macros in gpio.h + to assert, deassert or read the pin. */ + //LPC_PINCON->PINSEL1 &= ~(3UL << 14); /* Function GPIO. */ + //LPC_GPIO0->FIODIR |= (1UL << 16); /* P0.23 as output. */ + + /* The MAX7456 module uses p0.6 (p8) for it's chip select + output. Define it's setup here and use the macros in gpio.h + to assert, deassert or read the pin. */ + LPC_PINCON->PINSEL0 &= ~(3UL << 12); /* Function GPIO. */ + LPC_GPIO0->FIODIR |= (1UL << 6); /* P0.6 as output. */ + + + /* The MAX7456 module uses p1.31 (p20) for it's reset output. + Define it's setup here and use the macros in gpio.h to assert, + deassert or read the pin. */ + LPC_PINCON->PINSEL3 &= ~(3UL << 30); /* Function GPIO. */ + LPC_GPIO1->FIODIR |= (1UL << 31); /* P1.31 as output. */ + + /* We use p0.25 (p17) for the SD Card detect. */ + LPC_PINCON->PINSEL1 &= ~(3UL << 18); /* Function GPIO. */ + LPC_GPIO0->FIODIR &= ~(1UL << 25); /* P0.25 as Input. */ + + /* We use p0.16 (p14) for the Flash device SSP0 CS signal. */ + LPC_PINCON->PINSEL1 &= ~(3UL << 14); /* Function GPIO. */ + LPC_GPIO0->FIODIR |= (1UL << 16); /* P0.23 as output. */ + + /* We use p0.24 (p16) for the 25AA02E48 device SSP0 CS signal. */ + LPC_PINCON->PINSEL1 &= ~(3UL << 14); /* Function GPIO. */ + LPC_GPIO0->FIODIR |= (1UL << 24); /* P0.24 as output. */ + + /* We use p1.30 (p19) for the MicroSD card device SSP0 CS signal. */ + LPC_PINCON->PINSEL3 &= ~(3UL << 28); /* Function GPIO. */ + LPC_GPIO1->FIODIR |= (1UL << 30); /* P1.30 as output. */ + + /* We use p2.5 (p21) for debugging. */ + LPC_PINCON->PINSEL4 &= ~(3UL << 10); /* Function GPIO. */ + LPC_GPIO2->FIODIR |= (1UL << 5); /* P2.5 as output. */ + + /* We use p2.4 (p22) for debugging. */ + LPC_PINCON->PINSEL4 &= ~(3UL << 8); /* Function GPIO. */ + LPC_GPIO2->FIODIR |= (1UL << 4); /* P2.4 as output. */ + + +#ifdef MBED_LEDS + /* The MBED has four useful little blue LEDs that can be used. + Mbed examples use the DigitalOut led1(LED1) style. Mimic that + using our system here. Here however, I will use shorthand ;) + LED1 LED2 LED3 LED4 */ + LPC_PINCON->PINSEL3 &= ( ~(3UL << 4) & ~(3UL << 8) & ~(3UL << 10) & ~(3UL << 14) ); + LPC_GPIO1->FIODIR |= ( (1UL << 18) | (1UL << 20) | (1UL << 21) | (1UL << 23) ); +#endif + + + SSP0_CS_DEASSERT; + FLASH_CS_DEASSERT; + SDCARD_CS_DEASSERT; + AA02E48_CS_DEASSERT; + MAX7456_CS_DEASSERT; + + DEBUG_INIT_END; +} + +/** gpio_process + */ +void gpio_process(void) { + /* Does nothing, no house keeping required. */ +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gpio/gpio.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,135 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef GPIO_H +#define GPIO_H + +/* Switch on our macros to use the 4 LEDs on the Mbed. */ +#define MBED_LEDS + +/* Used by the MAX7456 module. + The MAX7456 !cs signal is connected to Mbed pin 8 + which is internally connected to Port0.6 */ +#define SET_P0_06 (LPC_GPIO0->FIOSET = (1UL << 6)) +#define CLR_P0_06 (LPC_GPIO0->FIOCLR = (1UL << 6)) +#define VAL_P0_06 (LPC_GPIO0->FIOPIN & (1UL << 6)) +#define MAX7456_CS_ASSERT CLR_P0_06 +#define MAX7456_CS_DEASSERT SET_P0_06 +#define MAX7456_CS_VALUE VAL_P0_06 +#define MAX7456_CS_TOGGLE MAX7456_CS_VALUE ? MAX7456_CS_DEASSERT : MAX7456_CS_ASSERT + +/* Used by the MAX7456 module. + The MAX7456 !rst signal is connected to Mbed pin 20 + which is internally connected to Port1.31 */ +#define SET_P1_31 (LPC_GPIO1->FIOSET = (1UL << 31)) +#define CLR_P1_31 (LPC_GPIO1->FIOCLR = (1UL << 31)) +#define VAL_P1_31 (LPC_GPIO1->FIOPIN & (1UL << 31)) +#define MAX7456_RST_ASSERT CLR_P1_31 +#define MAX7456_RST_DEASSERT SET_P1_31 +#define MAX7456_RST_VALUE VAL_P1_31 +#define MAX7456_RST_TOGGLE MAX7456_RST_VALUE ? MAX7456_RST_DEASSERT : MAX7456_RST_ASSERT +#define SSP0_CS_ASSERT CLR_P1_31 +#define SSP0_CS_DEASSERT SET_P1_31 +#define SSP0_CS_VALUE VAL_P1_31 +#define SSP0_CS_TOGGLE MAX7456_RST_VALUE ? MAX7456_RST_DEASSERT : MAX7456_RST_ASSERT + +/* Used by the flash module. + The flash !cs signal is connected to Mbed pin 14 + which is internally connected to Port0.16 */ +#define SET_P0_16 (LPC_GPIO0->FIOSET = (1UL << 16)) +#define CLR_P0_16 (LPC_GPIO0->FIOCLR = (1UL << 16)) +#define VAL_P0_16 (LPC_GPIO0->FIOPIN & (1UL << 16)) +#define FLASH_CS_ASSERT CLR_P0_16 +#define FLASH_CS_DEASSERT SET_P0_16 +#define FLASH_CS_VALUE VAL_P0_16 +#define FLASH_CS_TOGGLE FLASH_CS_VALUE ? FLASH_CS_DEASSERT : FLASH_CS_ASSERT + +/* Used by the 25AA02E48 module. + The device !cs signal is connected to Mbed pin 16 + which is internally connected to Port0.24 */ +#define SET_P0_24 (LPC_GPIO0->FIOSET = (1UL << 24)) +#define CLR_P0_24 (LPC_GPIO0->FIOCLR = (1UL << 24)) +#define VAL_P0_24 (LPC_GPIO0->FIOPIN & (1UL << 24)) +#define AA02E48_CS_ASSERT CLR_P0_24 +#define AA02E48_CS_DEASSERT SET_P0_24 +#define AA02E48_CS_VALUE VAL_P0_24 +#define AA02E48_CS_TOGGLE AA02E48_CS_VALUE ? AA02E48_CS_DEASSERT : AA02E48_CS_ASSERT + +/* Used by the SD card. + The device !cs signal is connected to Mbed pin 19 + which is internally connected to Port1.30 */ +#define SET_P1_30 (LPC_GPIO1->FIOSET = (1UL << 30)) +#define CLR_P1_30 (LPC_GPIO1->FIOCLR = (1UL << 30)) +#define VAL_P1_30 (LPC_GPIO1->FIOPIN & (1UL << 30)) +#define SDCARD_CS_ASSERT CLR_P1_30 +#define SDCARD_CS_DEASSERT SET_P1_30 +#define SDCARD_CS_VALUE VAL_P1_30 +#define SDCARD_CS_TOGGLE SDCARD_CS_VALUE ? SDCARD_CS_DEASSERT : SDCARD_CS_ASSERT + +/* Used for reading the SD Card detect pin. */ +#define SDCARD_DETECT (LPC_GPIO0->FIOPIN & (1UL << 25)) + +/* For debugging. + Mbed pin 21 which is internally connected to Port2.5 */ +#define SET_P2_05 (LPC_GPIO2->FIOSET = (1UL << 5)) +#define CLR_P2_05 (LPC_GPIO2->FIOCLR = (1UL << 5)) +#define VAL_P2_05 (LPC_GPIO2->FIOPIN & (1UL << 5)) +#define P21_ASSERT SET_P2_05 +#define P21_DEASSERT CLR_P2_05 +#define P21_VALUE VAL_P2_05 +#define P21_TOGGLE P21_VALUE ? P21_DEASSERT : P21_ASSERT + +/* For debugging. + Mbed pin 22 which is internally connected to Port2.4 */ +#define SET_P2_04 (LPC_GPIO2->FIOSET = (1UL << 4)) +#define CLR_P2_04 (LPC_GPIO2->FIOCLR = (1UL << 4)) +#define VAL_P2_04 (LPC_GPIO2->FIOPIN & (1UL << 4)) +#define P22_ASSERT SET_P2_04 +#define P22_DEASSERT CLR_P2_04 +#define P22_VALUE VAL_P2_04 +#define P22_TOGGLE P22_VALUE ? P22_DEASSERT : P22_ASSERT + +#ifdef MBED_LEDS +#define LED1_ON (LPC_GPIO1->FIOSET = (1UL << 18)) +#define LED1_OFF (LPC_GPIO1->FIOCLR = (1UL << 18)) +#define LED1_IS_ON (LPC_GPIO1->FIOPIN & (1UL << 18)) +#define LED1_TOGGLE LED1_IS_ON ? LED1_OFF : LED1_ON +#define LED2_ON (LPC_GPIO1->FIOSET = (1UL << 20)) +#define LED2_OFF (LPC_GPIO1->FIOCLR = (1UL << 20)) +#define LED2_IS_ON (LPC_GPIO1->FIOPIN & (1UL << 20)) +#define LED2_TOGGLE LED2_IS_ON ? LED2_OFF : LED2_ON +#define LED3_ON (LPC_GPIO1->FIOSET = (1UL << 21)) +#define LED3_OFF (LPC_GPIO1->FIOCLR = (1UL << 21)) +#define LED3_IS_ON (LPC_GPIO1->FIOPIN & (1UL << 21)) +#define LED3_TOGGLE LED3_IS_ON ? LED3_OFF : LED3_ON +#define LED4_ON (LPC_GPIO1->FIOSET = (1UL << 23)) +#define LED4_OFF (LPC_GPIO1->FIOCLR = (1UL << 23)) +#define LED4_IS_ON (LPC_GPIO1->FIOPIN & (1UL << 23)) +#define LED4_TOGGLE LED4_IS_ON ? LED4_OFF : LED4_ON +#endif + +/* Function prototypes. */ +void gpio_init(void); +void gpio_process(void); + +#endif + \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gpioirq/gpioirq.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,88 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#include "sowb.h" +#include "debug.h" +#include "gpioirq.h" + +/* Declare the external interrupt callback functions. */ +extern void MAX7456_vsync_rise(void); +extern void MAX7456_vsync_fall(void); +//extern void max7456_los_rise(void); +//extern void max7456_los_fall(void); +extern void gps_pps_rise(void); +extern void gps_pps_fall(void); + +/** EINT3_IRQHandler + */ +extern "C" void GPIOIRQ_IRQHandler (void) { + + /* Test for IRQ on Port0. */ + if (LPC_GPIOINT->IntStatus & 0x1) { + + /* GPS PPS is connected to MBED P29 (Port0.5) */ + //if (LPC_GPIOINT->IO0IntStatR & (1 << 5)) gps_pps_rise(); + + /* GPS PPS is connected to MBED P29 (Port0.5) */ + if (LPC_GPIOINT->IO0IntStatF & (1 << 5)) gps_pps_fall(); + + /* MAX7456 Vertical Sync is connected to MBED P15 (Port0.23) */ + if (LPC_GPIOINT->IO0IntStatF & (1 << 23)) MAX7456_vsync_fall(); + + /* MAX7456 LOS is connected to P17 (Port0.25) */ + //if (LPC_GPIOINT->IO0IntStatR & (1 << 25)) max7456_los_rise(); + + LPC_GPIOINT->IO0IntClr = (LPC_GPIOINT->IO0IntStatR | LPC_GPIOINT->IO0IntStatF); + } + + /* Test for IRQ on Port2. */ + if (LPC_GPIOINT->IntStatus & 0x4) { + + LPC_GPIOINT->IO2IntClr = (LPC_GPIOINT->IO2IntStatR | LPC_GPIOINT->IO2IntStatF); + } +} + +/** gpioirq_init + */ +void gpioirq_init(void) { + + DEBUG_INIT_START; + + /* Enable the interrupts for connected signals. + For bit definitions see the ISR function above. */ + LPC_GPIOINT->IO0IntEnR |= ( (1UL << 5) | (1UL << 25) | (1UL << 23) ); + LPC_GPIOINT->IO0IntEnF |= ( (1UL << 5) | (1UL << 25) | (1UL << 23) ); + //LPC_GPIOINT->IO2IntEnR |= ( (1UL << 5) ); + //LPC_GPIOINT->IO2IntEnF |= ( (1UL << 5) ); + + NVIC_SetVector(EINT3_IRQn, (uint32_t)GPIOIRQ_IRQHandler); + NVIC_EnableIRQ(EINT3_IRQn); + + DEBUG_INIT_END; +} + +void gpioirq_process(void) { + /* Does nothing, no periodic house keeping required. */ +} + + + \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gpioirq/gpioirq.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,30 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef GPIOIRQ_H +#define GPIOIRQ_H + +/* Function prototypes. */ +void gpioirq_init(void); +void gpioirq_process(void); + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gps/gps.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,670 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +/* + Implementation notes. + The SOWB reads GPS data in on RDX1. We don't use TDX1 as we use it as part + of the SSP/SPI for the MAX7456/Flash card reader. However, we are not really + interested in writing to the GPS module as the most crucial data is the time + rather than the location. We do use the location data but we don't need any + WAAS data correction, 10metres is enough accuracy. So we only use Uart1 Rx to + get data. + + Additionally, the GPS 1 pulse per second signal is connected to a P29 (P0.5) + and the gpioirq.c module routes that interrupt back to us via the _gps_pps_irq() + callback function. +*/ + +#include "sowb.h" +#include "rit.h" +#include "gpio.h" +#include "gps.h" +#include "math.h" +#include "debug.h" + +/* Module global variables. */ +double lat_average; +double lon_average; +double lat_history[GPS_HISTORY_SIZE]; +double lon_history[GPS_HISTORY_SIZE]; +int history_in_index; +int history_complete; +GPS_TIME the_time; +GPS_LOCATION_RAW the_location; + +double lat_acc_average; +double lon_acc_average; +double cnt_acc_average; + +/* We maintain two serial input buffers so that the + _process() function can be processing one buffer + while the serial interrupt system can be capturing + to the other. */ +char uart1_buffer[2][GPS_BUFFER_SIZE]; + +#define UART1_BUFFER_A 0 +#define UART1_BUFFER_B 1 + +char active_buffer, active_buffer_in; +char passive_buffer_ready; + +/* Update flag to signal new data in the active buffer. */ +char have_new_location; + +/* Set to non-zero by the updater interrupts. */ +char time_updated; +char location_updated; + +/* Internal function prototypes. */ +void _gps_process_rmc(char passive_buffer); +void _gps_process_gga(char passive_buffer); +void _gps_time_inc(GPS_TIME *q); +void _gps_date_inc(GPS_TIME *q); +void _gps_timer_tick_cb(int); +void _gps_pps_alive_cb(int); +void Uart1_init(void); + +/** gps_process + */ +void gps_process(void) { + int i, j; + uint32_t ier_copy; + char passive_buffer; + double lat_temp, lon_temp; + + if (passive_buffer_ready == 1) { + /* Disable serial interrupts on UART1 */ + ier_copy = LPC_UART1->IER; + LPC_UART1->IER = 0x0; + + /* What index is the passive buffer, i.e., what is the opposite + of the current active buffer? */ + passive_buffer = active_buffer == 0 ? 1 : 0; + + if (!strncmp(uart1_buffer[passive_buffer], "$GPRMC", 6)) { + _gps_process_rmc(passive_buffer); + } + else if (!strncmp(uart1_buffer[passive_buffer], "$GPGGA", 6)) { + _gps_process_gga(passive_buffer); + } + + /* Flag we have completed processing the passive buffer. */ + passive_buffer_ready = 0; + + /* Enable serial interrupts on UART1 */ + LPC_UART1->IER = ier_copy; + } + + /* Update the latitude/longitude moving average filter. */ + if (the_location.is_valid && have_new_location != 0) { + have_new_location = 0; + lat_history[history_in_index] = gps_convert_coord(the_location.lat, GPS_LAT_STR); + lon_history[history_in_index] = gps_convert_coord(the_location.lon, GPS_LON_STR); + history_in_index++; + if (history_in_index >= GPS_HISTORY_SIZE) { + history_in_index = 0; + history_complete = 1; + } + j = history_complete == 1 ? GPS_HISTORY_SIZE+1 : history_in_index; + for(lat_temp = lon_temp = 0., i = 1; i < j; i++) { + lat_temp += lat_history[i - 1]; + lon_temp += lon_history[i - 1]; + } + if (i) { + lat_average = lat_temp / (double)(i - 1); + lon_average = lon_temp / (double)(i - 1); + location_updated = 1; + } + } +} + +/** _gps_process_rmc + * + * Extract the NMEA data from an RMC packet. + * Sample:- + * $GPRMC,132555.639,A,5611.5374,N,00302.0325,W,000.0,129.3,020910,,,A*75 + * + * @param char passive_buffer Which buffer holds the RMC packet data. + */ +void _gps_process_rmc(char passive_buffer) { + char *token; + int token_counter = 0; + char *time = (char *)NULL; + char *date = (char *)NULL; + char *status = (char *)NULL; + + token = strtok(uart1_buffer[passive_buffer], ","); + while (token) { + switch (token_counter) { + case 9: date = token; break; + case 1: time = token; break; + case 2: status = token; break; + } + token = strtok((char *)NULL, ","); + token_counter++; + } + + if (status && date && time) { + the_time.hour = (char)((time[0] - '0') * 10) + (time[1] - '0'); + the_time.minute = (char)((time[2] - '0') * 10) + (time[3] - '0'); + the_time.second = (char)((time[4] - '0') * 10) + (time[5] - '0'); + the_time.day = (char)((date[0] - '0') * 10) + (date[1] - '0'); + the_time.month = (char)((date[2] - '0') * 10) + (date[3] - '0'); + the_time.year = (int)((date[4] - '0') * 10) + (date[5] - '0') + 2000; + the_time.is_valid = status[0] == 'A' ? 1 : 0; + the_time.prev_valid = 1; + } + else { + the_time.is_valid = 0; + } +} + +/** _gps_process_gga + * + * Extract the NMEA data from a GGA packet. + * Sample:- + * $GPGGA,132526.639,5611.5417,N,00302.0298,W,1,05,7.3,43.4,M,52.0,M,,0000*70 + * + * @param char passive_buffer Which buffer holds the GGA packet data. + */ +void _gps_process_gga(char passive_buffer) { + char *token; + int token_counter = 0; + char *latitude = (char *)NULL; + char *longitude = (char *)NULL; + char *lat_dir = (char *)NULL; + char *lon_dir = (char *)NULL; + char *qual = (char *)NULL; + char *altitude = (char *)NULL; + char *sats = (char *)NULL; + + token = strtok(uart1_buffer[passive_buffer], ","); + while (token) { + switch (token_counter) { + case 2: latitude = token; break; + case 4: longitude = token; break; + case 3: lat_dir = token; break; + case 5: lon_dir = token; break; + case 6: qual = token; break; + case 7: sats = token; break; + case 9: altitude = token; break; + } + token = strtok((char *)NULL, ","); + token_counter++; + } + + /* If the fix quality is valid set our location information. */ + if (latitude && longitude && altitude && sats) { + memcpy(the_location.lat, latitude, 10); /* Fixed length string. */ + memcpy(the_location.lon, longitude, 10); /* Fixed length string. */ + memset(the_location.alt, 0, sizeof(the_location.alt)); /* Clean string out first. */ + strncpy(the_location.alt, altitude, 10); /* Variable length string. */ + strncpy(the_location.sats, sats, 3); /* Variable length string. */ + the_location.north_south = lat_dir[0]; + the_location.east_west = lon_dir[0]; + the_location.is_valid = qual[0]; + the_location.updated++; + have_new_location = 1; + } + else { + the_location.is_valid = qual[0]; + } +} + +/** gps_convert_coord + * + * Given a string and a type convert the string into a double. + * + * @param char *s A pointer to the string to convert. + * @param int type The conversion type required (lat or lon) + * @return double the converted string. + */ +double gps_convert_coord(char *s, int type) { + int deg, min, sec; + double fsec, val; + + if (type == GPS_LAT_STR) { + deg = ( (s[0] - '0') * 10) + s[1] - '0'; + min = ( (s[2] - '0') * 10) + s[3] - '0'; + sec = ( ((s[5] - '0') * 1000) + ((s[6] - '0') * 100) + ((s[7] - '0') * 10) + (s[8] - '0')); + fsec = (double)((double)sec /10000.0); + val = (double)deg + ((double)((double)min/60.0)) + (fsec/60.0); + return val; + } + else { + deg = ( (s[0] - '0') * 100) + ((s[1] - '0') * 10) + (s[2] - '0'); + min = ( (s[3] - '0') * 10) + s[4] - '0'; + sec = ( ((s[6] - '0') * 1000) + ((s[7] - '0') * 100) + ((s[8] - '0') * 10) + (s[9] - '0')); + fsec = (double)((double)sec /10000.0); + val = (double)deg + ((double)((double)min/60.0)) + (fsec/60.0); + return val; + } +} + +/** gps_init + */ +void gps_init(void) { + int i; + + DEBUG_INIT_START; + + /* Set the time to a known starting point in the past. */ + the_time.year = 2000; + the_time.month = 1; + the_time.day = 1; + the_time.hour = 0; + the_time.minute = 0; + the_time.second = 0; + the_time.tenth = 0; + the_time.hundreth = 0; + the_time.is_valid = 0; + the_time.prev_valid = 0; + + memset(&the_location, 0, sizeof(GPS_LOCATION_RAW)); + + /* Initial condition. */ + time_updated = 0; + + /* Zero out the moving average filter. */ + lat_average = 0.; + lon_average = 0.; + history_in_index = 0; + history_complete = 0; + for(i = 0; i < GPS_HISTORY_SIZE; i++) { + lat_history[i] = 0.; + lon_history[i] = 0.; + } + + lat_acc_average = 0.; + lon_acc_average = 0.; + cnt_acc_average = 0.; + + /* Init the active buffer and the serial in pointer. */ + active_buffer = active_buffer_in = 0; + + /* Flag the passive buffer is not ready. The passive buffer + is the opposite of the active buffer. When the serial irq + system detects the end of a NEMA message it automatically + switches buffers and sets passive_buffer_ready non-zero to + indicate it's just finished dumping data into it. */ + passive_buffer_ready = 0; + + /* Updated to non-zero after a new location packet is received. */ + have_new_location = 0; + + /* Setup the 0.01second timer. */ + rit_timer_set_reload(RIT_TIMER_CB_GPS, 10); /* Recurring reload. */ + rit_timer_set_counter(RIT_TIMER_CB_GPS, 10); /* Start timer. */ + + DEBUG_INIT_END; + + Uart1_init(); +} + +/** gps_get_time + * + * Copies our internal time data structure to a buffer supplied by the caller. + * + * Note, the update flag is set to non-zero by the interrupt routines when an + * update occurs. The loop is to test if an update occured while the copy was + * in progress. If it did, do the copy again as it's most likely corrupted the + * orginal copy operation. + * + * @param GPS_TIME *q A pointer to the GPS_TIME data structure to copy to. + * @return GPS_TIME * The supplied pointer. + */ +GPS_TIME *gps_get_time(GPS_TIME *q) { + + do { + time_updated = 0; + memcpy(q, &the_time, sizeof(GPS_TIME)); + } while (time_updated != 0); + + return q; +} + +/** gps_get_location_raw + * + * Copies our internal location data structure to a buffer supplied by the caller. + * + * Note, the update flag is set to non-zero by the interrupt routines when an + * update occurs. The loop is to test if an update occured while the copy was + * in progress. If it did, do the copy again as it's most likely corrupted the + * orginal copy operation. + * + * @param GPS_LOCATION_RAW *q A pointer to the GPS_LOCATION_RAW data structure to copy to. + * @return GPS_LOCATION_RAW * The supplied pointer. + */ +GPS_LOCATION_RAW *gps_get_location_raw(GPS_LOCATION_RAW *q) { + + do { + location_updated = 0; + memcpy(q, &the_location, sizeof(GPS_LOCATION_RAW)); + } while (location_updated != 0); + + return q; +} + +/** gps_get_location_average + * + * Places the current average location into the supplied struct buffer. + * The caller is responsible for allocating the buffer storage space. + * + * Note, the update flag is set to non-zero by the interrupt routines when an + * update occurs. The loop is to test if an update occured while the copy was + * in progress. If it did, do the copy again as it's most likely corrupted the + * orginal copy operation. + * + * @param GPS_LOCATION_AVERAGE *q A pointer to the struct buffer to write data to. + * @return GPS_LOCATION_AVERAGE * The supplied pointer returned. + */ +GPS_LOCATION_AVERAGE *gps_get_location_average(GPS_LOCATION_AVERAGE *q) { + char **p = NULL; + + do { + location_updated = 0; + q->north_south = the_location.north_south; + q->latitude = lat_average; + q->east_west = the_location.east_west; + q->longitude = lon_average; + q->height = strtod(the_location.alt, p); + q->sats = the_location.sats; + q->is_valid = the_location.is_valid; + } while (location_updated != 0); + + /* Test the values to ensure the data is valid. */ + if (isnan(q->latitude) || isnan(q->longitude) || isnan(q->height)) { + q->is_valid = 0; + } + + return q; +} + +/** gps_julian_day_number + * + * Gets the Julian Day Number from the supplied time reference passed. + * http://en.wikipedia.org/wiki/Julian_day#Converting_Gregorian_calendar_date_to_Julian_Day_Number + * + * @param GPS_TIME *t A pointer to a time data structure. + * @return double The Julian Day Number. + */ +double gps_julian_day_number(GPS_TIME *t) { + double wikipedia_jdn = (double)(1461 * ((int)t->year + 4800 + ((int)t->month - 14) / 12)) / 4 + (367 * ((int)t->month - 2 - 12 * (((int)t->month - 14) / 12))) / 12 - (3 * (((int)t->year + 4900 + ((int)t->month - 14) / 12 ) / 100)) / 4 + (int)t->day - 32075; + + /* Not sure why yet but the calculation on the Wikipedia site returns a value that + is 0.5 too big. */ + return wikipedia_jdn; +} + +/** gps_julian_date + * + * Find the Julian Date based on the supplied args. + * + * @param GPS_TIME *t A pointer to a time data structure. + * @return double The Julian Date. + */ +double gps_julian_date(GPS_TIME *t) { + double hour, minute, second, jd; + hour = (double)t->hour; + minute = (double)t->minute; + second = (double)t->second + ((double)t->tenth / 10.) + ((double)t->hundreth / 100.); + /* Wiki fix, see above. */ + jd = gps_julian_day_number(t) - 0.5 + + ((hour - 12.) / 24.) + + (minute / 1440.) + + (second / 86400.); + + return jd; +} + +/** gps_siderealDegrees_by_jd + * + * Calculate the sidereal degree angle based on the + * Julian Date supplied. + * + * @param double jd Julian Date. + * @return The sidereal angle in degrees. + */ +double gps_siderealDegrees_by_jd(double jd) { + double sidereal, gmst, lmst, mul; + double T = jd - 2451545.0; + double T1 = T / 36525.0; + double T2 = T1 * T1; + double T3 = T2 * T1; + + /* Calculate gmst angle. */ + sidereal = 280.46061837 + (360.98564736629 * T) + (0.000387933 * T2) - (T3 / 38710000.0); + + /* Convert to degrees. */ + sidereal = fmod(sidereal, 360.0); + if (sidereal < 0.0) sidereal += 360.0; + + mul = (the_location.east_west == 'W') ? -1.0 : 1.0; + + gmst = sidereal; + lmst = gmst + (lon_average * mul); + return lmst; +} + +/** gps_siderealDegrees_by_time + * + * Calculate the sidereal degree angle based on the + * time data structure supplied. + * + * @param GPS_TIME *t A pointer to the time structure. + * @return The sidereal angle in degrees. + */ +double gps_siderealDegrees_by_time(GPS_TIME *t) { + GPS_TIME temp; + if (t == (GPS_TIME *)NULL) { + t = &temp; + gps_get_time(t); + } + return gps_siderealDegrees_by_jd(gps_julian_date(t)); +} + +/** gps_siderealHA_by_jd + * + * Calculate the HA (hour angle) based on the supplied Julian Date. + * + * @param double jd The Julian Date. + * @return double The Hour Angle. + */ +double gps_siderealHA_by_jd(double jd) { + double lmst = gps_siderealDegrees_by_jd(jd); + return lmst / 360.0 * 24.0; +} + +/** gps_siderealHA_by_time + * + * Calculate the HA (hour angle) based on the supplied time data structure. + * + * @param GPS_TIME *t The time data structure. + * @return double The Hour Angle. + */ +double gps_siderealHA_by_time(GPS_TIME *t) { + double lmst = gps_siderealDegrees_by_time(t); + return lmst / 360.0 * 24.0; +} + +/** _gps_inc_time + * + * Used to increment the time structure by 0.01sec. + * Called by the RIT timer callback. + * + * @see gpioirq.c + * @param int t_index The timer's index number (handle). + */ +void _gps_timer_tick_cb(int t_index) { + + /* We use x so that the_time.hundreth can never be 10 as I have noticed + occasionally between the ++ and the == 10 test an interrupt can occur + and then the_time.hundreth contains an invalid value. So using x to do + the ++ and ==10 test means the_time.hundreth can never itself be 10. + We reuse x on the tenths for a similar reason. */ + char x = the_time.hundreth; + x++; + + if (x == 10) { + the_time.hundreth = 0; + x = the_time.tenth + 1; + if (x < 10) { + the_time.tenth = x; + time_updated = 1; + } + } + else { + the_time.hundreth = x; + time_updated = 1; + } +} + +/** _gps_pps_alive_cb + * + * Timeout that goes off if the GPS 1PPS signal doesn't + * fire within 1.5seconds telling us that the GPS isn't + * connected. Not currently used. + */ +void _gps_pps_alive_cb(int index) { + the_time.is_valid = 0; +} + +/** gps_pps_fall + * + * Increments the seconds. Called by the GPS 1PP callback interrupt. + * + * Note, some GPS modules, including the one used in this design, + * provide a 1PPS signal. However, it's almost always positive logic + * and it doesn't interface directly to an Mbed pin/interrupt. So we + * have a simple FET that buffers the signal and in so doing it becomes + * an active low signal. Hence why this is a falling edge interrupt. + * + * @see gpioirq.c + */ +void gps_pps_fall(void) { + the_time.hundreth = 0; + the_time.tenth = 0; + _gps_time_inc(&the_time); +} + +/** gps_date_inc + * + * Increment the time. + * + * @param GPS_TIME *q Pointer the data struct holding the time. + */ +void _gps_time_inc(GPS_TIME *q) { + + time_updated = 1; + + q->second++; + if (q->second == 60) { + q->second = 0; + q->minute++; + if (q->minute == 60) { + q->minute = 0; + q->hour++; + if (q->hour == 24) { + q->hour = 0; + _gps_date_inc(q); + } + } + } +} + +/** _gps_date_inc + * + * Increment the date. + * + * @param GPS_TIME *q Pointer the data struct holding the time. + */ +void _gps_date_inc(GPS_TIME *q) { + const int days[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 } ; + + /* Handle February leap year. */ + int leap_year = ((the_time.year % 4 == 0 && the_time.year % 100 != 0) || the_time.year % 400 == 0) ? 1 : 0; + int days_this_month = days[q->month - 1]; + if (q->month == 2 && leap_year) days_this_month++; + + q->day++; + if (q->day > days_this_month) { + q->day = 1; + q->month++; + if (q->month == 13) { + q->year++; + } + } +} + +/* UART1 functions. */ + +extern "C" void UART1_IRQHandler(void) __irq { + volatile uint32_t iir; + volatile char c; + + iir = LPC_UART1->IIR; + + if (iir & 0x1) return; + + /* Do we have a serial character(s) in the fifo? */ + if (UART_RX_INTERRUPT) { + while (UART1_FIFO_NOT_EMPTY) { + c = UART1_GETC; + uart1_buffer[active_buffer][active_buffer_in++] = c; + active_buffer_in &= (GPS_BUFFER_SIZE - 1); + if (c == '\n') { + /* Swap buffers and clean it out. */ + active_buffer = active_buffer == 0 ? 1 : 0; + memset(uart1_buffer[active_buffer], 0, GPS_BUFFER_SIZE); + active_buffer_in = 0; + passive_buffer_ready = 1; + } + } + } +} + +/** Uart1_init + */ +void Uart1_init(void) { + + DEBUG_INIT_START; + + LPC_SC->PCONP |= (1UL << 4); + LPC_SC->PCLKSEL0 &= ~(3UL << 8); + LPC_SC->PCLKSEL0 |= (1UL << 8); + LPC_PINCON->PINSEL4 &= ~(3UL << 2); /* TXD1 not used. See SSP0_init() in max7456.c */ + LPC_PINCON->PINSEL4 |= (2UL << 2); /* TXD1 not used. See SSP0_init() in max7456.c */ + LPC_UART1->LCR = 0x83; + LPC_UART1->DLL = 0x71; + LPC_UART1->DLM = 0x02; + LPC_UART1->LCR = 0x03; + LPC_UART1->FCR = 0x07; + + NVIC_SetVector(UART1_IRQn, (uint32_t)UART1_IRQHandler); + NVIC_EnableIRQ(UART1_IRQn); + + /* Enable the RDA interrupt. */ + LPC_UART1->IER = 0x01; + + DEBUG_INIT_END; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gps/gps.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,109 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef GPS_H +#define GPS_H + +#define GPS_LAT_STR 0 +#define GPS_LON_STR 1 + +#define GPS_HISTORY_SIZE 60 + +typedef struct _gps_time { + int year; + char month; + char day; + char hour; + char minute; + char second; + char tenth; + char hundreth; + char is_valid; + char prev_valid; +} GPS_TIME; + +typedef struct _gps_location_raw { + char north_south; + char east_west; + char lat[16]; + char lon[16]; + char alt[16]; + char sats[8]; + char is_valid; + uint32_t updated; +} GPS_LOCATION_RAW; + +typedef struct _gps_location_average { + char north_south; + double latitude; + char east_west; + double longitude; + double height; + char *sats; + char is_valid; +} GPS_LOCATION_AVERAGE; + +/* GPS module API function prototypes. */ +void gps_init(void); +void gps_process(void); +double gps_convert_coord(char *s, int type); +double gps_julian_day_number(GPS_TIME *t); +double gps_julian_date(GPS_TIME *t); +double gps_siderealDegrees_by_jd(double jd); +double gps_siderealDegrees_by_time(GPS_TIME *t); +double gps_siderealHA_by_jd(double jd); +double gps_siderealHA_by_time(GPS_TIME *t); +GPS_TIME *gps_get_time(GPS_TIME *q); +GPS_LOCATION_RAW *gps_get_location_raw(GPS_LOCATION_RAW *q); +GPS_LOCATION_AVERAGE *gps_get_location_average(GPS_LOCATION_AVERAGE *q); + +/* Used by other modules to make callbacks. */ +void gps_pps_fall(void); /* gpioirq.c needs this to know what to callback to. */ + +#define GPS_BUFFER_SIZE 128 + +/* Used to test the IIR register. Common across UARTs. */ +#define UART_ISSET_THRE 0x0002 +#define UART_ISSET_RDA 0x0004 +#define UART_ISSET_CTI 0x000C +#define UART_ISSET_RLS 0x0006 +#define UART_ISSET_FIFOLVL_RXFULL 0x0000000F +#define UART_ISSET_FIFOLVL_TXFULL 0x00000F00 + +#define UART_RX_INTERRUPT iir & UART_ISSET_RDA + + +/* UART1 register configuration values. */ +#define UART1_SET_LCR 0x00000003 +#define UART1_SET_LCR_DLAB 0x00000083 +#define UART1_SET_DLLSB 0x71 +#define UART1_SET_DLMSB 0x02 +#define UART1_SET_FCR 0x01 +#define UART1_SET_FCR_CLEAR 0x07 +#define UART1_SET_IER 0x07 + +/* Macros. */ +#define UART1_FIFO_NOT_EMPTY LPC_UART1->LSR & 0x1 +#define UART1_GETC (char)LPC_UART1->RBR + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,289 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef MAIN_CPP +#define MAIN_CPP +#endif + +#include "sowb.h" +#include "gpioirq.h" +#include "gpio.h" +#include "rit.h" +#include "usbeh.h" +#include "usbeh_endpoint.h" +#include "usbeh_device.h" +#include "usbeh_controller.h" +#include "usbeh_api.h" +#include "xbox360gamepad.h" +#include "th_xbox360gamepad.h" +#include "gps.h" +#include "MAX7456.h" +#include "osd.h" +#include "nexstar.h" +#include "utils.h" +#include "user.h" +#include "dma.h" +#include "flash.h" +#include "sdcard.h" +#include "config.h" +#include "ff.h" +#include "sgp4sdp4.h" +#include "satapi.h" +#include "star.h" + +#include "main.h" +#include "debug.h" +#include "predict_th.h" + +int test_flash_page; + +/* Create an array of _process function pointers + to call while user_io is waiting. */ +typedef void (PROCESS_FUNC)(); + +PROCESS_FUNC *process_callbacks[] = { + usbeh_api_process, + xbox360gamepad_process, + gps_process, + gpioirq_process, + nexstar_process, + sdcard_process, + config_process, + NULL +}; + +int main_test_flag; + +void _main_test_callback(int index) { + main_test_flag = 0; +} + + + +int main() { + int counter = 0; + char test_buffer[256]; + DIR fDir; + FILINFO fInfo; + int f_return; + GPS_LOCATION_RAW location; + + /* Carry out module start-up _init() functions. + Note, the order is important, do not change. */ + debug_init(); + gpio_init(); + rit_init(); + xbox360gamepad_init(); + usbeh_api_init(); + MAX7456_init(); + osd_init(); + gps_init(); + gpioirq_init(); + + /* We use raw MAX7456 calls to display the splash screen because + at this point not all interrupts are active and the OSD system + will not yet be fully operational even though we've _init() it. */ + MAX7456_cursor(0, 5); MAX7456_string((unsigned char *)" Satellite Observers "); + MAX7456_cursor(0, 6); MAX7456_string((unsigned char *)" Workbench V0.1 "); + MAX7456_cursor(0, 7); MAX7456_string((unsigned char *)" (c) Copyright 2010 "); + MAX7456_cursor(0, 8); MAX7456_string((unsigned char *)" Stellar Technologies Ltd"); + if (LPC_WDT->WDMOD & 0x4) { MAX7456_cursor(0, 14); MAX7456_string((unsigned char *)" WDT Error detected"); } + user_wait_ms_blocking(2000); /* Simple splash screen delay. */ + MAX7456_cursor(0, 11); MAX7456_string((unsigned char *)" Press A to continue"); + while (user_get_button(false) != BUTT_A_PRESS) ; + while (user_get_button(false) != BUTT_A_RELEASE) ; + + /* Complete the module _init() stage. */ + nexstar_init(); + DMA_init(); + flash_init(); + sdcard_init(); + config_init(); + th_xbox360gamepad_init(); + + if (!_nexstar_is_aligned()) { + debug_printf("Nexstar not aligned, forcing user to align.\r\n"); + nexstar_force_align(); + } + + MAX7456_cursor(0, 11); MAX7456_string((unsigned char *)" Waiting for GPS...."); + do { + gps_get_location_raw(&location); + WHILE_WAITING_DO_PROCESS_FUNCTIONS; + } while (location.is_valid == '0'); + osd_clear(); osd_set_mode_l01(L01_MODE_A); + + /* Tell the Nexstar the real time and place. */ + _nexstar_set_time(NULL); + _nexstar_set_location(NULL); + + /* Init the watchdog and then go into the main loop. */ + LPC_SC->PCLKSEL0 |= 0x3; + LPC_WDT->WDCLKSEL = 1; + LPC_WDT->WDTC = 6000000; + LPC_WDT->WDMOD = 3; + KICK_WATCHDOG; + + while(1) { + + char c = user_get_button(false); + switch (c) { + case BUTT_START_PRESS: + if (!sdcard_is_mounted()) { + osd_string_xy(1, 14, "No SD card inserted"); + } + break; + + case BUTT_XBOX_PRESS: + SAT_POS_DATA q; + satapi_aos(&q, true); + break; + + case BUTT_LS_PRESS: + osd_l01_next_mode(); + break; + case BUTT_RS_PRESS: + osd_crosshair_toggle(); + break; + case BUTT_B_PRESS: + //_nexstar_goto_azm_fast(0x238F); + //_nexstar_goto(0x238F, 0x238F); + _nexstar_goto(0x0, 0x0); + break; + case BUTT_X_PRESS: + /* + _nexstar_set_elevation_rate_auto(1.0); + main_test_flag = 1; + rit_timer_set_counter(MAIN_TEST_CB, 5000); + P22_ASSERT; + while (main_test_flag == 1) { + user_call_process(); + } + _nexstar_set_elevation_rate_auto(0); + P22_DEASSERT; + */ + + for (int i = 0; i < 256; i++) { + test_buffer[i] = 255 - i; + } + debug_printf("Test buffer before:-\r\n"); + printBuffer(test_buffer, 256); + flash_page_write(1, test_buffer); + LED1_ON; + while(flash_write_in_progress()); + LED1_OFF; + flash_read_page(1, test_buffer, true); + debug_printf("Test buffer after:-\r\n"); + printBuffer(test_buffer, 256); + break; + + case BUTT_Y_PRESS: + memset(test_buffer, 0xAA, 256); + flash_read_page(0, test_buffer, true); + debug_printf("Page 0\r\n"); + printBuffer(test_buffer, 256); + memset(test_buffer, 0xAA, 256); + flash_read_page(1, test_buffer, true); + debug_printf("Page 1\r\n"); + printBuffer(test_buffer, 256); + memset(test_buffer, 0xAA, 256); + flash_read_page(2, test_buffer, true); + debug_printf("Page 2\r\n"); + printBuffer(test_buffer, 256); + memset(test_buffer, 0xAA, 256); + flash_read_page(3, test_buffer, true); + debug_printf("Page 3\r\n"); + printBuffer(test_buffer, 256); + break; + case BUTT_DPAD_DOWN_PRESS: + flash_erase_sector(0); + break; + case BUTT_DPAD_UP_PRESS: + flash_erase_bulk(); + break; + case BUTT_DPAD_LEFT_PRESS: + { + AltAz y; + RaDec x; + GPS_LOCATION_AVERAGE loc; + GPS_TIME t; + memset(&t, 0, sizeof(GPS_TIME)); + t.year = 2010; t.month = 10; t.day = 7; t.hour = 21; t.minute = 15; t.second = 21; + + double jd = gps_julian_date(&t); + sprintf(test_buffer, "\n\n\rJD = %f\r\n", jd); + debug_printf(test_buffer); + + gps_get_location_average(&loc); + double siderealDegrees = gps_siderealDegrees_by_time(&t); + sprintf(test_buffer, "SR by time = %f\r\n", siderealDegrees); + debug_printf(test_buffer); + + x.dec = 28.026111; + x.ra = 116.32875; + + sprintf(test_buffer, "Staring with Dec = %f, RA = %f\r\n", x.dec, x.ra); + debug_printf(test_buffer); + + radec2altaz(siderealDegrees, &loc, &x, &y); + sprintf(test_buffer, "Alt = %f, Azm = %f\r\n", y.alt, y.azm); + debug_printf(test_buffer); + + altaz2radec(siderealDegrees, &loc, &y, &x); + sprintf(test_buffer, "Dec = %f, RA = %f\r\n", x.dec, x.ra); + debug_printf(test_buffer); + + // Lets look for the brightest star near Sirius. + // It should return HR2491, Sirius it's self. + // RA 6 45 8.9 101.2606833 + // Dec -16 42, 58 -16.716111 + x.ra = 101.2606833; x.dec = -16.716111; + char test_buffer2[32]; + basicStarData star, *p; + p = star_closest(&x, &star); + if (!p) { + debug_printf("No star found\r\n"); + } + else { + sprintf(test_buffer, "HR%d %f %f %f\r\n", star.hr, star.ra, star.dec, star.mag); + debug_printf(test_buffer); + } + + + } + + + break; + } + + //sgp4sdp4_th_init(); + + /* + for(int i = 0; process_callbacks[i] != NULL; i++) { + (process_callbacks[i])(); + } + + th_xbox360gamepad(); + */ + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,37 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef MAIN_H +#define MAIN_H + +#ifdef MAIN_CPP + +/* Define system globals here. */ +//Serial debug(USBTX, USBRX); + +#else + +/* Declare system globals here. */ +//extern Serial debug; + +#endif +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/9114680c05da
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/md5/md5.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,396 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +/* + Not even sure where I lifted this code now, but I think it was the + FreeBSD project. So any copyright that is attributable to that project + and the BSD license is acknowledged. This module is dual licensed:- + + http://www.opensource.org/licenses/bsd-license.php + + Copyright (c) 2010, Stellar Technologies Ltd/Andy Kirkham + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the <ORGANIZATION> nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Additionally see http://www.freebsd.org/copyright/license.html +*/ + +#include "sowb.h" + +/** + * MD5 context structure. + */ +typedef struct { + uint32_t lo, hi; + uint32_t a, b, c, d; + unsigned char buffer[64]; + uint32_t block[16]; +} MD5_CTX; + +/* Used to create human text for MD5 */ +static const char hexits[17] = "0123456789ABCDEF"; + +/** + * Internal function prototypes. + */ +static void make_digest(char *md5str, unsigned char *digest); +static void md5_init(MD5_CTX *); +static void md5_update(MD5_CTX *, const void *, unsigned int); +static void md5_final(unsigned char *, MD5_CTX *); +static const void *body(MD5_CTX *, const void *, unsigned int); + +void md5(const char *s, char *md5str) { + + // A local MD5 context. + MD5_CTX context; + + // Place to store the raw MD5 digest. + unsigned char digest[16]; + + // Clear the output string and initialise the context. + md5str[0] = '\0'; + md5_init(&context); + + // Make the MD5 and finalise. + md5_update(&context, s, strlen(s)); + md5_final(digest, &context); + + // Convert the binary digest into human text in the caller's output buffer. + make_digest(md5str, digest); +} + +/** + * md5_short + * + * As MD5 function but selects 5 fixed characters + * from the 32 generated to return a short name. + */ +void md5_short(const char *s, char *md5str, int d) { + char temp[33]; + static const int day[7][5] = { + { 18, 3, 8, 27, 19 }, // 01 + { 12, 11, 6, 21, 15 }, // 02 + { 27, 14, 12, 4, 11 }, // 03 + { 12, 18, 13, 6, 2 }, // 04 + { 29, 13, 8, 1, 15 }, // 05 + { 13, 12, 9, 30, 22 }, // 06 + { 29, 31, 2, 5, 14 } // 07 + }; + + // Get the full MD5 string. + md5(s, temp); + + // Ensure we stay within our array boundaries. + d &= 0x7; + + // Get the shortened version of the MD5. + md5str[0] = temp[day[d][0]]; + md5str[1] = temp[day[d][1]]; + md5str[2] = temp[day[d][2]]; + md5str[3] = temp[day[d][3]]; + md5str[4] = temp[day[d][4]]; + md5str[5] = '\0'; +} + +static void make_digest(char *md5str, unsigned char *digest) { + int i; + + for (i = 0; i < 16; i++) { + md5str[i * 2] = hexits[digest[i] >> 4]; + md5str[(i * 2) + 1] = hexits[digest[i] & 0x0F]; + } + + md5str[32] = '\0'; +} + +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, + * Inc. MD5 Message-Digest Algorithm (RFC 1321). + * + * Written by Solar Designer <solar at openwall.com> in 2001, and placed + * in the public domain. There's absolutely no warranty. + * + * This differs from Colin Plumb's older public domain implementation in + * that no 32-bit integer data type is required, there's no compile-time + * endianness configuration, and the function prototypes match OpenSSL's. + * The primary goals are portability and ease of use. + * + * This implementation is meant to be fast, but not as fast as possible. + * Some known optimizations are not included to reduce source code size + * and avoid compile-time configuration. + */ + + +/* + * The basic MD5 functions. + * + * F and G are optimized compared to their RFC 1321 definitions for + * architectures that lack an AND-NOT instruction, just like in Colin Plumb's + * implementation. + */ +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | ~(z))) + +/* + * The MD5 transformation for all four rounds. + */ +#define STEP(f, a, b, c, d, x, t, s) \ + (a) += f((b), (c), (d)) + (x) + (t); \ + (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \ + (a) += (b); + +# define SET(n) \ + (ctx->block[(n)] = \ + (uint32_t)ptr[(n) * 4] | \ + ((uint32_t)ptr[(n) * 4 + 1] << 8) | \ + ((uint32_t)ptr[(n) * 4 + 2] << 16) | \ + ((uint32_t)ptr[(n) * 4 + 3] << 24)) +# define GET(n) \ + (ctx->block[(n)]) + +/* + * This processes one or more 64-byte data blocks, but does NOT update + * the bit counters. There are no alignment requirements. + */ +static const void *body(MD5_CTX *ctx, const void *data, unsigned int size) { + const unsigned char *ptr; + uint32_t a, b, c, d; + uint32_t saved_a, saved_b, saved_c, saved_d; + + ptr = (const unsigned char *)data; + + a = ctx->a; + b = ctx->b; + c = ctx->c; + d = ctx->d; + + do { + saved_a = a; + saved_b = b; + saved_c = c; + saved_d = d; + + /* Round 1 */ + STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7) + STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12) + STEP(F, c, d, a, b, SET(2), 0x242070db, 17) + STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22) + STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7) + STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12) + STEP(F, c, d, a, b, SET(6), 0xa8304613, 17) + STEP(F, b, c, d, a, SET(7), 0xfd469501, 22) + STEP(F, a, b, c, d, SET(8), 0x698098d8, 7) + STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12) + STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17) + STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22) + STEP(F, a, b, c, d, SET(12), 0x6b901122, 7) + STEP(F, d, a, b, c, SET(13), 0xfd987193, 12) + STEP(F, c, d, a, b, SET(14), 0xa679438e, 17) + STEP(F, b, c, d, a, SET(15), 0x49b40821, 22) + + /* Round 2 */ + STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5) + STEP(G, d, a, b, c, GET(6), 0xc040b340, 9) + STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14) + STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20) + STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5) + STEP(G, d, a, b, c, GET(10), 0x02441453, 9) + STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14) + STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20) + STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5) + STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9) + STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14) + STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20) + STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5) + STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9) + STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14) + STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20) + + /* Round 3 */ + STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4) + STEP(H, d, a, b, c, GET(8), 0x8771f681, 11) + STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16) + STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23) + STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4) + STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11) + STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16) + STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23) + STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4) + STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11) + STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16) + STEP(H, b, c, d, a, GET(6), 0x04881d05, 23) + STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4) + STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11) + STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16) + STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23) + + /* Round 4 */ + STEP(I, a, b, c, d, GET(0), 0xf4292244, 6) + STEP(I, d, a, b, c, GET(7), 0x432aff97, 10) + STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15) + STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21) + STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6) + STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10) + STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15) + STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21) + STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6) + STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10) + STEP(I, c, d, a, b, GET(6), 0xa3014314, 15) + STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21) + STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6) + STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10) + STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15) + STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21) + + a += saved_a; + b += saved_b; + c += saved_c; + d += saved_d; + + ptr += 64; + } while (size -= 64); + + ctx->a = a; + ctx->b = b; + ctx->c = c; + ctx->d = d; + + return ptr; +} + +static void md5_init(MD5_CTX *ctx) { + ctx->a = 0x67452301; + ctx->b = 0xefcdab89; + ctx->c = 0x98badcfe; + ctx->d = 0x10325476; + + ctx->lo = 0; + ctx->hi = 0; +} + +static void md5_update(MD5_CTX *ctx, const void *data, unsigned int size) { + uint32_t saved_lo; + uint32_t used, free; + + saved_lo = ctx->lo; + if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) { + ctx->hi++; + } + ctx->hi += size >> 29; + + used = saved_lo & 0x3f; + + if (used) { + free = 64 - used; + + if (size < free) { + memcpy(&ctx->buffer[used], data, size); + return; + } + + memcpy(&ctx->buffer[used], data, free); + data = (unsigned char *)data + free; + size -= free; + body(ctx, ctx->buffer, 64); + } + + if (size >= 64) { + data = body(ctx, data, size & ~(size_t)0x3f); + size &= 0x3f; + } + + memcpy(ctx->buffer, data, size); +} + +static void md5_final(unsigned char *result, MD5_CTX *ctx) { + uint32_t used, free; + + used = ctx->lo & 0x3f; + + ctx->buffer[used++] = 0x80; + + free = 64 - used; + + if (free < 8) { + memset(&ctx->buffer[used], 0, free); + body(ctx, ctx->buffer, 64); + used = 0; + free = 64; + } + + memset(&ctx->buffer[used], 0, free - 8); + + ctx->lo <<= 3; + ctx->buffer[56] = (unsigned char)ctx->lo; + ctx->buffer[57] = (unsigned char)(ctx->lo >> 8); + ctx->buffer[58] = (unsigned char)(ctx->lo >> 16); + ctx->buffer[59] = (unsigned char)(ctx->lo >> 24); + ctx->buffer[60] = (unsigned char)(ctx->hi); + ctx->buffer[61] = (unsigned char)(ctx->hi >> 8); + ctx->buffer[62] = (unsigned char)(ctx->hi >> 16); + ctx->buffer[63] = (unsigned char)(ctx->hi >> 24); + + body(ctx, ctx->buffer, 64); + + result[0] = (unsigned char)ctx->a; + result[1] = (unsigned char)(ctx->a >> 8); + result[2] = (unsigned char)(ctx->a >> 16); + result[3] = (unsigned char)(ctx->a >> 24); + result[4] = (unsigned char)ctx->b; + result[5] = (unsigned char)(ctx->b >> 8); + result[6] = (unsigned char)(ctx->b >> 16); + result[7] = (unsigned char)(ctx->b >> 24); + result[8] = (unsigned char)ctx->c; + result[9] = (unsigned char)(ctx->c >> 8); + result[10] = (unsigned char)(ctx->c >> 16); + result[11] = (unsigned char)(ctx->c >> 24); + result[12] = (unsigned char)ctx->d; + result[13] = (unsigned char)(ctx->d >> 8); + result[14] = (unsigned char)(ctx->d >> 16); + result[15] = (unsigned char)(ctx->d >> 24); + + memset(ctx, 0, sizeof(*ctx)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/md5/md5.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,9 @@ + +#ifndef MD5_H +#define MD5_H + + +void md5(const char *s, char *md5str); +void md5_short(const char *s, char *md5str, int day); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nexstar/nexstar.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,640 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +/* + Update: This whole module requires refactoring into something much more + sane. Basically, I "organically" grew the code in this module with trial + and error using the hardware since getting simple things done proved hard. + I did design (see below) what I thought reasonable system but the Nexstar + kept throwing up problems. So I really need to come back to this code and + sort it out properly. + + Frustrations: I originally implemented an "intelligent" start-up routine + that sent echo requests to check the Nexstar was there, then requested + isAligned and, once aligned, would finally send the Tracking Off command + and enter operational state. However, that's all out the window. + + Basically, I have found that if you send anything down the serial cable + while the Nexstar is powering up it goes dumb and won't responsd to + anything you send it. How useless, someone needs to educate their + software engineers to designing robust serial protocols that can + handle battery/power failure. Really very silly because I now know + that my software MUST assume the end user has powered on their Nexstar + before I start sending serial commands! Rubbish design, I like smart + designs that don't rely on the end user having to do "special things", + they should just work! + + Additionally, I have found that, based on documents from TheSky program + you cannot ask the Nexstar for it's pointing position faster than once + per second! WTF? Asking too fast can crash the Nexstar hand controller. + Doh! Since we really need the position at a higher frequency then at the + subsecond level, the pointing position is calculated from the last position + known +/- whatever variable speed rates have been sent since then. + + For the purposes of trying to track a fast moving object (an artificial + satellite in this case) we end up having to do most of the work ourselves + and hope the Nexstar tracks it with a sub-standard pointing system. + Hopefully I'll get it right! + + Means the serial protocol I develop here is more basic than I would have + prefered. For example, rather than sending periodic echo requests to + detect the Nexstar, I'll send just one. If no reply I'll have to prompt + the user to "Power on the Nexstar and press a key to continue". Doh. +*/ + +#define NEXSTAR_C + +#include "sowb.h" +#include "nexstar.h" +#include "utils.h" +#include "rit.h" +#include "user.h" +#include "osd.h" +#include "debug.h" +#include "gpio.h" +#include "main.h" + +/* Module global variables. */ +int nexstar_status; +int nexstar_command; +int nexstar_command_status; +char rx_buffer[NEXSTAR_BUFFER_SIZE]; +int rx_buffer_in; + +bool nexstar_aligned; + +double last_elevation; +double last_azmith; +double virtual_elevation; +double virtual_azmith; + +double elevation_rate; +double elevation_rate_coarse; +double elevation_rate_fine; +double elevation_rate_auto; + +double azmith_rate; +double azmith_rate_coarse; +double azmith_rate_fine; +double azmith_rate_auto; + +bool nexstar_goto_in_progress; +char nexstar_goto_elevation[5]; +char nexstar_goto_azmith[5]; + +int virtual_update_counter; + +/* Local function prototypes. */ +static void Uart2_init(void); +static inline void Uart2_putc(char c); +static inline void Uart2_puts(char *s, int len); + +/** nexstar_process + * + * Our system _process function. + */ +void nexstar_process(void) { + + if (nexstar_command_status != 0) { + switch (nexstar_command) { + case NEXSTAR_IS_ALIGNED: + nexstar_aligned = rx_buffer[0] == 1 ? true : false; + nexstar_command = 0; + nexstar_command_status = 0; + break; + case NEXSTAR_GET_AZMALT: + last_azmith = virtual_azmith = 360.0 * (((double)hex2bin(&rx_buffer[0], 4)) / 65536.0); + last_elevation = virtual_elevation = 360.0 * (((double)hex2bin(&rx_buffer[5], 4)) / 65536.0); + nexstar_command = 0; + nexstar_command_status = 0; + virtual_update_counter = 0; + if (nexstar_goto_in_progress) { + if (!memcmp(&rx_buffer[0], nexstar_goto_azmith, 4) && !memcmp(&rx_buffer[5], nexstar_goto_elevation, 4)) { + nexstar_goto_in_progress = false; + osd_clear_line(2); + osd_clear_line(3); + _nexstar_set_tracking_mode(0); + } + } + break; + case NEXSTAR_GET_RADEC: + + break; + case NEXSTAR_SET_ELEVATION_RATE: + case NEXSTAR_SET_AZMITH_RATE: + nexstar_command = 0; + nexstar_command_status = 0; + break; + case NEXSTAR_GOTO: + nexstar_command = 0; + nexstar_command_status = 0; + break; + case NEXSTAR_GOTO_AZM_FAST: + nexstar_command = 0; + nexstar_command_status = 0; + break; + case NEXSTAR_SET_APPROACH: + nexstar_command = 0; + nexstar_command_status = 0; + break; + case NEXSTAR_SET_TIME: + nexstar_command = 0; + nexstar_command_status = 0; + break; + case NEXSTAR_SET_LOCATION: + nexstar_command = 0; + nexstar_command_status = 0; + break; + case NEXSTAR_SYNC: + nexstar_command = 0; + nexstar_command_status = 0; + break; + } + } +} + +/** nexstar_timeout_callback + * + * The generic timer callback handler. + * + * @param int index The timer index (handle). + */ +void _nexstar_timeout_callback(int index) { + nexstar_status = NEXSTAR_STATE_NOT_CONN; +} + +void _nexstar_one_second_timer(int index) { + _nexstar_get_altazm(); + //_nexstar_get_radec(); + rit_timer_set_counter(RIT_ONESEC_NEXSTAR, 200); +} + +double nexstar_get_rate_azm(void) { + if (nexstar_goto_in_progress) return 0.0; + return azmith_rate_coarse + azmith_rate_fine + azmith_rate_auto; +} + +double nexstar_get_rate_alt(void) { + if (nexstar_goto_in_progress) return 0.0; + return elevation_rate_coarse + elevation_rate_fine + elevation_rate_auto; +} + +void _nexstar_100th_timer(int index) { + rit_timer_set_counter(RIT_100TH_NEXSTAR, 100); +} + +/** nexstar_init + * + * Used to initialise the system. + */ +void nexstar_init(void) { + + DEBUG_INIT_START; + + rit_timer_set_counter(RIT_TIMER_NEXSTAR, 0); + rit_timer_set_counter(RIT_ONESEC_NEXSTAR, 250); + rit_timer_set_counter(RIT_100TH_NEXSTAR, 100); + nexstar_status = NEXSTAR_STATE_IDLE; + nexstar_command = 0; + nexstar_command_status = 0; + last_elevation = 0.0; + last_azmith = 0.0; + virtual_elevation = 0.0; + virtual_azmith = 0.0; + + elevation_rate = elevation_rate_coarse = elevation_rate_fine = elevation_rate_auto = 0.0; + azmith_rate = azmith_rate_coarse = azmith_rate_fine = azmith_rate_auto = 0.0; + + nexstar_goto_in_progress = false; + + nexstar_aligned = false; + + rx_buffer_in = 0; + virtual_update_counter = 0; + + DEBUG_INIT_END; + + Uart2_init(); +} + +/* External API functions. */ +void nexstar_get_elazm(double *el, double *azm) { + *(el) = last_elevation; + *(azm) = last_azmith; +} + +/* Internal API functions. */ +int _nexstar_set_tracking_mode(int mode) { + if (nexstar_status == NEXSTAR_STATE_IDLE) { + nexstar_status = NEXSTAR_STATE_BUSY; + rx_buffer_in = 0; + nexstar_command_status = 0; + nexstar_command = NEXSTAR_SET_TRACKING; + LPC_UART2->FCR = UART2_SET_FCR_CLEAR; + Uart2_putc('T'); + Uart2_putc((char)mode); + rit_timer_set_counter(RIT_TIMER_NEXSTAR, NEXSTAR_SERIAL_TIMEOUT); + return 1; + } + return 0; +} + +int _nexstar_get_altazm(void) { + if (nexstar_status == NEXSTAR_STATE_IDLE) { + nexstar_status = NEXSTAR_STATE_BUSY; + rx_buffer_in = 0; + nexstar_command_status = 0; + nexstar_command = NEXSTAR_GET_AZMALT; + LPC_UART2->FCR = UART2_SET_FCR_CLEAR; + Uart2_putc('Z'); + rit_timer_set_counter(RIT_TIMER_NEXSTAR, NEXSTAR_SERIAL_TIMEOUT); + return 1; + } + return 0; +} + +int _nexstar_get_radec(void) { + if (nexstar_status == NEXSTAR_STATE_IDLE) { + nexstar_status = NEXSTAR_STATE_BUSY; + rx_buffer_in = 0; + nexstar_command_status = 0; + nexstar_command = NEXSTAR_GET_RADEC; + LPC_UART2->FCR = UART2_SET_FCR_CLEAR; + Uart2_putc('E'); + rit_timer_set_counter(RIT_TIMER_NEXSTAR, NEXSTAR_SERIAL_TIMEOUT); + return 1; + } + return 0; +} + +void _nexstar_set_elevation_rate_coarse(double rate) { + elevation_rate_coarse = rate; + _nexstar_set_elevation_rate(); +} + +void _nexstar_set_elevation_rate_fine(double rate) { + elevation_rate_fine = rate; + _nexstar_set_elevation_rate(); +} + +void _nexstar_set_elevation_rate_auto(double rate) { + elevation_rate_auto = rate; + _nexstar_set_elevation_rate(); +} + +int _nexstar_set_elevation_rate(void) { + char dir, high, low, cmd[32]; + double rate; + + rate = elevation_rate_coarse + elevation_rate_fine + elevation_rate_auto; + + if (elevation_rate == rate) return 0; + + if (rate != 0.0) { + if (nexstar_goto_in_progress || nexstar_status != NEXSTAR_STATE_IDLE) return 0; + } + + while (nexstar_status != NEXSTAR_STATE_IDLE) { + if (nexstar_status == NEXSTAR_STATE_NOT_CONN) return 0; + user_wait_ms(1); + }; + + //if (rate >= 0.0) osd_string_xyl(0, 14, cmd, sprintf(cmd, " ALT >> %c%.1f", '+', rate)); + //else osd_string_xyl(0, 14, cmd, sprintf(cmd, " ALT >> %+.1f", rate)); + nexstar_status = NEXSTAR_STATE_BUSY; + rx_buffer_in = 0; + nexstar_command_status = 0; + nexstar_command = NEXSTAR_SET_ELEVATION_RATE; + LPC_UART2->FCR = UART2_SET_FCR_CLEAR; + dir = 6; + if (rate < 0.0) { + dir = 7; + rate *= -1; + } + high = ((int)(3600.0 * rate * 4.0) / 256) & 0xFF; + low = ((int)(3600.0 * rate * 4.0) % 256) & 0xFF; + Uart2_puts(cmd, sprintf(cmd, "P%c%c%c%c%c%c%c", 3, 17, dir, high, low, 0, 0)); + rit_timer_set_counter(RIT_TIMER_NEXSTAR, NEXSTAR_SERIAL_TIMEOUT); + elevation_rate = rate; + return 1; +} + +void _nexstar_set_azmith_rate_coarse(double rate) { + azmith_rate_coarse = rate; + _nexstar_set_azmith_rate(); +} + +void _nexstar_set_azmith_rate_fine(double rate) { + azmith_rate_fine = rate; + _nexstar_set_azmith_rate(); +} + +void _nexstar_set_azmith_rate_auto(double rate) { + azmith_rate_auto = rate; + _nexstar_set_azmith_rate(); +} + +int _nexstar_set_azmith_rate(void) { + char dir, high, low, cmd[32]; + double rate; + + rate = azmith_rate_coarse + azmith_rate_fine + azmith_rate_auto; + + if (azmith_rate == rate) return 0; + + if (rate != 0.0) { + if (nexstar_goto_in_progress || nexstar_status != NEXSTAR_STATE_IDLE) return 0; + } + + while (nexstar_status != NEXSTAR_STATE_IDLE) { + if (nexstar_status == NEXSTAR_STATE_NOT_CONN) return 0; + user_wait_ms(1); + }; + + //if (rate >= 0.0) osd_string_xyl(14, 14, cmd, sprintf(cmd, " AZM >> %c%.1f", '+', rate)); + //else osd_string_xyl(14, 14, cmd, sprintf(cmd, " AZM >> %+.1f", rate)); + nexstar_status = NEXSTAR_STATE_BUSY; + nexstar_status = NEXSTAR_STATE_BUSY; + rx_buffer_in = 0; + nexstar_command_status = 0; + nexstar_command = NEXSTAR_SET_AZMITH_RATE; + LPC_UART2->FCR = UART2_SET_FCR_CLEAR; + dir = 6; + if (rate < 0.0) { + dir = 7; + rate *= -1; + } + high = ((int)(3600.0 * rate * 4.0) / 256) & 0xFF; + low = ((int)(3600.0 * rate * 4.0) % 256) & 0xFF; + Uart2_puts(cmd, sprintf(cmd, "P%c%c%c%c%c%c%c", 3, 16, dir, high, low, 0, 0)); + rit_timer_set_counter(RIT_TIMER_NEXSTAR, NEXSTAR_SERIAL_TIMEOUT); + azmith_rate = rate; + return 1; +} + +int _nexstar_goto(uint32_t elevation, uint32_t azmith) { + char cmd[32], buf1[6], buf2[6]; + double azm_target, azm_current; + + if (nexstar_goto_in_progress) return 0; + + printDouble_3_2(buf1, 360.0 * ((double)elevation / 65536)); + osd_stringl(2, cmd, sprintf(cmd, " GOTO > %s < ALT", buf1)); + printDouble_3_2(buf2, 360.0 * ((double)azmith / 65536)); + osd_stringl(3, cmd, sprintf(cmd, " > %s < AZM", buf2)); + osd_clear_line(14); + + /* Adjust the GOTO approach based on where we are pointing now + comapred to where we want to go. */ + azm_target = 360.0 * ((double)((double)azmith / 65536.0)); + azm_current = last_azmith - azm_target; + + if (azm_current > 180.) _nexstar_set_azm_approach(1); + else _nexstar_set_azm_approach(-1); + + while(nexstar_status != NEXSTAR_STATE_IDLE) { + if(nexstar_status == NEXSTAR_STATE_NOT_CONN) return 0; + user_wait_ms(1); + }; + + nexstar_goto_in_progress = true; + nexstar_status = NEXSTAR_STATE_BUSY; + rx_buffer_in = 0; + nexstar_command_status = 0; + nexstar_command = NEXSTAR_GOTO; + LPC_UART2->FCR = UART2_SET_FCR_CLEAR; + sprintf(nexstar_goto_azmith, "%04X", azmith); + sprintf(nexstar_goto_elevation, "%04X", elevation); + Uart2_puts(cmd, sprintf(cmd, "B%s,%s", nexstar_goto_azmith, nexstar_goto_elevation)); + rit_timer_set_counter(RIT_TIMER_NEXSTAR, 60000); + return 1; +} + +int _nexstar_goto_azm_fast(uint32_t azmith) { + char cmd[16]; + + while(nexstar_status != NEXSTAR_STATE_IDLE) { + if(nexstar_status == NEXSTAR_STATE_NOT_CONN) return 0; + user_wait_ms(1); + }; + + nexstar_status = NEXSTAR_STATE_BUSY; + rx_buffer_in = 0; + nexstar_command_status = 0; + nexstar_command = NEXSTAR_GOTO_AZM_FAST; + LPC_UART2->FCR = UART2_SET_FCR_CLEAR; + Uart2_puts(cmd, sprintf(cmd, "P%c%c%c%c%c%c%c", 3, 16, 2, (azmith >> 8) & 0xFF, azmith & 0xFF, 0, 0)); + + rit_timer_set_counter(RIT_TIMER_NEXSTAR, 60000); + return 1; +} + +void _nexstar_set_azm_approach(int approach) { + char cmd[16]; + + while(nexstar_status != NEXSTAR_STATE_IDLE) { + if(nexstar_status == NEXSTAR_STATE_NOT_CONN) return; + user_wait_ms(1); + }; + + nexstar_command = NEXSTAR_SET_APPROACH; + nexstar_command_status = 0; + nexstar_status = NEXSTAR_STATE_BUSY; + rx_buffer_in = 0; + LPC_UART2->FCR = UART2_SET_FCR_CLEAR; + Uart2_puts(cmd, sprintf(cmd, "P%c%c%c%c%c%c%c", 3, 16, 0xFD, approach < 0 ? 1 : 0, 0, 0, 0)); + rit_timer_set_counter(RIT_TIMER_NEXSTAR, NEXSTAR_SERIAL_TIMEOUT); +} + +bool _nexstar_is_aligned(void) { + + while(nexstar_status != NEXSTAR_STATE_IDLE) { + if(nexstar_status == NEXSTAR_STATE_NOT_CONN) return false; + user_wait_ms(1); + }; + + nexstar_command = NEXSTAR_IS_ALIGNED; + nexstar_command_status = 0; + nexstar_status = NEXSTAR_STATE_BUSY; + rx_buffer_in = 0; + LPC_UART2->FCR = UART2_SET_FCR_CLEAR; + Uart2_putc('J'); + rit_timer_set_counter(RIT_TIMER_NEXSTAR, NEXSTAR_SERIAL_TIMEOUT); + + /* This command blocks while we wait for an answer. */ + while(nexstar_status != NEXSTAR_STATE_IDLE) { + user_wait_ms(10); + }; + + return nexstar_aligned; +} + +void _nexstar_sync(RaDec *radec) { + char cmd[32]; + uint16_t ra, dec; + + while(nexstar_status != NEXSTAR_STATE_IDLE) { + user_wait_ms(1); + }; + + ra = (uint16_t)((radec->ra / 360.0) * 65536); + dec = (uint16_t)((radec->dec / 360.0) * 65536); + + nexstar_command = NEXSTAR_SYNC; + nexstar_command_status = 0; + nexstar_status = NEXSTAR_STATE_BUSY; + rx_buffer_in = 0; + LPC_UART2->FCR = UART2_SET_FCR_CLEAR; + Uart2_puts(cmd, sprintf(cmd, "S%02X,%02X", ra, dec)); + rit_timer_set_counter(RIT_TIMER_NEXSTAR, NEXSTAR_SERIAL_TIMEOUT); + +} + +void _nexstar_set_time(GPS_TIME *t) { + char cmd[32]; + GPS_TIME rt; + + while(nexstar_status != NEXSTAR_STATE_IDLE) { + user_wait_ms(1); + }; + + if (t == (GPS_TIME *)NULL) { + t = &rt; + gps_get_time(t); + } + + nexstar_command = NEXSTAR_SET_TIME; + nexstar_command_status = 0; + nexstar_status = NEXSTAR_STATE_BUSY; + rx_buffer_in = 0; + LPC_UART2->FCR = UART2_SET_FCR_CLEAR; + Uart2_puts(cmd, sprintf(cmd, "H%c%c%c%c%c%c%c%c", t->hour, t->minute, t->second, t->month, t->day, t->year - 2000, 0, 0)); + rit_timer_set_counter(RIT_TIMER_NEXSTAR, NEXSTAR_SERIAL_TIMEOUT); +} + +void _nexstar_set_location(GPS_LOCATION_AVERAGE *l) { + char cmd[32]; + GPS_LOCATION_AVERAGE rl; + double d, t; + char lat_degrees, lat_minutes, lat_seconds, lon_degrees, lon_minutes, lon_seconds; + + while(nexstar_status != NEXSTAR_STATE_IDLE) { + user_wait_ms(1); + }; + + if (l == (GPS_LOCATION_AVERAGE *)NULL) { + l = &rl; + gps_get_location_average(l); + } + + d = l->latitude; + lat_degrees = (char)d; t = (d - (double)lat_degrees) * 60.0; + lat_minutes = (char)t; + lat_seconds = (t - (double)lat_minutes) * 60.0; + d = l->longitude; + lon_degrees = (int)d; t = (d - (double)lon_degrees) * 60.0; + lon_minutes = (int)t; + lon_seconds = (t - (double)lon_minutes) * 60.0; + + nexstar_command = NEXSTAR_SET_LOCATION; + nexstar_command_status = 0; + nexstar_status = NEXSTAR_STATE_BUSY; + rx_buffer_in = 0; + LPC_UART2->FCR = UART2_SET_FCR_CLEAR; + Uart2_puts(cmd, sprintf(cmd, "W%c%c%c%c%c%c%c%c", lat_degrees, lat_minutes, lat_seconds, l->north_south == 'N' ? 0 : 1, lon_degrees, lon_minutes, lon_seconds, l->east_west == 'E' ? 0 : 1)); + rit_timer_set_counter(RIT_TIMER_NEXSTAR, NEXSTAR_SERIAL_TIMEOUT); +} + +/** UART2_IRQHandler(void) + * + * The interrupt service routine for the UART2. + */ +extern "C" void UART2_IRQHandler(void) __irq { + volatile uint32_t iir; + char c; + + /* Get the interrupt identification register which also resets IIR. */ + iir = LPC_UART2->IIR; + + if (iir & 0x1) return; + + iir = (iir >> 1) & 0x3; + + /* Handle the incoming character. */ + if (iir == 2) { + c = LPC_UART2->RBR; + //Uart0_putc(c); + rit_timer_set_counter(RIT_TIMER_NEXSTAR, NEXSTAR_SERIAL_TIMEOUT); + rx_buffer[rx_buffer_in] = c; + rx_buffer_in++; + if (rx_buffer_in >= NEXSTAR_BUFFER_SIZE) { + rx_buffer_in = 0; + } + if (c == '#') { + rit_timer_set_counter(RIT_TIMER_NEXSTAR, 0); + nexstar_command_status = 1; + nexstar_status = NEXSTAR_STATE_IDLE; + } + } +} + +/** Uart2_init + * + * Initialise UART2 to our requirements for Nexstar. + */ +static void Uart2_init (void) { + volatile char c __attribute__((unused)); + + DEBUG_INIT_START; + + LPC_SC->PCONP |= (1UL << 24); + LPC_SC->PCLKSEL1 &= ~(3UL << 16); + LPC_SC->PCLKSEL1 |= (1UL << 16); + LPC_PINCON->PINSEL0 |= ((1UL << 20) | (1UL << 22)); + LPC_UART2->LCR = 0x80; + LPC_UART2->DLM = 0x2; // 115200 baud, for 9600 use 0x2; + LPC_UART2->DLL = 0x71; // 115200 baud, for 9600 use 0x71; + LPC_UART2->LCR = 0x3; + LPC_UART2->FCR = 0x1; + + /* Ensure the FIFO is empty. */ + while (LPC_UART2->LSR & 0x1) c = (char)LPC_UART2->RBR; + + NVIC_SetVector(UART2_IRQn, (uint32_t)UART2_IRQHandler); + NVIC_EnableIRQ(UART2_IRQn); + + /* Enable UART0 RX interrupt only. */ + LPC_UART2->IER = 0x1; + + DEBUG_INIT_END; +} + +static inline void Uart2_putc(char c) { + //Uart0_putc(c); + LPC_UART2->THR = (uint32_t)(c & 0xFF); +} + +static inline void Uart2_puts(char *s, int len) { + int i; + if (len > 0) for (i = 0; len; i++, len--) Uart2_putc(s[i]); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nexstar/nexstar.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,126 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef NEXSTAR_H +#define NEXSTAR_H + +#ifndef NEXSTAR_C +extern bool nexstar_aligned; +#endif + +#define IS_NEXSTAR_ALIGNED nexstar_aligned + +#define NEXSTAR_INIT 0 +#define NEXSTAR_IDLE 1 +#define NEXSTAR_CMD 2 + +/* Nexstar statuses. */ +#define NEXSTAR_STATE_NOT_CONN -1 +#define NEXSTAR_STATE_IDLE 1 +#define NEXSTAR_STATE_BUSY 2 + +/* Statuses for command packets. */ +#define NEXSTAR_SET_TRACKING 1 +#define NEXSTAR_GET_AZMALT 2 +#define NEXSTAR_GET_RADEC 3 +#define NEXSTAR_SET_ELEVATION_RATE 4 +#define NEXSTAR_SET_AZMITH_RATE 5 +#define NEXSTAR_GOTO 6 +#define NEXSTAR_SET_APPROACH 7 +#define NEXSTAR_GOTO_AZM_FAST 8 +#define NEXSTAR_GOTO_ELE_FAST 9 +#define NEXSTAR_IS_ALIGNED 10 +#define NEXSTAR_SET_TIME 11 +#define NEXSTAR_SET_LOCATION 12 +#define NEXSTAR_SYNC 13 + +#define NEXSTAR_BUFFER_SIZE 16 +#define NEXSTAR_SERIAL_TIMEOUT 350 + +/* API functions. */ +void nexstar_get_elazm(double *el, double *azm); + +/* Function prototypes. */ +int _nexstar_set_tracking_mode(int mode); +int _nexstar_get_altazm(void); +int _nexstar_get_radec(void); +void _nexstar_set_elevation_rate_coarse(double rate); +void _nexstar_set_elevation_rate_fine(double rate); +void _nexstar_set_elevation_rate_auto(double rate); +void _nexstar_set_azmith_rate_coarse(double rate); +void _nexstar_set_azmith_rate_fine(double rate); +void _nexstar_set_azmith_rate_auto(double rate); + +int _nexstar_set_elevation_rate(void); +int _nexstar_set_azmith_rate(void); +void _nexstar_set_azm_approach(int approach); + +int _nexstar_goto(uint32_t, uint32_t); +int _nexstar_goto_azm_fast(uint32_t azmith); + +#include "gps.h" +void _nexstar_set_time(GPS_TIME *t); +void _nexstar_set_location(GPS_LOCATION_AVERAGE *l); + +#include "satapi.h" +void _nexstar_sync(RaDec *); + +double nexstar_get_rate_azm(void); +double nexstar_get_rate_alt(void); + +bool _nexstar_is_aligned(void); + +/* Defined in nexstar_align.c */ +void nexstar_force_align(void); + +/* Macros */ + +/* Used to test the IIR register. Common across UARTs. */ +#define UART_ISSET_THRE 0x0002 +#define UART_ISSET_RDA 0x0004 +#define UART_ISSET_CTI 0x000C +#define UART_ISSET_RLS 0x0006 +#define UART_ISSET_FIFOLVL_RXFULL 0x0000000F +#define UART_ISSET_FIFOLVL_TXFULL 0x00000F00 + +/* UART2 peripheral control masks. */ +#define UART2_ORMASK_PCONP 0x01000000 +#define UART2_ORMASK_PCLKSEL1 0x00010000 +#define UART2_ORMASK_PINMODE0 0x00A00000 +#define UART2_ORMASK_PINSEL0 0x00500000 + +/* UART2 register configuration values. */ +#define UART2_SET_LCR 0x00000003 +#define UART2_SET_LCR_DLAB 0x00000083 +#define UART2_SET_DLLSB 0x71 +#define UART2_SET_DLMSB 0x02 +#define UART2_SET_FCR 0x01 +#define UART2_SET_FCR_CLEAR 0x07 +#define UART2_SET_IER 0x01 + +/* Standard API functions. */ +void nexstar_init(void); +void nexstar_process(void); + +/* endif NEXSTAR_H */ +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nexstar/nexstar_align.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,54 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#include "sowb.h" +#include "osd.h" +#include "nexstar.h" +#include "xbox360gamepad.h" +#include "user.h" + +/** nexstar_force_align + * + * On boot-up if main() detects the Nexstar is not aligned + * full control is passed here to force the user to align + * the Nexstar. + */ +void nexstar_force_align(void) { + char c, buf[32]; + + osd_stringl(11, buf, sprintf(buf, " Please align the NexStar")); + osd_stringl(12, buf, sprintf(buf, " Press 'start' when done")); + + do { + c = 0; + while(c != BUTT_START_PRESS) { + c = user_get_button(false); + } + } + while(!_nexstar_is_aligned()); + + osd_clear_line(11); + osd_clear_line(12); + + _nexstar_set_tracking_mode(0); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nexstar/nexstar_old.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,798 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifdef NEVERCOMPILETHIS + +#include "mbed.h" +#include "nexstar.h" +#include "utils.h" +#include "debug.h" +#include "main.h" + +DigitalOut led1(LED1); +DigitalOut led2(LED2); +DigitalOut led3(LED3); +DigitalOut led4(LED4); + +/* The main place holder data structure for the Nexstar. */ +NEXSTAR_DATA nexstar; + +/* A timer to look for serial comms failure. */ +OneMS timeout; + +/** nexstar_process(void) + * + * Standard module _process function. + */ +void nexstar_process(void) { + int i, j, q; + signed char status, type; + + BLAT4; + + /* Multiple queued requests will start automatically after the previous + request (see the ISR for details). However, it is possible that when + the ISR detects the completion of a request there are, at that time, + no more pending requests in the queue. So loop over the request queue + and if none are in progress, initiate a request transfer to the Nexstar. */ + if (! nexstar_request_count_status(NEXSTAR_REQUEST_IN_PROGRESS)) { + if (nexstar_request_count_status(NEXSTAR_REQUEST_PENDING)) { + for (i = 0, q = nexstar.currentRequest; i < NEXSTAR_NUM_OF_PACKETS; i++) { + if (nexstar.commsPackets[q].requestStatus == NEXSTAR_REQUEST_PENDING) { + nexstar.currentRequest = q; + nexstar_send_request(q); + i = NEXSTAR_NUM_OF_PACKETS; + } + else { + NEXSTAR_NEXT_REQUEST(q); + } + } + } + } + + /* look through all the comms request packets and see if any need processing. */ + /* + for (i = 0; i < NEXSTAR_NUM_OF_PACKETS; i++) { + status = nexstar.commsPackets[i].requestStatus; + type = nexstar.commsPackets[i].requestType; + if (status == NEXSTAR_REQUEST_TIMEOUT) { + for (j = 0; j < NEXSTAR_NUM_OF_PACKETS; j++) { + REQUEST_SET_PACKET_STATUS(j, NEXSTAR_REQUEST_IDLE); + nexstar_request_packet_reset(&nexstar.commsPackets[j]); + } + NEXSTAR_SET_STATUS(NEXSTAR_NOT_CONNECTED); + } + else if (status == NEXSTAR_REQUEST_COMPLETE) { + switch (type) { + case NEXSTAR_ECHO_COMMS: + nexstar_request_echo(NEXSTAR_PROCESS_REQUEST, i); + break; + case NEXSTAR_ASK_IS_ALIGNED: + nexstar_request_get_aligned(NEXSTAR_PROCESS_REQUEST, i); + break; + case NEXSTAR_ASK_ALTAZM_POSITION: + nexstar_request_get_altazm(NEXSTAR_PROCESS_REQUEST, i); + break; + } + } + } + */ + + if (nexstar.commsPackets[nexstar.currentRequest].requestStatus; == NEXSTAR_REQUEST_COMPLETE) { + switch (type) { + case NEXSTAR_ECHO_COMMS: + nexstar_request_echo(NEXSTAR_PROCESS_REQUEST, nexstar.currentRequest); + break; + case NEXSTAR_ASK_IS_ALIGNED: + nexstar_request_get_aligned(NEXSTAR_PROCESS_REQUEST, nexstar.currentRequest); + break; + case NEXSTAR_ASK_ALTAZM_POSITION: + nexstar_request_get_altazm(NEXSTAR_PROCESS_REQUEST, nexstar.currentRequest); + break; + } + } + + /* If the Nexstar is in an unknown state attempt to ask it for + alignment. Once we get a positive response we at least know + a Nexstar is connected and responding. Until we have that + knowledge there is little else we can do. */ + switch(nexstar.status) { + case NEXSTAR_NOT_CONNECTED: + if (! nexstar_request_count_request_type(NEXSTAR_ECHO_COMMS)) { + Uart2_flush_rxfifo(); + nexstar_request_echo(NEXSTAR_SEND_REQUEST, 0); + } + return; + + case NEXSTAR_CONNECTED: + case NEXSTAR_NOT_ALIGNED: + if (! nexstar_request_count_request_type(NEXSTAR_ASK_IS_ALIGNED)) { + Uart2_flush_rxfifo(); + nexstar_request_get_aligned(NEXSTAR_SEND_REQUEST, 0); + } + return; + + default: + debug.printf("I don't know what to do! status is %d\r\n", nexstar.status); + break; + } + + /* As possible as often, request the Nexstar's pointing position. */ + if (! nexstar_request_count_request_type(NEXSTAR_ASK_ALTAZM_POSITION)) { + nexstar_request_get_altazm(NEXSTAR_SEND_REQUEST, 0); + } + + +} + +/** nexstar_init(void) + * + * Standard module _init function. + */ +void nexstar_init(void) { + + /* Setup the global mode of this Nexstar. */ + NEXSTAR_SET_STATUS(NEXSTAR_NOT_CONNECTED); + + /* Initialise the comms packets and buffers. */ + nexstar.currentRequest = 0; + nexstar.availableRequest = 0; + for (int i = 0; i < NEXSTAR_NUM_OF_PACKETS; i++) { + nexstar_request_packet_reset(&nexstar.commsPackets[i]); + //nexstar.commsPackets[i].requestType = 0; + //nexstar.commsPackets[i].requestStatus = NEXSTAR_REQUEST_IDLE; + //nexstar.commsPackets[i].bufferPointer = 0; + //nexstar.commsPackets[i].callback = NULL; + //memset(nexstar.commsPackets[i].buffer, 0, NEXSTAR_PACKET_BUFFER_SIZE); + } + + /* Prepare the one-shot timeout timers. */ + timeout.mode(ONEMS_MODE_TIMEOUT_CALLBACK); + timeout.attach(nexstar_timeout); + + /* Initialise the UART we use. */ + Uart2_init(); +} + +/** nexstar_request_packet_reset + * + * Return a request packet back to default state. + * + * @param NEXSTAR_COMMS_PACKET *p A pointer to the packet to reset. + */ +void nexstar_request_packet_reset(NEXSTAR_COMMS_PACKET *p) { + p->requestType = 0; + p->bufferPointer = 0; + p->callback = NULL; + memset(p->buffer, 0, NEXSTAR_PACKET_BUFFER_SIZE); + p->requestStatus = NEXSTAR_REQUEST_IDLE; +} + +/** nexstar_p(void) + * + * Get a pointer to the data structure for the Nexstar. + * Used by the API to get data. + */ +NEXSTAR_DATA * nexstar_p(void) { + return &nexstar; +} + +/** nexstar_request_count_request_type(char requestType) + * + * Used to find out if any of the packets are currently marked as the supplied request type. + * + * @param char The status to test. + * @return bool True otherwise false + */ +int nexstar_request_count_request_type(char requestType) { + int count, i; + + for (count = 0, i = 0; i < NEXSTAR_NUM_OF_PACKETS; i++) { + if (nexstar.commsPackets[i].requestType == requestType) { + count++;; + } + } + return count; +} + +/** nexstar_request_count_status (char status) + * + * Used to find out if any of the packets are currently marked as the supplied status. + * + * @param char The status to test. + * @return bool True otherwise false + */ +int nexstar_request_count_status(char status) { + int count, i; + + for (count = 0, i = 0; i < NEXSTAR_NUM_OF_PACKETS; i++) { + if (nexstar.commsPackets[i].requestStatus == status) { + count++;; + } + } + return count; +} + +/** nexstar_timeout(class OneMS *q) + * + * A callback for the timeout timer. + * + * @param pointer class OneMS that invoked the callback. + */ +void nexstar_timeout(class OneMS *q) { + q->stop(); /* Ensure we stop this timer. */ + + /* Mark this request timed out. */ + REQUEST_SET_PACKET_STATUS(nexstar.currentRequest, NEXSTAR_REQUEST_TIMEOUT); +} + +/** nexstar_request_get_altazm(int mode, unsigned char handle) + * + * Used to either create a request to get the current AltAzm position of the Nextsra + * or to process a previously completed request. + * + * @param int mode Determine what action to create, queue request or process packet. + * @param unsigned char handle If processing a request this is the index of the packet to be processed. + * @return zero on failure or error, non-zero otherwise. + */ +int nexstar_request_get_altazm(int mode, unsigned char handle) { + + /* Create a request to get the ALT/AZM and queue it. */ + if (mode == NEXSTAR_SEND_REQUEST) { + REQUEST_HANDLE; + nexstar.commsPackets[handle].buffer[0] = 'Z'; + REQUEST_SET(NEXSTAR_ASK_ALTAZM_POSITION, 1); + led3 = 1; + return 1; + } + + /* Given a completed request, parse the data and update our information. */ + if (mode == NEXSTAR_PROCESS_REQUEST) { + if (nexstar.commsPackets[handle].requestStatus != NEXSTAR_REQUEST_COMPLETE) return 0; + char *buffer = nexstar.commsPackets[handle].buffer; + REQUEST_BUFFER_CHECK(9, 0); + nexstar.currentAltRaw = hex2bin(buffer + 5, 4); + nexstar.currentAlt = (double)(((double)nexstar.currentAltRaw / 65536.) * 360.); + nexstar.currentAzmRaw = hex2bin(buffer + 0, 4); + nexstar.currentAzm = (double)(((double)nexstar.currentAzmRaw / 65536.) * 360.); + nexstar_request_packet_reset(&nexstar.commsPackets[handle]); + REQUEST_SET_PACKET_STATUS(handle, NEXSTAR_REQUEST_IDLE); + led3 = 0; + return 1; + } + + return 0; +} + +/** nexstar_request_get_aligned(int mode, unsigned char handle) + * + * Used to either create a request to check teh Nexstar is aligned + * or to process a previously completed request. + * + * @param int mode Determine what action to create, queue request or process packet. + * @param unsigned char handle If processing a request this is the index of the packet to be processed. + * @return zero on failure or error, non-zero otherwise. + */ +int nexstar_request_get_aligned(int mode, unsigned char handle) { + + /* Create a request to get the ALT/AZM and queue it. */ + if (mode == NEXSTAR_SEND_REQUEST) { + REQUEST_HANDLE; + nexstar.commsPackets[handle].buffer[0] = 'J'; + nexstar.commsPackets[handle].timeout = 2000; + REQUEST_SET(NEXSTAR_ASK_IS_ALIGNED, 1); + led2 = 1; + return 1; + } + + /* Given a completed request, parse the data and update our information. */ + if (mode == NEXSTAR_PROCESS_REQUEST) { + if (nexstar.commsPackets[handle].requestStatus == NEXSTAR_REQUEST_TIMEOUT) { + NEXSTAR_SET_STATUS(NEXSTAR_NOT_CONNECTED); + nexstar_request_packet_reset(&nexstar.commsPackets[handle]); + led2 = 0; + return 0; + } + if (nexstar.commsPackets[handle].requestStatus != NEXSTAR_REQUEST_COMPLETE) return 0; + char *buffer = nexstar.commsPackets[handle].buffer; + REQUEST_BUFFER_CHECK(1, 0); + NEXSTAR_SET_STATUS((buffer[0] == 1) ? NEXSTAR_ALIGNED : NEXSTAR_NOT_ALIGNED); + nexstar_request_packet_reset(&nexstar.commsPackets[handle]); + REQUEST_SET_PACKET_STATUS(handle, NEXSTAR_REQUEST_IDLE); + led2 = 0; + return 1; + } + + return 0; +} + +/** nexstar_request_echo(int mode, unsigned char handle) + * + * Used to either echo a data byte off the Nexstar. + * + * @param int mode Determine what action to create, queue request or process packet. + * @param unsigned char handle If processing a request this is the index of the packet to be processed. + * @return zero on failure or error, non-zero otherwise. + */ +int nexstar_request_echo(int mode, unsigned char handle) { + + /* Create a request to get the ALT/AZM and queue it. */ + if (mode == NEXSTAR_SEND_REQUEST) { + REQUEST_HANDLE; + nexstar.commsPackets[handle].buffer[0] = 'K'; + nexstar.commsPackets[handle].buffer[1] = 'k'; + nexstar.commsPackets[handle].timeout = 2000; + REQUEST_SET(NEXSTAR_ECHO_COMMS, 2); + led1 = 1; + return 1; + } + + /* Given a completed request, parse the data and update our information. */ + if (mode == NEXSTAR_PROCESS_REQUEST) { + led3 = 1; + if (nexstar.commsPackets[handle].requestStatus == NEXSTAR_REQUEST_TIMEOUT) { + NEXSTAR_SET_STATUS(NEXSTAR_NOT_CONNECTED); + nexstar_request_packet_reset(&nexstar.commsPackets[handle]); + led1 = 0; + return 0; + } + if (nexstar.commsPackets[handle].requestStatus != NEXSTAR_REQUEST_COMPLETE) return 0; + char *buffer = nexstar.commsPackets[handle].buffer; + REQUEST_BUFFER_CHECK(1, 0); + if (buffer[0] == 'k') debug.printf("YES! "); + else debug.printf("NO! "); + + NEXSTAR_SET_STATUS((buffer[0] == 'k') ? NEXSTAR_CONNECTED : NEXSTAR_NOT_CONNECTED); + nexstar_request_packet_reset(&nexstar.commsPackets[handle]); + REQUEST_SET_PACKET_STATUS(handle, NEXSTAR_REQUEST_IDLE); + led1 = 0; + return 1; + } + + return 0; +} + +/** nexstar_request_set_tracking_mode(int mode, unsigned char handle, char tracking) + * + * Used to set the tracking mode of the Nexstar + * + * @param int mode Determine what action to create, queue request or process packet. + * @param unsigned char handle If processing a request this is the index of the packet to be processed. + * @param char tracking The mode to send. + * @return zero on failure or error, non-zero otherwise. + */ +int nexstar_request_set_tracking_mode(int mode, unsigned char handle, char tracking) { + + /* Create request and queue. */ + if (mode == NEXSTAR_SEND_REQUEST) { + REQUEST_HANDLE; + nexstar.commsPackets[handle].buffer[0] = 'T'; + nexstar.commsPackets[handle].buffer[1] = tracking; + REQUEST_SET(NEXSTAR_SET_TRACKING, 2); + return 1; + } + + /* Given a completed request, parse the data and update our information. */ + if (mode == NEXSTAR_PROCESS_REQUEST) { + if (nexstar.commsPackets[handle].requestStatus != NEXSTAR_REQUEST_COMPLETE) return 0; + char *buffer = nexstar.commsPackets[handle].buffer; + REQUEST_BUFFER_CHECK(0, 0); + nexstar_request_packet_reset(&nexstar.commsPackets[handle]); + REQUEST_SET_PACKET_STATUS(handle, NEXSTAR_REQUEST_IDLE); + return 1; + } + + return 0; +} + +/** nexstar_request_get_tracking_mode(int mode, unsigned char handle) + * + * Used to find out what tracking mode Nexstar is in. + * + * @param int mode Determine what action to create, queue request or process packet. + * @param unsigned char handle If processing a request this is the index of the packet to be processed. + * @return zero on failure or error, non-zero otherwise. + */ +int nexstar_request_get_tracking_mode(int mode, unsigned char handle) { + + /* Create request and queue. */ + if (mode == NEXSTAR_SEND_REQUEST) { + REQUEST_HANDLE; + nexstar.commsPackets[handle].buffer[0] = 't'; + REQUEST_SET(NEXSTAR_ASK_TRACKING, 1); + return 1; + } + + /* Given a completed request, parse the data and update our information. */ + if (mode == NEXSTAR_PROCESS_REQUEST) { + if (nexstar.commsPackets[handle].requestStatus != NEXSTAR_REQUEST_COMPLETE) return 0; + char *buffer = nexstar.commsPackets[handle].buffer; + REQUEST_BUFFER_CHECK(1, 0); + nexstar.trackingMode = buffer[0]; + nexstar_request_packet_reset(&nexstar.commsPackets[handle]); + REQUEST_SET_PACKET_STATUS(handle, NEXSTAR_REQUEST_IDLE); + return 1; + } + + return 0; +} + +/** nexstar_request_set_slew(int mode, unsigned char handle, double alt, double azm) + * + * Used to set a variable slew rate. + * + * @param int mode Determine what action to create, queue request or process packet. + * @param unsigned char handle If processing a request this is the index of the packet to be processed. + * @param double alt The alt slew rate in degrees per second. + * @param double azm The azm slew rate in degrees per second. + * @return zero on failure or error, non-zero otherwise. + */ +int nexstar_request_set_slew(int mode, unsigned char handle, double alt, double azm) { + int i; + + /* Create request and queue. */ + if (mode == NEXSTAR_SEND_REQUEST) { + REQUEST_HANDLE; + nexstar.commsPackets[handle].buffer[0] = 'P'; + nexstar.commsPackets[handle].buffer[1] = '\x3'; + nexstar.commsPackets[handle].buffer[2] = '\x11'; + nexstar.commsPackets[handle].buffer[3] = alt > 0 ? '\x6' : '\x7'; + i = ((int)(alt * 3600.)) * 4; + nexstar.commsPackets[handle].buffer[4] = (char)((i & 0xFF00) >> 8); + nexstar.commsPackets[handle].buffer[5] = (char)(i & 0xFF); + nexstar.commsPackets[handle].buffer[6] = '\0'; + nexstar.commsPackets[handle].buffer[7] = '\0'; + REQUEST_SET(NEXSTAR_SET_ALT_RATE, 8); + + REQUEST_HANDLE; + nexstar.commsPackets[handle].buffer[0] = 'P'; + nexstar.commsPackets[handle].buffer[1] = '\x3'; + nexstar.commsPackets[handle].buffer[2] = '\x10'; + nexstar.commsPackets[handle].buffer[3] = azm > 0 ? '\x6' : '\x7'; + i = ((int)(azm * 3600.)) * 4; + nexstar.commsPackets[handle].buffer[4] = (char)((i & 0xFF00) >> 8); + nexstar.commsPackets[handle].buffer[5] = (char)(i & 0xFF); + nexstar.commsPackets[handle].buffer[6] = '\0'; + nexstar.commsPackets[handle].buffer[7] = '\0'; + REQUEST_SET(NEXSTAR_SET_AZM_RATE, 8); + return 1; + } + + /* Given a completed request, parse the data and update our information. */ + if (mode == NEXSTAR_PROCESS_REQUEST) { + if (nexstar.commsPackets[handle].requestStatus != NEXSTAR_REQUEST_COMPLETE) return 0; + char *buffer = nexstar.commsPackets[handle].buffer; + REQUEST_BUFFER_CHECK(0, 0); + nexstar_request_packet_reset(&nexstar.commsPackets[handle]); + REQUEST_SET_PACKET_STATUS(handle, NEXSTAR_REQUEST_IDLE); + return 1; + } + + return 0; +} + +/** nexstar_request_set_location(int mode, unsigned char handle, NEXSTAR_LOCATION *location) + * + * Used to set the Nexstar's location. + * + * @param int mode Determine what action to create, queue request or process packet. + * @param unsigned char handle If processing a request this is the index of the packet to be processed. + * @param NEXSTAR_LOCATION *location A pointer to a data struct holding the data. + * @return zero on failure or error, non-zero otherwise. + */ +int nexstar_request_set_location(int mode, unsigned char handle, NEXSTAR_LOCATION *location) { + + /* Create request and queue. */ + if (mode == NEXSTAR_SEND_REQUEST) { + REQUEST_HANDLE; + nexstar.commsPackets[handle].buffer[0] = 'W'; + memcpy((char *)nexstar.commsPackets[handle].buffer + 1, (char *)location, 8); + REQUEST_SET(NEXSTAR_SET_LOCATION, 9); + return 1; + } + + /* Given a completed request, parse the data and update our information. */ + if (mode == NEXSTAR_PROCESS_REQUEST) { + if (nexstar.commsPackets[handle].requestStatus != NEXSTAR_REQUEST_COMPLETE) return 0; + char *buffer = nexstar.commsPackets[handle].buffer; + REQUEST_BUFFER_CHECK(1, 0); + nexstar.trackingMode = buffer[0]; + nexstar_request_packet_reset(&nexstar.commsPackets[handle]); + REQUEST_SET_PACKET_STATUS(handle, NEXSTAR_REQUEST_IDLE); + return 1; + } + + return 0; +} + +/** nexstar_request_set_time(int mode, unsigned char handle, NEXSTAR_TIME *time) + * + * Used to set the Nexstar time. + * + * @param int mode Determine what action to create, queue request or process packet. + * @param unsigned char handle If processing a request this is the index of the packet to be processed. + * @param NEXSTAR_TIME *time A pointer to a data struct holding the data. + * @return zero on failure or error, non-zero otherwise. + */ +int nexstar_request_set_time(int mode, unsigned char handle, NEXSTAR_TIME *time) { + + /* Create request and queue. */ + if (mode == NEXSTAR_SEND_REQUEST) { + REQUEST_HANDLE; + nexstar.commsPackets[handle].buffer[0] = 'H'; + memcpy((char *)nexstar.commsPackets[handle].buffer + 1, (char *)time, 8); + REQUEST_SET(NEXSTAR_SET_TIME, 9); + return 1; + } + + /* Given a completed request, parse the data and update our information. */ + if (mode == NEXSTAR_PROCESS_REQUEST) { + if (nexstar.commsPackets[handle].requestStatus != NEXSTAR_REQUEST_COMPLETE) return 0; + char *buffer = nexstar.commsPackets[handle].buffer; + REQUEST_BUFFER_CHECK(0, 0); + nexstar_request_packet_reset(&nexstar.commsPackets[handle]); + REQUEST_SET_PACKET_STATUS(handle, NEXSTAR_REQUEST_IDLE); + return 1; + } + + return 0; +} + +/** nexstar_request_get_version(int mode, unsigned char handle) + * + * Used to set the Nexstar software version. + * + * @param int mode Determine what action to create, queue request or process packet. + * @param unsigned char handle If processing a request this is the index of the packet to be processed. + * @return zero on failure or error, non-zero otherwise. + */ +int nexstar_request_get_version(int mode, unsigned char handle) { + + /* Create request and queue. */ + if (mode == NEXSTAR_SEND_REQUEST) { + REQUEST_HANDLE; + nexstar.commsPackets[handle].buffer[0] = 'V'; + REQUEST_SET(NEXSTAR_ASK_VERSION, 1); + return 1; + } + + /* Given a completed request, parse the data and update our information. */ + if (mode == NEXSTAR_PROCESS_REQUEST) { + if (nexstar.commsPackets[handle].requestStatus != NEXSTAR_REQUEST_COMPLETE) return 0; + char *buffer = nexstar.commsPackets[handle].buffer; + REQUEST_BUFFER_CHECK(2, 0); + nexstar.version = (buffer[0] << 8) | buffer[1]; + nexstar_request_packet_reset(&nexstar.commsPackets[handle]); + REQUEST_SET_PACKET_STATUS(handle, NEXSTAR_REQUEST_IDLE); + return 1; + } + + return 0; +} + +/** nexstar_request_raw(int mode, unsigned char handle, NEXSTAR_COMMS_PACKET *q) + * + * Used for external callers to setup a REQUEST based on an externally defined packet structure. + * + * This function allows other parts of the system to make Nextstar requests that are not covered + * by the API or just want to handle a request via a callback. + * + * @param int mode Determine what action to create, queue request or process packet. + * @param unsigned char handle If processing a request this is the index of the packet to be processed. + * @param pointer A pointer to a predefined comms request packet to copy into our queue. + * @return zero on failure or error, non-zero otherwise. + */ +int nexstar_request_raw(int mode, unsigned char handle, NEXSTAR_COMMS_PACKET *q) { + + /* Create request and queue. */ + if (mode == NEXSTAR_SEND_REQUEST) { + /* Externally handled requests must have a callback defined as a completion handler. */ + if (q->callback == NULL) { + return 0; + } + REQUEST_HANDLE; + memcpy(&nexstar.commsPackets[handle], q, sizeof(NEXSTAR_COMMS_PACKET)); + REQUEST_SET(NEXSTAR_REQUEST_RAW, 0); + return 1; + } + + /* Given a completed request, parse the data and update our information. */ + if (mode == NEXSTAR_PROCESS_REQUEST) { + if (nexstar.commsPackets[handle].requestStatus != NEXSTAR_REQUEST_COMPLETE) return 0; + if (nexstar.commsPackets[handle].callback != NULL) { + (nexstar.commsPackets[handle].callback)(&nexstar.commsPackets[handle]); + } + nexstar_request_packet_reset(&nexstar.commsPackets[handle]); + REQUEST_SET_PACKET_STATUS(handle, NEXSTAR_REQUEST_IDLE); + return 1; + } + + return 0; +} + + +/** nexstar_send_request(int handle) + * + * Used to send a request packet to Nexstar via the serial port. + * + * @param int handle The packet to send. + * @return zero on failure, non-zero otherwise. + */ +int nexstar_send_request(int handle) { + if (nexstar.commsPackets[handle].requestStatus == NEXSTAR_REQUEST_PENDING) { + nexstar.commsPackets[handle].requestStatus = NEXSTAR_REQUEST_IN_PROGRESS; + if (Uart2_puts(nexstar.commsPackets[handle].buffer, (int)nexstar.commsPackets[handle].txLength) != 0) { + memset(nexstar.commsPackets[handle].buffer, 0, NEXSTAR_PACKET_BUFFER_SIZE); + nexstar.commsPackets[handle].bufferPointer = 0; + // Note, we only start the timeout timer AFTER the TxFIFO goes empty, see below. + return 1; + } + else { + /* If we failed to fill the Tx FIFo then switch this request back to pending. */ + REQUEST_SET_PACKET_STATUS(handle, NEXSTAR_REQUEST_PENDING); + return 0; + } + } + return 0; +} + +/** UART2_IRQHandler(void) + * + * The interrupt service routine for the UART2. + */ +extern "C" void UART2_IRQHandler(void) { + char c; + uint32_t iir; + + /* Get the interrupt identification register which also resets IIR. */ + iir = LPC_UART2->IIR; + + if (iir & 0x0001) { + /* Eh? Then why did we interrupt? */ + return; + } + + /* Do we have incoming data? */ + if (iir & UART_ISSET_RDA) { + c = (char)LPC_UART2->RBR; + //debug.printf(" %c", c & 0x7f); + if (nexstar.commsPackets[nexstar.currentRequest].requestStatus != NEXSTAR_REQUEST_IN_PROGRESS) { + return; + } + nexstar.commsPackets[nexstar.currentRequest].buffer[nexstar.commsPackets[nexstar.currentRequest].bufferPointer] = c; + nexstar.commsPackets[nexstar.currentRequest].bufferPointer++; + nexstar.commsPackets[nexstar.currentRequest].bufferPointer &= (NEXSTAR_PACKET_BUFFER_SIZE-1); + if (c == '#' || c == '\r' || c == '\n') { + timeout.stop(); /* Halt the timeout timer. */ + REQUEST_SET_PACKET_STATUS(nexstar.currentRequest, NEXSTAR_REQUEST_COMPLETE); + + /* Advance to the next request packet and if pending start it. */ + //NEXSTAR_NEXT_REQUEST(nexstar.currentRequest); + //nexstar_send_request(nexstar.currentRequest); + //debug.printf("\r\n"); + } + } + + /* If the THRE goes empty AND the TxFIFO is also empty then a command + was just sent to the Nexstar. Start the serial timeout timer so we + only make a timeout measurement AFTER we have sent our command. + That way we don't include our serial transmit time within the timeout + specified by the timer. */ + if (iir & UART_ISSET_THRE) { + if ((LPC_UART2->FIFOLVL & UART_ISSET_FIFOLVL_TXFULL) == 0) { + timeout.start(nexstar.commsPackets[nexstar.currentRequest].timeout == 0 ? NEXSTAR_SERIAL_TIMEOUT : (uint32_t)nexstar.commsPackets[nexstar.currentRequest].timeout); + } + } + + if (iir & UART_ISSET_RLS) { + // Do nothing for now other than read the iir register and clear the interrupt. + } +} + +/** Uart2_init + * + * Initialise UART2 to our requirements for Nexstar. + */ +void Uart2_init (void) { + + /* Switch on UART2. */ + LPC_SC->PCONP |= UART2_ORMASK_PCONP; + + /* Set PCLK == CCLK, 96Mhz */ + LPC_SC->PCLKSEL1 |= UART2_ORMASK_PCLKSEL1; + + /* Enable the tx/rx to pins and select pin mode. */ + LPC_PINCON->PINSEL0 |= UART2_ORMASK_PINSEL0; + LPC_PINCON->PINMODE0 |= UART2_ORMASK_PINMODE0; + + /* Set the divisor values for 9600 and then set 8,n,1 */ + LPC_UART2->LCR = UART2_SET_LCR_DLAB; + LPC_UART2->DLL = UART2_SET_DLLSB; + LPC_UART2->DLM = UART2_SET_DLMSB; + LPC_UART2->LCR = UART2_SET_LCR; + + /* Enable FIFOs and then clear them. */ + LPC_UART2->FCR = UART2_SET_FCR; + LPC_UART2->FCR = UART2_SET_FCR_CLEAR; + + /* Enable the RDA and THRE interrupts. */ + LPC_UART2->IER = UART2_SET_IER; + + /* Now it's time to do interrupts. */ + NVIC_SetVector(UART2_IRQn, (uint32_t)UART2_IRQHandler); + NVIC_EnableIRQ(UART2_IRQn); +} + +/** Uart2_flush_rxfifo + * + * Flush the input RX fifo to make sure it's empty. + */ +void Uart2_flush_rxfifo(void) { + uint8_t c; + while (LPC_UART2->LSR & 0x1) { + c = LPC_UART2->RBR; + } +} + +/** Uart2_putc + * + * Put the character given into the TxFIFO. + * By design there should always be room in + * the fifo, but check it to make sure. + * + * @param char The character to write. + * @return int zero on failure, non-zero otherwise. + */ +int Uart2_putc(char c) { + /* Check the TxFIFO is not full. */ + if ((LPC_UART2->FIFOLVL & UART_ISSET_FIFOLVL_TXFULL) != 0) return 0; + LPC_UART2->THR = (uint8_t)c; + return -1; +} + +/** Uart2_puts + * + * Put the string given into the TX FIFO. + * By design there should always be room in + * the fifo, but check it to make sure. + * + * @param char *s Pointer The string to write. + * @return int zero on failure, non-zero (number of chars written) otherwise. + */ +int Uart2_puts(char *s, int len) { + int i; + + /* Check the FIFO is empty, as it should always be by design. */ + if ((LPC_UART2->FIFOLVL & UART_ISSET_FIFOLVL_TXFULL) == 0) { + for (i = 0; i < len; i++) { + LPC_UART2->THR = (uint8_t)s[i]; + debug.printf("%c", s[i]); + } + debug.printf("\r\n"); + } + else { + return 0; + } + return i; +} + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/osd/MAX7456.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,374 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +/* + Design notes. + The MAX7456 is connected to SSP1 on the Mbed. Additionally, the vertical sync + is connected to Pxx, horizontal sync to Pxx, LOS to Pxx, RST to Pxx. These IO + pins are setup and macros made available via gpio.c and the interrupts (vsync) + via gpioirq.c so for information regarding those see those modules. +*/ + +#include "sowb.h" +#include "gpio.h" +#include "gpioirq.h" +#include "utils.h" +#include "user.h" +#include "MAX7456.h" +#include "MAX7456_chars.h" +#include "debug.h" + +/* Forward local function prototypes. */ +static void SSP1_init(void); + +/* Declare the custom character map (CM) definitions. + See MAX7456_chars.c for more details. */ +extern MAX7456_CUSTOM_CHAR custom_chars[]; + +/* Map ASCII table to the MAX7456 character map. + Note, the MAX7456 in-built character map is no where near the ascii + table mapping and very few characters are abailable to map. Where + possible we create new characters for those we need that are missing + from the MAX7456 that we want to use and also we create some special + characters of our own that are not ASCII chars (crosshair for example). + These additional character definitions are listed below the table. + Character maps we have create can be found in MAX7456_chars.c */ +const unsigned char MAX7456_ascii[256] = { + + /* Regular ASCII table. */ + /* 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F */ + /* 00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 20 */ 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x46, 0x3F, 0x40, 0x00, 0x4d, 0x45, 0x49, 0x41, 0x47, + /* 30 */ 0x0A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x44, 0x43, 0x4A, 0x00, 0x4B, 0x42, + /* 40 */ 0x4C, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + /* 50 */ 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0X1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 60 */ 0x46, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, + /* 70 */ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* Extended ASCII table. */ + /* 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F */ + /* 80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* B0 */ 0xB0, 0x00, 0x00, 0xB3, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, + /* C0 */ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xDA, 0x00, 0x00, 0x00, 0x00, 0x00, + /* E0 */ 0xe0, 0xe1, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/** MAX7456_map_char + * + * Convert the supplied ASCII character to a MAX7456 character. + * Note, the MAX7456 does not support all ASCII chars. Those it + * cannot convert are converted to spaces. Proceedure is a simple + * table look-up. + * + * @See const unsigned char MAX7456_ascii + * + * @param unsigned char c The character to convert. + * @return unsigned char The converted character. + */ +unsigned char MAX7456_map_char(unsigned char c) { + return MAX7456_ascii[c]; +} + +/** MAX7456_init + */ +void MAX7456_init(void) { + + /* Setup SSP1 to interface to the MAX7456 chip. */ + SSP1_init(); + + DEBUG_INIT_START; + + /* Reset the MAX7456 device. */ + MAX7456_RST_ASSERT; + user_wait_ms_blocking(100); + MAX7456_RST_DEASSERT; + user_wait_ms_blocking(100); + + /* Write the custom CM map. */ + MAX7456_write_byte(0, MAX7456_read_byte(0) & 0xF7); + for (int index = 0; custom_chars[index].ascii != 0; index++) { + MAX7456_write_char_map(custom_chars[index].ascii, custom_chars[index].map); + } + user_wait_ms_blocking(100); + + /* Change the vertical offset. */ + MAX7456_write_byte(0x3, 0x16); + + /* Enable display of OSD image. */ + MAX7456_write_byte(0x0, 0x48); + + DEBUG_INIT_END; +} + +/** MAX7456_vsync_fall + * + * Interrupt handler for the vertical sync signal from the MAX7456 chip. + * Note, this is called from gpioirq.c module which handles GPIO interrupts. + */ +void osd_vsync(void); +void MAX7456_vsync_fall(void) { + osd_vsync(); +} + +/** MAX7456_vsync_rise + * + * Interrupt handler for the vertical sync signal from the MAX7456 chip. + * Note, this is called from gpioirq.c module which handles GPIO interrupts. + */ +void MAX7456_vsync_rise(void) { + // Does nothing. +} + +/** MAX7456_write_byte + * + * Used to write a byte to a specific address. + * This function also doubles up to allow a byte + * to be written without an address (less than 0x80) + * and this is used to make 16bit transfer from two + * 8bit transfers or to construct continuous 8bit + * transfer where the MAX7456 auto-increments an + * internal location pointer on each write operation. + * + * Note, this function effectivly "blocks". However, the + * speed of the SSP serial bus is pretty high to say the + * least and experimentation has show it, so far, to have + * had no adverse effects. + * + * @param unsigned char address The register address to write to. + * @param unsigned char byte The byte to write to teh register. + */ +void MAX7456_write_byte(unsigned char address, unsigned char byte) { + volatile int dev_null __attribute__((unused)); + + MAX7456_CS_ASSERT; + + /* MAX7456 addresses are always less than 0x80 so if the + address is > 0x7F then the caller is requesting an direct + 8bit data transfer. */ + if (address < 0x80) { + LPC_SSP1->DR = (uint32_t)(address & 0xFF); + while(LPC_SSP1->SR & 0x10); + dev_null = LPC_SSP1->DR; + } + + LPC_SSP1->DR = (uint32_t)byte & 0xFF; + while(LPC_SSP1->SR & 0x10); + dev_null = LPC_SSP1->DR; + + MAX7456_CS_DEASSERT; +} + +/** MAX7456_read_byte + * + * Read a byte from a specific address. + * + * Note, this function effectivly "blocks". However, the + * speed of the SSP serial bus is pretty high to say the + * least and experimentation has show it, so far, to have + * had no adverse effects. + * + * @param unsigned char address The address of the register to read. + * @return int data The value of the register addressed. + */ +int MAX7456_read_byte(unsigned char address) { + int data; + + MAX7456_CS_ASSERT; + + LPC_SSP1->DR = (uint32_t)address & 0xFF; + while(LPC_SSP1->SR & 0x10); + data = LPC_SSP1->DR; /* Discarded. */ + + LPC_SSP1->DR = 0; + while(LPC_SSP1->SR & 0x10); + data = LPC_SSP1->DR & 0xFF; + + MAX7456_CS_DEASSERT; + + return data; +} + +/** MAX7456_cursor + * + * Move the MAX7456 "cursor" (next display memory write) + * to the specified position. + * + * @param int x The X position. + * @param int y The Y position. + */ +void MAX7456_cursor(int x, int y) { + int pos = (y * 30) + x; + MAX7456_write_byte(0x05, (unsigned char)((pos >> 8) & 0xFF)); + MAX7456_write_byte(0x06, (unsigned char)(pos & 0xFF)); +} + +/** MAX7456_convert_string + * + * Convert the NULL terminated raw string to MAX7456 character set compat bytes. + * Note, alters the string passed, doesn't make a copy of the string so cannot + * be a const value. + * + * @param unisgned char *s A pointer to the string to convert. + */ +void MAX7456_convert_string(unsigned char *s) { + while(*(s)) { + *(s) = MAX7456_ascii[*(s)]; + s++; + } +} + +/** MAX7456_string + * + * Send the NULL terminated ASCII string to the display memory. + * + * @param unisgned char *s A pointer to the ASCII string to write. + */ +void MAX7456_string(unsigned char *s) { + MAX7456_write_byte(0x04, 0x01); /* Enable 8bit write */ + while(*(s)) { + MAX7456_write_byte(0x80, MAX7456_map_char(*s++)); + } + MAX7456_write_byte(0x80, 0xFF); +} + +/** MAX7456_stringl + * + * Send the ASCII string to the display memory. A null will terminate the write. + * + * @param int x The X position to write the string to. + * @param int y The Y position to write the string to. + * @param unisgned char *s A pointer to the string to write. + * @param int len The length of the string to send. + */ +void MAX7456_stringl(int x, int y, unsigned char *s, int len) { + MAX7456_cursor(x, y); + MAX7456_write_byte(0x04, 0x01); /* Enable 8bit write */ + while(len--) { + if (*s == '\0') break; + MAX7456_write_byte(0x80, MAX7456_map_char(*s++)); + } + MAX7456_write_byte(0x80, 0xFF); +} + +/** MAX7456_read_char_map + * + * Reads the 54byte character make-up bytes and stores them into a buffer. + * + */ +void MAX7456_read_char_map(unsigned char address, unsigned char *data54) { + MAX7456_write_byte(0x9, address); + MAX7456_write_byte(0x8, 0x50); + user_wait_ms_blocking(100); + for (int index = 0; index < 54; index++) { + MAX7456_write_byte(0xA, index); + user_wait_ms_blocking(1); + *(data54 + index) = MAX7456_read_byte(0xC0); + } +} + +/** MAX7456_write_char_map + * + * Used to write the 54bytes that make up a character into + * the MAX7456 CM non-volatile memory. Note, it tests the + * current non-v memory against the supplied buffer and only + * writes the buffer out if they don't match. Used to ensure + * we don't keep writing the same data into non-v memory which + * has a "lifetime" associated with it. + * + * @param unsigned char address The character address we are writing. + * @param unsigned char *data54 An array that contains the 54bytes of CM data. + */ +void MAX7456_write_char_map(unsigned char address, const unsigned char *data54) { + unsigned char index, c, match = 1; + + MAX7456_write_byte(0x9, address); + MAX7456_write_byte(0x8, 0x50); + user_wait_ms_blocking(20); + for (index = 0; index < 54; index++) { + MAX7456_write_byte(0xA, index); + c = MAX7456_read_byte(0xC0); + if (c != data54[index]) { + match = 0; + break; + } + } + + if (!match) { + MAX7456_write_byte(0x9, address); + for (index = 0; index < 0x36; index++) { + MAX7456_write_byte(0x0A, index); + MAX7456_write_byte(0x0B, data54[index]); + } + MAX7456_write_byte(0x08, 0xA0); + user_wait_ms_blocking(20); + while ((MAX7456_read_byte(0xA0) & 0x20) != 0x00); + } +} + +/** SSP1_init + */ +static void SSP1_init(void) { + + DEBUG_INIT_START; + + /* The MAX7456 device is connected to SSP1 via the Mbed pins. + So this init is about configuring just the SSP1, other + MAX7456 signals (vsync, etc) are setup elsewhere although + make call backs to this module as the "clearing house" for + MAX7456 signals. */ + + /* Enable the SSP1 peripheral. */ + LPC_SC->PCONP |= (1UL << 10); + + /* Select the clock required for SSP1. */ + LPC_SC->PCLKSEL0 &= ~(3UL << 20); + LPC_SC->PCLKSEL0 |= (3UL << 20); + + /* Select the GPIO pins for the SSP1 functions. */ + /* SCK1 */ + LPC_PINCON->PINSEL0 &= ~(3UL << 14); + LPC_PINCON->PINSEL0 |= (2UL << 14); + /* MISO1 */ + LPC_PINCON->PINSEL0 &= ~(3UL << 16); + LPC_PINCON->PINSEL0 |= (2UL << 16); + /* MOSI1 */ + LPC_PINCON->PINSEL0 &= ~(3UL << 18); + LPC_PINCON->PINSEL0 |= (2UL << 18); + + /* Note, we don't use SSEL1 in our design, we just use a standard GPIO + because a) the MAX7456 didn't really like the speed! and b) writing + 16bit data is somewhat simpler than reconfiguring the SSP each time + when all we need to do is hold CS low across 2 8bit operations. */ + + /* Setup the control registers for SSP1 */ + LPC_SSP1->CR0 = 0x7; + LPC_SSP1->CPSR = 0x2; + LPC_SSP1->CR1 = 0x2; + + DEBUG_INIT_END; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/osd/MAX7456.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,41 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef MAX7456_H +#define MAX7456_H + +#define MAX7456_DISPLAY_LINES 15 +#define MAX7456_DISPLAY_LINE_LEN 32 + +/* Function prototypes. */ +void MAX7456_init(void); +void MAX7456_write_byte(unsigned char address, unsigned char byte); +int MAX7456_read_byte(unsigned char address); +void MAX7456_cursor(int x, int y); +unsigned char MAX7456_map_char(unsigned char c); +void MAX7456_convert_string(unsigned char *s); +void MAX7456_string(unsigned char *s); +void MAX7456_stringl(int x, int y, unsigned char *s, int len); +void MAX7456_read_char_map(unsigned char address, unsigned char *data54); +void MAX7456_write_char_map(unsigned char address, const unsigned char *data54); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/osd/MAX7456_chars.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,405 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#include "MAX7456_chars.h" + +/* Why doesn't the MAX7456 have a + symbol? wtf! */ +const unsigned char ascii_4d[54] = { + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x00, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x00, 0x28, 0x00, + 0x4A, 0xAA, 0xA1, + 0x4A, 0xAA, 0xA1, + 0x00, 0x28, 0x00, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x00, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55 }; + +const unsigned char crosshair1_left[54] = { + 0x55, 0x55, 0x56, // 0 + 0x55, 0x55, 0x56, // 1 + 0x55, 0x55, 0x56, // 2 + 0x55, 0x55, 0x56, // 3 + 0x55, 0x55, 0x56, // 4 + 0x55, 0x55, 0x56, // 5 + 0x55, 0x55, 0x55, // 6 + 0x55, 0x55, 0x55, // 7 + 0x55, 0xAA, 0x95, // 8 + 0x55, 0xAA, 0x95, // 9 - 8 + 0x55, 0x55, 0x55, // 10 - 7 + 0x55, 0x55, 0x55, // 11 - 6 + 0x55, 0x55, 0x56, // 12 - 5 + 0x55, 0x55, 0x56, // 13 - 4 + 0x55, 0x55, 0x56, // 14 - 3 + 0x55, 0x55, 0x56, // 15 - 2 + 0x55, 0x55, 0x56, // 16 - 1 + 0x55, 0x55, 0x56 }; + +const unsigned char crosshair1_right[54] = { + 0x95, 0x55, 0x55, // 0 + 0x95, 0x55, 0x55, // 1 + 0x95, 0x55, 0x55, // 2 + 0x95, 0x55, 0x55, // 3 + 0x95, 0x55, 0x55, // 4 + 0x95, 0x55, 0x55, // 5 + 0x55, 0x55, 0x55, // 6 + 0x55, 0x55, 0x55, // 7 + 0x56, 0xAA, 0x55, // 8 + 0x56, 0xAA, 0x55, // 9 - 8 + 0x55, 0x55, 0x55, // 10 - 7 + 0x55, 0x55, 0x55, // 11 - 6 + 0x95, 0x55, 0x55, // 12 - 5 + 0x95, 0x55, 0x55, // 13 - 4 + 0x95, 0x55, 0x55, // 14 - 3 + 0x95, 0x55, 0x55, // 15 - 2 + 0x95, 0x55, 0x55, // 16 - 1 + 0x95, 0x55, 0x55 }; + +const unsigned char crosshair_centre[54] = { + 0x55, 0x28, 0x55, // 0 + 0x55, 0x28, 0x55, // 1 + 0x55, 0x28, 0x55, // 2 + 0x55, 0x28, 0x55, // 3 + 0x55, 0x28, 0x55, // 4 + 0x55, 0x00, 0x55, // 5 + 0x55, 0x55, 0x55, // 6 + 0x01, 0x55, 0x40, // 7 + 0xA1, 0x69, 0x4A, // 8 + 0xA1, 0x69, 0x4A, // 9 + 0x01, 0x55, 0x40, // 10 + 0x55, 0x55, 0x55, // 11 + 0x55, 0x00, 0x55, // 12 + 0x55, 0x28, 0x55, // 13 + 0x55, 0x28, 0x55, // 14 + 0x55, 0x28, 0x55, // 15 + 0x55, 0x28, 0x55, // 16 + 0x55, 0x28, 0x55 }; + + +const unsigned char ascii_b0[54] = { + 0x55, 0x55, 0x55, // 0 + 0x55, 0x55, 0x55, // 1 + 0x50, 0x01, 0x55, // 2 + 0x42, 0xA0, 0x55, // 3 + 0x0A, 0xA8, 0x15, // 4 + 0x28, 0x0A, 0x15, // 5 + 0x28, 0x0A, 0x15, // 6 + 0x28, 0x0A, 0x15, + 0x0A, 0xA8, 0x15, + 0x42, 0xA0, 0x55, + 0x50, 0x01, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55 }; + +const unsigned char ascii_b3[54] = { + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55 }; + +const unsigned char ascii_b4[54] = { + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x00, 0x28, 0x55, + 0xAA, 0xA8, 0x55, + 0xAA, 0xA8, 0x55, + 0x00, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55 }; + +const unsigned char ascii_bf[54] = { + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x00, 0x00, 0x55, + 0xAA, 0xA8, 0x55, + 0xAA, 0xA8, 0x55, + 0x00, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55 }; + +const unsigned char ascii_c0[54] = { + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x00, + 0x55, 0x2A, 0xAA, + 0x55, 0x2A, 0xAA, + 0x55, 0x00, 0x00, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55 }; + +const unsigned char ascii_c1[54] = { + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x00, 0x28, 0x00, + 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, + 0x00, 0x00, 0x00, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55 }; + +const unsigned char ascii_c2[54] = { + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x00, 0x00, 0x00, + 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, + 0x00, 0x28, 0x00, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55 }; + +const unsigned char ascii_c3[54] = { + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x00, + 0x55, 0x2A, 0xAA, + 0x55, 0x2A, 0xAA, + 0x55, 0x28, 0x00, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55 }; + +const unsigned char ascii_c4[54] = { + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x00, 0x00, 0x00, + 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, + 0x00, 0x00, 0x00, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55 }; + +const unsigned char ascii_c5[54] = { + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x00, 0x28, 0x00, + 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, + 0x00, 0x28, 0x00, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55 }; + +const unsigned char ascii_d9[54] = { + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x00, 0x28, 0x55, + 0xAA, 0xA8, 0x55, + 0xAA, 0xA8, 0x55, + 0x00, 0x00, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55 }; + +const unsigned char ascii_da[54] = { + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, + 0x55, 0x00, 0x00, + 0x55, 0x2A, 0xAA, + 0x55, 0x2A, 0xAA, + 0x55, 0x28, 0x00, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55, + 0x55, 0x28, 0x55 }; + +/* For the curious, during testing I managed to screw up the + characher at CM index2, ('2'). So I needed to reprogram + index2 with the correct character, doh! Anyway, since I + went to the trouble I'll leave it in the code. I managed + to find a default CM map at:- + http://www.maxim-ic.com/tools/evkit/index.cfm?EVKit=558 + If you download this then be aware that the DEFAULTCM.MCM file + defines each charmap as 64bytes, the 10 additional bytes need + to be stripped off as "not used". */ +#ifdef FIX_CM2_SCREW_UP +const unsigned char ascii_02[54] = { + 0x55, 0x55, 0x55, // 01010101 01010101 01010101 + 0x55, 0x55, 0x55, // 01010101 01010101 01010101 + 0x54, 0x00, 0x15, // 01010100 00000000 00010101 + 0x52, 0xAA, 0x85, // 01010010 10101010 10000101 + 0x4A, 0xAA, 0xA1, // 01001010 10101010 10100001 + 0x2A, 0x80, 0xA8, // 00101010 10000000 10101000 + 0x2A, 0x15, 0x28, // 00101010 00010101 00101000 + 0x40, 0x55, 0x28, // 01000000 01010101 00101000 + 0x55, 0x54, 0xA8, // 01010101 01010100 10101000 + 0x55, 0x52, 0xA1, // 01010101 01010010 10100001 + 0x55, 0x4A, 0x85, // 01010101 01001010 10000101 + 0x55, 0x2A, 0x15, // 01010101 00101010 00010101 + 0x54, 0xA8, 0x55, // 01010100 10101000 01010101 + 0x52, 0xA1, 0x55, // 01010010 10100001 01010101 + 0x4A, 0x80, 0x01, // 01001010 10000000 00000001 + 0x2A, 0xAA, 0xA8, // 00101010 10101010 10101000 + 0x2A, 0xAA, 0xA8, // 00101010 10101010 10101000 + 0x40, 0x00, 0x01 // 01000000 00000000 00000001 +}; +#endif + +/* Create an array of structures that link the data + characters to ASCII characters. The last entry + must always be null so we can detect the end of + the array. */ +MAX7456_CUSTOM_CHAR custom_chars[] = { + { 0xE0, crosshair1_left }, + { 0xE1, crosshair1_right }, + { 0xE2, crosshair_centre }, + { 0x4D, ascii_4d }, + { 0xB0, ascii_b0 }, + { 0xB3, ascii_b3 }, + { 0xB4, ascii_b4 }, + { 0xBF, ascii_bf }, + { 0xC0, ascii_c0 }, + { 0xC1, ascii_c1 }, + { 0xC2, ascii_c2 }, + { 0xC3, ascii_c3 }, + { 0xC4, ascii_c4 }, + { 0xC5, ascii_c5 }, + { 0xD9, ascii_d9 }, + { 0xDA, ascii_da }, +#ifdef FIX_CM2_SCREW_UP + { 0x02, ascii_02 }, +#endif + { 0x00, 0 } +}; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/osd/MAX7456_chars.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,33 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef MAX7456_CHARS_H +#define MAX7456_CHARS_H + +typedef struct _max7456_custom_char { + unsigned char ascii; + const unsigned char *map; +} MAX7456_CUSTOM_CHAR; + + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/osd/osd.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,315 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#include "sowb.h" +#include "debug.h" +#include "osd.h" +#include "gps.h" +#include "satapi.h" +#include "utils.h" +#include "nexstar.h" + +int test_counter = 0; + +/* Define the array of OSD dislay lines. */ +OSD_display_line osd_display_area[MAX7456_DISPLAY_LINES]; + +/* Toggle between odd and even fields. */ +int video_field; + +/* The top two display lines have a special use case. This int + is used to select the mode in which it works. */ +int l01_mode; + +/* Handles whether and how the crosshair is displayed. */ +int crosshair_mode; + + +/** osd_init + */ +void osd_init(void) { + + DEBUG_INIT_START; + video_field = 0; + l01_mode = 0; + crosshair_mode = 1; + osd_clear(); + DEBUG_INIT_END; +} + +/** osd_clear + * + * Clear the display area buffer. + */ +void osd_clear(void) { + for (int i = 0; i < MAX7456_DISPLAY_LINES; i++) { + osd_clear_line(i); + } +} + +/** osd_clear_line + * + * Clear a single line. + * + * @param int line The line to clear. + */ +void osd_clear_line(int line) { + for (int i = 0; i < MAX7456_DISPLAY_LINE_LEN; i++) { + osd_display_area[line].line_buffer[i] = '\0'; + } + osd_display_area[line].update = true; +} + +/** osd_string + * + * Write a null terminated string to a display line. + * + * @param int line The display line to write to. + * @param char *s The null terminated string. + */ +void osd_string(int line, char *s) { + for (int i = 0; *s; s++, i++) { + osd_display_area[line].line_buffer[i] = *s; + } + osd_display_area[line].update = true; +} + +/** osd_string_xy + * + * Write a null terminated string to a display line at x y. + * + * @param int line The display line to write to. + * @param char *s The null terminated string. + */ +void osd_string_xy(int x, int y, char *s) { + for (int i = x; *s; s++, i++) { + osd_display_area[y].line_buffer[i] = *s; + } + osd_display_area[y].update = true; +} + +/** osd_string_xyl + * + * Write a null terminated string to a display line at x y. + * + * @param int line The display line to write to. + * @param char *s The null terminated string. + * @param int len The length of the string to print. + */ +void osd_string_xyl(int x, int y, char *s, int len) { + for (int i = x; len; s++, i++, len--) { + osd_display_area[y].line_buffer[i] = *s; + } + osd_display_area[y].update = true; +} + +/** osd_stringl + * + * Write a string of specified length to a display line. + * + * @param int line The display line to write to. + * @param char *s The string. + * @param int len The length to write. + */ +void osd_stringl(int line, char *s, int len) { + for (int i = 0; len; s++, i++, len--) { + osd_display_area[line].line_buffer[i] = *s; + } + osd_display_area[line].update = true; +} + +/** osd_get_mode_l01 + */ +int osd_get_mode_l01(void) { + return l01_mode; +} + +/** osd_set_mode_l01 + */ +void osd_set_mode_l01(int mode) { + l01_mode = mode; +} + +/** osd_l01_next_mode + */ +void osd_l01_next_mode(void) { + int m = osd_get_mode_l01(); + m++; + if (m > L01_MODE_D) m = L01_MODE_A; + osd_set_mode_l01(m); +} + +/** osd_set_crosshair + */ +int osd_set_crosshair(int mode) { + if (mode > -1) { + crosshair_mode = mode; + } + return crosshair_mode; +} + +/** osd_crosshair_toggle + */ +int osd_crosshair_toggle(void) { + crosshair_mode = crosshair_mode == 0 ? 1 : 0; + if (!crosshair_mode) osd_clear(); + return crosshair_mode; +} + +/** osd_write_buffers + * + * Write the line buffers to the display. + */ +static void osd_write_buffers(void) { + for (int i = 0; i < MAX7456_DISPLAY_LINES; i++) { + if (osd_display_area[i].update) { + MAX7456_cursor(0, i); + MAX7456_write_byte(0x04, 0x01); /* Enable 8bit write. */ + for (int j = 0; j < MAX7456_DISPLAY_LINE_LEN; j++) { + MAX7456_write_byte(0x80, MAX7456_map_char(osd_display_area[i].line_buffer[j])); + } + MAX7456_write_byte(0x80, 0xFF); + osd_display_area[i].update = false; + } + } +} + +void osd_l01_position(void) { + GPS_LOCATION_AVERAGE loc; + char buf[64], buf2[64]; + double el, azm; + + gps_get_location_average(&loc); + + if (l01_mode != 0) { + if (IS_NEXSTAR_ALIGNED) { + nexstar_get_elazm(&el, &azm); + printDouble_3_2(buf, el); osd_string_xy(12, 0, buf); + printDouble_3_2(buf, azm); osd_string_xy(12, 1, buf); + } + else { + strcpy(buf, "---.--"); + osd_string_xy(12, 0, buf); + osd_string_xy(12, 1, buf); + } + } + + switch(l01_mode) { + case L01_MODE_C: + case L01_MODE_D: + double2dms(buf2, loc.latitude); sprintf(buf, "%c%s", loc.north_south, buf2); osd_string_xy(18, 0, buf); + double2dms(buf2, loc.longitude); sprintf(buf, "%c%s", loc.east_west, buf2); osd_string_xy(18, 1, buf); + break; + case L01_MODE_A: + case L01_MODE_B: + printDouble(buf2, loc.latitude); sprintf(buf, " %c%c%s", loc.is_valid, loc.north_south, buf2); osd_string_xy(18, 0, buf); + printDouble(buf2, loc.longitude); sprintf(buf, "%c%c%c%s", loc.sats[0] == '0' ? ' ' : loc.sats[0], loc.sats[1], loc.east_west, buf2); osd_string_xy(18, 1, buf); + break; + } +} + +/** osd_vsync + * + * A callback made when the MAX7456 vertical sync fires. + */ +void osd_vsync(void) { + GPS_TIME latched_time; + char buffer[32]; + + /* captire the time at which this VSync pulse occured. */ + gps_get_time(&latched_time); + + /* We don't actually know if this is an odd or even field. + All we can do is divide by two so each frame only displays + the time, otherwise it will "smudge" the display. We may + well add in an LM1881 device to the final design as that + has an odd/even field ttl output. */ + if (!video_field) { video_field = 1; return; } + else { video_field = 0; } + + /* If no mode is set, do not display line0/1. */ + if (l01_mode == 0) return; + + /* Display lines 0 and 1 are used for a specific feature, i.e. + the display of the time, GPS position, telescope pointing + position, etc. Handle the "time" display portion now. */ + osd_clear_line(0); + osd_clear_line(1); + + char buf2[32]; + double jd = gps_julian_date(&latched_time); + + if (crosshair_mode) { + osd_string_xy(13, 7, "\xE0\xE1"); + } + + switch(l01_mode) { + case L01_MODE_D: + case L01_MODE_B: + /* Display time as Julain Date. */ + sprintf(buf2, "%.7f", jd - (long)jd); + memset(buffer, 0, 32); sprintf(buffer, "JDI %07ld", (long)jd); osd_string_xy(0, 0, buffer); + memset(buffer, 0, 32); sprintf(buffer, "JDF.%s", buf2 + 2); osd_string_xy(0, 1, buffer); + break; + case L01_MODE_C: + case L01_MODE_A: + /* Display time as UTC. */ + memset(buffer, 0, 32); date_AsString(&latched_time, buffer); osd_string_xy(0, 0, buffer); + memset(buffer, 0, 32); time_AsString(&latched_time, buffer); osd_string_xy(0, 1, buffer); + break; + } + + osd_l01_position(); + + #ifdef NEVECOMPILETHIS + /* TEST TEST TEST !!! */ + /* Test failed. It actually worked, once. It seems the total math + involved in doing this is WAY to much to be inside what is effectively + an interrupt service routine. It does tell me lots, I need to move all + this to _process() but do it in a way that's fast enough for user output + in "real time" as it would appear to the user. */ + test_counter++; + if (test_counter == 1000) { + test_counter = 0; + SAT_POS_DATA data; + data.tsince = 0; + strcpy(data.elements[0], "ISS (ZARYA)"); + strcpy(data.elements[1], "1 25544U 98067A 10249.33655722 .00010912 00000-0 87866-4 0 8417"); + strcpy(data.elements[2], "2 25544 051.6459 175.3962 0008058 342.0418 161.2933 15.71504826676236"); + gps_get_time(&data.t); + gps_get_location_average(&data.l); + satallite_calculate(&data); + if (!isnan(data.elevation) && !isnan(data.azimuth) && !isnan(data.range)) { + sprintf(buffer, " ISS EL:%.1f AZM:%.1f RG:%.1f", data.elevation, data.azimuth, data.range); + osd_string_xy(0, 14, buffer); + } + } + /* TEST TEST TEST !!! */ + #endif + + osd_write_buffers(); +} + + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/osd/osd.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,65 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef OSD_H +#define OSD_H + +#include "MAX7456.h" + +#define L01_MODE_A 1 +#define L01_MODE_B 2 +#define L01_MODE_C 3 +#define L01_MODE_D 4 + +/* Define a structure that holds a OSD character line. + This is used to basically buffer the line so that it + can be displayed during the vertical sync period. + Additionally, we hold a binary flag to state whether + teh buffer has been updated. That way we know if we + don't need to send the buffer to the MAX7456 device + if no update to the buffer has occured. */ + +typedef struct { + bool update; + char line_buffer[MAX7456_DISPLAY_LINE_LEN]; +} OSD_display_line; + + +void osd_init(void); +void osd_clear(void); +void osd_clear_line(int line); +void osd_string(int line, char *s); +void osd_string_xy(int x, int y, char *s); +void osd_stringl(int line, char *s, int len); +void osd_string_xyl(int x, int y, char *s, int len); + +void osd_set_mode_l01(int mode); +void osd_l01_next_mode(void); +int osd_set_crosshair(int mode); +int osd_crosshair_toggle(void); + +void osd_vsync(void); + + + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pccomms/handlers/mode1.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,142 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +/* +MODE 1 Packet handler. + +This mode is used by the Host to send a file containing all the TLEs that +SOWB needs to aquire satellites. The base packet payload itself conatins +a sub packet as defined below. Note, we assign a number of flash pages to +the TLE file. Each flash page is 256bytes in size. So, the host sends the +file in 256byte blocks. The sub-packet header defines the block being sent. +We add to this block the flash base page and write the 256byte sub-packet +payload into the flash device. Note, TLE files are ascii characters so the +sub-packet payload is ASCII itself and doesn't require any conversions. + +Subp-acket format <BBBBCF>......... +Where:- + < is the "start of packet header" character. + BBBB is a hex string representation of the uint16_t 256 char block. + C is a two's complement checksum of the header from < to > inclusive. + F is a char flag. Normally zero. + > is the "end of packet header" character. + .... is the packet payload, 256 bytes in length. + +*/ + +#include "sowb.h" +#include "user.h" +#include "utils.h" +#include "flash.h" +#include "pccomms.h" + +#define FLASH_BASE_TLE_FILE 10 + +/* Error flags to send back on failure. */ +#define FLAG_BAD_CHECKSUM '1' +#define FLAG_INVALID_LENGTH '2' + +/* Base packet payload to sub-packet header definition. */ +typedef struct _pccomms_mode1_header { + char lead_char; + char block[4]; + char csum; + char flag; + char trail_char; +} PCCOMMS_MODE1_HEADER; + +/* Base packet payload to sub-packet overall definition. */ +typedef struct _pccomms_mode1 { + PCCOMMS_MODE1_HEADER header; + char payload[256]; +} PCCOMMS_MODE1; + + +/** pccomms_mode1_failed + * + * Used to send back a failed packet with a flag "reason for failure". + * + * @param BASE_PACKET_A *a The original ASCII version of the packet header. + * @param char flag The char flag to insert. + */ +void pccomms_mode1_failed(BASE_PACKET_A *a, char flag) { + BASE_PACKET_A temp; + char *p; + int i; + + memcpy((char *)&temp, (char *)a, sizeof(BASE_PACKET_A)); + temp.flag = flag; + temp.csum = 0; + temp.csum = strcsuml((char *)&temp, sizeof(BASE_PACKET_A)); + for (p = (char *)&temp, i = 0; i < sizeof(BASE_PACKET_A); i++) { + Uart3_putc((char)p[i]); + } +} + +/** pccomms_mode1_handler + * + * The packet handler for MODE 1. + * + * @param BASE_PACKET_B *b + * @param BASE_PACKET_A *a + * @return int + */ +int pccomms_mode1_handler(BASE_PACKET_B *b, BASE_PACKET_A *a) { + PCCOMMS_MODE1 data; + char *p; + int page, c, i; + + /* Sanity check, should never fail, should really assert() */ + if (b->mode != 1) return PCCOMMS_PACKET_REJECTED; + + /* Sanity check, should never fail, should really assert() */ + if (b->length != sizeof(PCCOMMS_MODE1)) return PCCOMMS_PACKET_REJECTED; + + /* Copy the base packet payload into our internal data structure. */ + for(p = (char *)&data, i = 0; i < sizeof(PCCOMMS_MODE1); i++) { + c = Uart3_getc(0); + if (c != -1) p[i] = (char)c; + else { + /* This shouldn't happen as once the IRQ system has detected the + end of the packet it no longer inserts serial chars into the + buffer. So another sanity check really. Unless the Host did + in fact screw up somewhere. */ + pccomms_mode1_failed(a, FLAG_INVALID_LENGTH); + return PCCOMMS_PACKET_REJECTED; + } + } + + /* Run a checksum check. On failure, send back the Host's packet with "flag" set to "bad checksum". */ + if (strsuml((char *)&data, sizeof(PCCOMMS_MODE1)) != 0) { + pccomms_mode1_failed(a, FLAG_BAD_CHECKSUM); + return PCCOMMS_PACKET_REJECTED; + } + + /* Get the block header and add the flash page offset. */ + page = (int)hex2bin(data.header.block, 4) + FLASH_BASE_TLE_FILE; + + /* Assuming we programmed the flash device ok, return packet accepted. */ + flash_page_write(page, data.payload); + while(flash_write_in_progress()) user_call_process(); + return PCCOMMS_PACKET_ACCEPTED; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pccomms/pccomms.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,285 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +/* +Packet format <MMMMLLLLCF>......... +Where:- + < is the "start of packet header" character. + MMMM is a hex string representation of the uint16_t mode. + LLLL is a hex string representation of the uint16_t length (payload length). + C is a two's complement checksum of the header from < to > inclusive. + F is a char flag. Normally zero. + > is the "end of packet header" character. + .... is the packet payload, a series of bytes, the number defined by length LLLL + +Note, the C checksum should be added by the sender. This is the two's complement of +all the ascii chars from < to > inclusive. Once inserted by the sender, the header +packet can be checked by summing all the charachers, from < to > inclusive and the +result should be zero. + +Once a complete header is received the IRQ is told how many bytes to read into the +RX buffer before changing the state to PCCOMMS_PACKET_READ. After this any future +characters received will be sent to dev/null until the current packet is handled. + +The handling is done by the _process() function. Basically, once we have a packet +the MMMM mode decides what to do with it. The _process() function will call the list +of handler functions passing a pointer to the packet header. Each handler can +accept the header and then empty the payload RX buffer. Handlers can get the payload +by simply calling Uart1_getc(), which will eventually return -1 when the RX buffer +is empty (which should match the LLLL length of the payload. + +If a handler returns PCCOMMS_PACKET_ACCEPTED then we clear out the header and reset +the serial system to begin listening for a new packet. Note, if a handler needs to +keep a copy of any data (header or payload) it should do so before it returns +PCCOMMS_PACKET_ACCEPTED because the engine here will ensure all buffers get reset +before going back into reception mode. + +If no handler accepts the packet then the packet is dropped, the serial engine is +reset and basically everything is reset to begin looking for a new packet header. */ + +#include "sowb.h" +#include "debug.h" +#include "pccomms.h" +#include "utils.h" + +/* Globals used for the packet reception engine. */ +int pccomms_state; +BASE_PACKET_A header_packet_ascii; +unsigned char header_packet_in; +BASE_PACKET_B header_packet; +uint16_t packet_char_counter; + +/* Payload buffers. */ +volatile char uart3txBuffer[UART3_TX_BUFFER_SIZE]; +volatile char uart3rxBuffer[UART3_RX_BUFFER_SIZE]; +volatile unsigned char uart3txBufferIn, uart3txBufferOut; +volatile unsigned char uart3rxBufferIn, uart3rxBufferOut; +volatile bool uart3txBufferFull, uart3rxBufferFull, uart3rxBufferOverflow; + +/* Used to reset the PC COMMS system. */ +static void pccomms_reset(void) { + pccomms_state = PCCOMMS_STATE_WAITING; + header_packet_in = 0; + uart3txBufferIn = uart3txBufferOut = 0; + memset((char *)uart3txBuffer, 0, UART3_TX_BUFFER_SIZE); + uart3rxBufferIn = uart3rxBufferOut = 0; + memset((char *)uart3txBuffer, 0, UART3_RX_BUFFER_SIZE); + uart3txBufferFull = uart3rxBufferFull = false; + uart3rxBufferOverflow = false; +} + +/** pccomms_init + */ +void pccomms_init(void) { + DEBUG_INIT_START; + pccomms_reset(); + Uart3_init(); + DEBUG_INIT_END; +} + +/* We declare the packet handler functions prototypes here. */ +int pccomms_mode1_handler(BASE_PACKET_B *b, BASE_PACKET_A *a); + +/** pccomms_process + */ +void pccomms_process(void) { + + /* If the IRQ system has flagged a packet reception complete handle it. */ + if (pccomms_state == PCCOMMS_PACKET_READ) { + switch(header_packet.mode) { + case 1: + pccomms_mode1_handler(&header_packet, &header_packet_ascii); + break; + } + + pccomms_reset(); + } +} + +/** base_packet_a2b + * + * Convert a header packet in ASCII format to the internal + * binary form. + * + * @param BASE_PACKET_B *b The dst of the conversion + * @param BASE_PACKET_A *a The src of the conversion + */ +void base_packet_a2b(BASE_PACKET_B *b, BASE_PACKET_A *a) { + b->mode = (uint16_t)hex2bin(a->mode, 4); + b->length = (uint16_t)hex2bin(a->length, 4); +} + +/** base_packet_b2a + * + * Convert an internal header packet in binary format to the external + * ASCII form. + * + * @param BASE_PACKET_A *a The dst of the conversion + * @param BASE_PACKET_B *b The src of the conversion + */ +void base_packet_b2a(BASE_PACKET_A *a, BASE_PACKET_B *b) { + bin2hex((uint32_t)b->mode, 4, a->mode); + bin2hex((uint32_t)b->length, 4, a->length); + a->lead_char = '<'; + a->trail_char = '>'; + a->csum = '\0'; + a->csum = strcsuml((char *)a, BASE_PACKET_A_LEN); +} + +/** Uart3_putc + * + * Put a character out the UART1 serial port. + * Note, if the THR register is not empty AND the output buffer is not empty + * then place the character into the output buffer and enable interrupt to + * flush the buffer. + * + * Additionally, if the TX buffer is full this function will BLOCK! + * Be aware of this blocking! + * + * @param char c The character to send out of UART1. + */ +void Uart3_putc(char c) { + if ((LPC_UART3->LSR & 0x20) && (uart3txBufferIn == uart3txBufferOut && !uart3txBufferFull)) { + LPC_UART3->THR = (uint8_t)c; + } + else { + while (uart3txBufferFull) ; /* Blocks!!! */ + uart3txBuffer[uart3txBufferIn++] = c; + uart3txBufferIn &= (UART3_TX_BUFFER_SIZE - 1); + if (uart3txBufferIn == uart3txBufferOut && !uart3txBufferFull) uart3txBufferFull = true; + LPC_UART3->IER = 0x3; + } +} + +/** Uart3_getc + * + * Used to get a character from Uart1. If the passed arg "block" is non-zero + * then this function will block (wait) for user input. Otherwise if a char + * is available return it, otherwise return -1 to show buffer was empty. + * + * @param int block Should we block? + * @return int Cast char to int for char or -1 if non-blocking and no char. + */ +int Uart3_getc(int block) { + char c; + + if (block) while (uart3rxBufferOut == uart3rxBufferIn && !uart3rxBufferFull) ; /* Blocks! */ + else if (uart3rxBufferIn == uart3rxBufferOut && !uart3rxBufferFull) return -1; + + c = uart3rxBuffer[uart3rxBufferOut++]; + uart3rxBufferOut &= (UART3_RX_BUFFER_SIZE - 1); + if (uart3rxBufferFull) uart3rxBufferFull = false; + return (int)c; +} + +/** UART3_IRQHandler + */ +extern "C" void UART3_IRQHandler(void) __irq { + uint32_t iir; + char c, *p; + + iir = LPC_UART3->IIR; + + if (iir & 1) return; + + iir = (iir >> 1) & 0x3; + + if (iir == 2) { + c = (char)LPC_UART3->RBR; + if (pccomms_state == PCCOMMS_STATE_WAITING) { + p = (char *)&header_packet_ascii; + if (c == '<') { + header_packet_in = 0; + p[header_packet_in++] = c; + BASE_PACKET_WRAP; + } + else if (c == '>') { + p[header_packet_in++] = c; + BASE_PACKET_WRAP; + if (strsuml(p, BASE_PACKET_A_LEN) == 0) { + base_packet_a2b(&header_packet, &header_packet_ascii); + packet_char_counter = header_packet.length; + pccomms_state = PCCOMMS_BASE_PACKET_READ; + } + else { + pccomms_state = PCCOMMS_BASE_PACKET_BAD_CSUM; + header_packet_in = 0; + } + } + else { + p[header_packet_in++] = c; + BASE_PACKET_WRAP; + } + } + else if (pccomms_state == PCCOMMS_BASE_PACKET_READ) { + if (uart3rxBufferIn == uart3rxBufferOut && uart3rxBufferFull) { + uart3rxBufferOverflow = true; + } + else { + uart3rxBuffer[uart3rxBufferIn++] = c; + uart3rxBufferIn &= (UART3_RX_BUFFER_SIZE - 1); + if (uart3rxBufferIn == uart3rxBufferOut) uart3rxBufferFull = true; + if (packet_char_counter) packet_char_counter--; + if (packet_char_counter == 0) { + pccomms_state = PCCOMMS_PACKET_READ; + } + } + + } + else { + /* Unknown state, send char to /dev/null */ + } + } + + if (iir == 1) { + if (uart3txBufferIn != uart3txBufferOut || uart3txBufferFull) { + LPC_UART3->THR = (uint8_t)(uart3txBuffer[uart3txBufferOut++]); + uart3txBufferOut &= (UART3_TX_BUFFER_SIZE - 1); + uart3txBufferFull = false; + } + else { + LPC_UART3->IER = 0x1; + } + } +} + +/** Uart3_init + */ +void Uart3_init(void) { + + LPC_SC->PCONP |= (1UL << 25); + LPC_SC->PCLKSEL1 &= ~(3UL << 18); + LPC_SC->PCLKSEL1 |= (1UL << 18); + LPC_PINCON->PINSEL0 &= ~((2UL << 0) | (2UL << 2)); + LPC_PINCON->PINSEL0 |= ((2UL << 0) | (2UL << 2)); + LPC_UART1->LCR = 0x80; + LPC_UART1->DLM = 0x0; // 0x00 for 115200 baud, for 9600 use 0x2; + LPC_UART1->DLL = 0x34; // 0x34 for 115200 baud, for 9600 use 0x71; + LPC_UART1->LCR = 0x3; + LPC_UART1->FCR = 0x7; + + NVIC_SetVector(UART3_IRQn, (uint32_t)UART3_IRQHandler); + NVIC_EnableIRQ(UART3_IRQn); + + /* Enable UART1 RX and TX interrupt. */ + LPC_UART3->IER = 0x3; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pccomms/pccomms.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,72 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef PCCOMMS_H +#define PCCOMMS_H + +#include "sowb.h" + +#define PCCOMMS_STATE_WAITING 0 +#define PCCOMMS_BASE_PACKET_READ 1 +#define PCCOMMS_PACKET_READ 2 +#define PCCOMMS_BASE_PACKET_BAD_CSUM 3 + +#define PCCOMMS_PACKET_ACCEPTED 1 +#define PCCOMMS_PACKET_REJECTED 2 + +typedef struct _base_packet_bin { + uint16_t mode; + uint16_t length; +} BASE_PACKET_B; + +#define BASE_PACKET_B_LEN sizeof(BASE_PACKET_B) + +typedef struct _base_packet_ascii { + char lead_char; + char mode[4]; + char length[4]; + char csum; + char flag; + char trail_char; +} BASE_PACKET_A; + +#define BASE_PACKET_A_LEN sizeof(BASE_PACKET_A) + +#define BASE_PACKET_WRAP if(header_packet_in>=BASE_PACKET_A_LEN)header_packet_in=0 + +void pccomms_init(void); +void pccomms_process(void); + +void Uart3_init(void); +void Uart3_putc(char c); +int Uart3_getc(int block); + +void base_packet_a2b(BASE_PACKET_B *b, BASE_PACKET_A *a); +void base_packet_b2a(BASE_PACKET_A *a, BASE_PACKET_B *b); + +/* Buffer sizes MUST be a aligned 2^, for example 8, 16, 32, 64, 128, 256, 512, 1024, etc + Do NOT use any other value or the buffer wrapping firmware won't work. */ +#define UART3_TX_BUFFER_SIZE 512 +#define UART3_RX_BUFFER_SIZE 512 + + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rit/rit.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,155 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#include "sowb.h" +#include "debug.h" +#include "rit.h" +#include "gps.h" +#include "gpio.h" + +volatile uint32_t uptimeL; +volatile uint32_t uptimeH; + +/* Declare "timer at zero" callback function prototypes. */ +void _gps_timer_tick_cb(int); +void _user_wait_ms_cb(int); +void _nexstar_timeout_callback(int); +void _nexstar_one_second_timer(int index); +void _nexstar_100th_timer(int index); +void _flash_write_timer_callback(int index); +void _main_test_callback(int index); +void _sdcard_timer_callback(int index); + +/* Define an array of timers that the ISR should handle. */ +volatile RIT_TIMER timers[] = { + { 10, 10, _gps_timer_tick_cb }, /* Index 0 */ + { 0, 0, _user_wait_ms_cb }, /* Index 1 */ + { 0, 0, _nexstar_timeout_callback }, /* Index 2 */ + { 0, 0, _nexstar_one_second_timer }, /* Index 3 */ + { 0, 0, _nexstar_100th_timer }, /* Index 4 */ + { 0, 0, _flash_write_timer_callback }, /* Index 5 */ + { 0, 0, _sdcard_timer_callback }, /* Index 6 */ + { 0, 0, _main_test_callback }, /* Index 7 */ + { 0, 0, NULL } /* Always the last entry. */ +}; + +/** RIT_IRQHandler + * + * The ISR for the RIT. + */ +extern "C" static void RIT_IRQHandler(void) __irq { + if (++uptimeL == 0) uptimeH++; + for (int index = 0; timers[index].callback != NULL; index++) { + if (timers[index].counter > 0) { + timers[index].counter--; + if (timers[index].counter == 0) { + (timers[index].callback)(index); + if (timers[index].reload > 0) { + timers[index].counter = timers[index].reload; + } + } + } + } + LPC_RIT->RICTRL |= 0x1; /* Dismiss the IRQ. */ +} + +/** rit_index_check + * + * Check that an index exists. Ensures that index into array is valid. + * + * @param int inex The index to check. + * @return int zero on non-existent index, non-zero otherwise. + */ +inline static bool rit_index_check(int index) { + for (int i = 0; timers[i].callback != NULL; i++) if (i == index) return true; + return false; +} + +/** rit_timer_set_counter + */ +void rit_timer_set_counter(int index, uint32_t value) { + if (rit_index_check(index)) timers[index].counter = value; +} + +/** rit_timer_set_reload + */ +void rit_timer_set_reload(int index, uint32_t value) { + if (rit_index_check(index)) timers[index].reload = value; +} + +/** rit_timer_get_values + * + * Get the current counter/reload values of the specified timer. + * + * If the supplied "index" value is out of range the index value pointed to by + * the caller is set to -1 to signify an error has occured (subscript/index out + * of range). + * + * @param int * index A pointer to an int for the index value of the array to return. + * @param uint32_t * counter A pointer to variable to place the counter value into. + * @param uint32_t * counter A pointer to variable to place the reload value into. + */ +void rit_timer_get_values(int *index, uint32_t *counter, uint32_t *reload) { + if (rit_index_check(*(index))) { + *(counter) = timers[*(index)].counter; + *(reload) = timers[*(index)].reload; + } + else *(index) = -1; +} + +/** rit_get_uptime + */ +void rit_read_uptime(uint32_t *h, uint32_t *l) { + *(l) = uptimeL; + *(h) = uptimeH; +} + +/** rit_init + */ +void rit_init(void) { + + DEBUG_INIT_START; + + uptimeL = uptimeH = 0; + + /* Start by switching power on to the peripheral */ + LPC_SC->PCONP |= (1UL << 16); + + /* The compare value depends on the PCLK frequency. + The following are based on a CCLK of 96Mhz to + achieve a 1ms timeout value. */ + switch ((LPC_SC->PCLKSEL1 >> 26) & 0x3) { + case 0: LPC_RIT->RICOMPVAL = (96000000L / 4 / 1000); break; /* CCLK / 4 */ + case 1: LPC_RIT->RICOMPVAL = (96000000L / 1 / 1000); break; /* CCLK / 1 */ + case 2: LPC_RIT->RICOMPVAL = (96000000L / 2 / 1000); break; /* CCLK / 2 */ + case 3: LPC_RIT->RICOMPVAL = (96000000L / 8 / 1000); break; /* CCLK / 8 */ + } + + /* Set the ISR vector and enable interrupts for the RIT. */ + NVIC_SetVector(RIT_IRQn, (uint32_t)RIT_IRQHandler); + NVIC_EnableIRQ(RIT_IRQn); + + /* Enable the RIT. */ + LPC_RIT->RICTRL = 0x0000000A; + + DEBUG_INIT_END; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rit/rit.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,49 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef RIT_H +#define RIT_H + +#define RIT_TIMER_CB_GPS 0 +#define RIT_TIMER_CB_WAIT 1 +#define RIT_TIMER_NEXSTAR 2 +#define RIT_ONESEC_NEXSTAR 3 +#define RIT_100TH_NEXSTAR 4 +#define FLASH_WRITE_CB 5 +#define SDCARD_TIMER_CB 6 +#define MAIN_TEST_CB 7 + +#include "sowb.h" + +typedef struct _rit_timer { + uint32_t reload; /* Value to reload for recurring mode. */ + uint32_t counter; /* The acutal counter that "down counts" to zero. */ + void (*callback)(int); /* The function to call when zero is reached. */ +} RIT_TIMER; + +void rit_init(void); +void rit_timer_set_counter(int index, uint32_t value); +void rit_timer_set_reload(int index, uint32_t value); +void rit_timer_get_values(int *, uint32_t *, uint32_t *); +void rit_read_uptime(uint32_t *h, uint32_t *l); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/satapi/mbedfilesys.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,142 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +/* Sadly stung by the Mbed libraries again. The sheer number + of interrupts running on SOWB are incomp with the LocalFileSystem + library which simply crashes the entire project. + + Need to get down to the electonics shop and buy myself some flash + and DIY my own solution again. Sigh... */ + +#ifdef NEVERCOMPILETHIS + +#include "mbed.h" +#include "mbedfilesys.h" +#include "user.h" +#include "utils.h" +#include "gpio.h" +#include "debug.h" + +LocalFileSystem local("local"); + +inline void disable_irqs(void) { + NVIC_DisableIRQ(EINT3_IRQn); + NVIC_DisableIRQ(RIT_IRQn); + NVIC_DisableIRQ(UART0_IRQn); + NVIC_DisableIRQ(UART1_IRQn); + NVIC_DisableIRQ(UART2_IRQn); + NVIC_DisableIRQ(USB_IRQn); +} + +inline void enable_irqs(void) { + NVIC_EnableIRQ(USB_IRQn); + NVIC_EnableIRQ(EINT3_IRQn); + NVIC_EnableIRQ(RIT_IRQn); + NVIC_EnableIRQ(UART0_IRQn); + NVIC_EnableIRQ(UART1_IRQn); + NVIC_EnableIRQ(UART2_IRQn); +} + +static int get_tle_from_file(const char *filename, int index, SAT_POS_DATA *sat) { + FILE *fp; + char *r, line[128]; + int line_count = 0, sat_count = 0; + + fp = fopen(filename, "r"); + if (!fp) { + return SOWB_FILE_NOT_FOUND; + } + else { + while (!feof(fp)) { + LED1_ON; + disable_irqs(); + r = fgets(line, 127, fp); + enable_irqs(); + LED1_OFF; + if(!fgets(line, 127, fp)) { + fclose(fp); + return SOWB_FILE_EOF_REACHED; + } + else { + switch(line_count) { + case 0: strncpy(sat->elements[0], line, 80); break; + case 1: strncpy(sat->elements[1], line, 80); break; + case 2: strncpy(sat->elements[2], line, 80); break; + } + line_count++; + if (line_count == 3) { + if (sat_count == index) { + fclose(fp); + return SOWB_FILE_OK; + } + line_count = 0; + sat_count++; + } + } + } + } + + fclose(fp); + return SOWB_FILE_INDEX_NOT_FOUND; +} + +/* Used to hold the index across first/next calls. */ +int satllite_index; + +int get_first_tle_from_file(const char *filename, SAT_POS_DATA *sat) { + satllite_index = 0; + return get_tle_from_file(filename, satllite_index, sat); +} + +int get_next_tle_from_file(const char *filename, SAT_POS_DATA *sat) { + satllite_index++; + return get_tle_from_file(filename, satllite_index, sat); +} + +void process_tle(SAT_POS_DATA *sat) { + char line[128]; + + /* Wait until time and location are valid. */ + do { + observer_now(sat); + user_call_process(); + } + while (!sat->time.is_valid || !sat->location.is_valid); + + debug_printf(" A %d\r\n", sizeof(SAT_POS_DATA)); + debug_printf(" A %s", sat->elements[0]); + debug_printf(" A %s", sat->elements[1]); + debug_printf(" A %s", sat->elements[2]); + time_AsString(&sat->time, line); + debug_printf(" A AT %s\r\n", line); + sprintf(line, " A LAT %.4f\r\n", sat->location.latitude); debug_printf("%s", line); + sprintf(line, " A LON %.4f\r\n", sat->location.longitude); debug_printf("%s", line); + sprintf(line, " A HEI %.4f\r\n", sat->location.height); debug_printf("%s", line); + + sat->tsince = 0; + satallite_calculate(sat); + debug_stringl(line, sprintf(line, " Azmith %.1f Elevation %.1f\r\n", sat->azimuth, sat->elevation)); +} + +#endif + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/satapi/mbedfilesys.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,43 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifdef NEVERCOMPILETHIS + +#ifndef MBEDFILESYS_H +#define MBEDFILESYS_H + +#include "satapi.h" + +#define SOWB_FILE_OK 1 +#define SOWB_FILE_NOT_FOUND -1 +#define SOWB_FILE_INDEX_NOT_FOUND -2 +#define SOWB_FILE_EOF_REACHED -3 + +int get_first_tle_from_file(const char *filename, SAT_POS_DATA *sat); +int get_next_tle_from_file(const char *filename, SAT_POS_DATA *sat); + +void process_tle(SAT_POS_DATA *sat); + +#endif + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/satapi/satapi.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,193 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#include "sowb.h" +#include "user.h" +#include "satapi.h" +#include "utils.h" +#include "debug.h" +#include "gpio.h" +#include "osd.h" +#include "nexstar.h" +#include "utils.h" + +#ifndef M_PI +#define M_PI 3.1415926535898 +#endif + +#define SCAN_INTERVAL 60 + +double satapi_aos(SAT_POS_DATA *q, bool goto_aos) { + double tsince; + char temp1[32], temp2[32]; + + strcpy(q->elements[0], "Lacrosse 2"); + strcpy(q->elements[1], "1 21147U 91017A 10269.82093092 0.00000020 00000-0 28786-5 0 05"); + strcpy(q->elements[2], "2 21147 67.9820 220.2995 0002000 244.7811 115.2189 14.76261286 07"); + + observer_now(q); + + P22_ASSERT; + + for (q->tsince = 0; q->tsince < (SCAN_INTERVAL * 90); q->tsince += SCAN_INTERVAL) { + KICK_WATCHDOG; /* We are busy! */ + satallite_calculate(q); + if (q->elevation >= 10.) { + /* Above horizon viewing. Work back to AOS. */ + for (tsince = q->tsince, q->tsince--; q->elevation > 10. ; tsince = q->tsince--) { + satallite_calculate(q); + if (q->elevation < 10.) { + //sprintf(temp, "%03f Q AOS El:%.1f AZ:%.1f %dKm\r\n", q->tsince, q->elevation, q->azimuth, (int)q->range); + //debug_printf(temp); + q->tsince = tsince; + satallite_calculate(q); + sprintf(temp1, "%03f T AOS El:%.1f AZ:%.1f %dKm\r\n", q->tsince, q->elevation, q->azimuth, (int)q->range); + debug_printf(temp1); + P22_DEASSERT; + if (goto_aos) { + sprintf(temp1, "%s T-%.2f", q->elements[0], tsince); + osd_string_xy(1, 12, temp1); + sprintf(temp1, "AOS %.2f%c %s%c %dKm", q->elevation, 176, printDouble_3_2(temp2, q->azimuth), 176, (int)q->range); + osd_string_xy(1, 13, temp1); + _nexstar_goto((uint32_t)((q->elevation / 360.) * 65536), (uint32_t)((q->azimuth / 360.) * 65536)); + } + return tsince; + } + } + } + } + + P22_DEASSERT; + return 0.; +} + +int satallite_calculate(SAT_POS_DATA *q) { + double tsince; + + /* Ensure the time and place are valid. */ + if (!q->time.is_valid) return -1; + if (!q->location.is_valid) return -2; + + ClearFlag(ALL_FLAGS); + + Get_Next_Tle_Set(q->elements, &q->tle); + + select_ephemeris(&q->tle); + + q->jd_utc = gps_julian_date(&q->time); + q->jd_epoch = Julian_Date_of_Epoch(q->tle.epoch); + + tsince = ((q->jd_utc + (q->tsince * (1 / 86400.))) - q->jd_epoch) * xmnpda; + + if (isFlagSet(DEEP_SPACE_EPHEM_FLAG)) { + SDP4(tsince, &q->tle, &q->pos, &q->vel, &q->phase); + } + else { + SGP4(tsince, &q->tle, &q->pos, &q->vel, &q->phase); + } + + Convert_Sat_State(&q->pos, &q->vel); + SgpMagnitude(&q->vel); // scalar magnitude, not brightness... + q->velocity = q->vel.w; + + /* Populate the geodetic_t struct from data supplied. */ + q->observer.lat = q->location.latitude * de2ra; + q->observer.lon = q->location.longitude * de2ra; + q->observer.alt = q->location.height / 1000.; + if (q->location.north_south == 'S') q->observer.lat *= -1.; + if (q->location.east_west == 'W') q->observer.lon *= -1.; + + Calculate_Obs(q->jd_utc, &q->pos, &q->vel, &q->observer, &q->obs_set); + Calculate_LatLonAlt(q->jd_utc, &q->pos, &q->sat_geodetic); + + q->azimuth = Degrees(q->obs_set.x); + q->elevation = Degrees(q->obs_set.y); + q->range = q->obs_set.z; + q->rangeRate = q->obs_set.w; + q->height = q->sat_geodetic.alt; + + return 0; +} + +/** observer_now + * + * Fills the data structure with the observers time and position. + * + * @param SAT_POS_DATA * A pointer to the data structure. + */ +SAT_POS_DATA * observer_now(SAT_POS_DATA *q) { + gps_get_time(&q->time); + gps_get_location_average(&q->location); + return q; +} + +AltAz * radec2altaz(double siderealDegrees, GPS_LOCATION_AVERAGE *location, RaDec *radec, AltAz *altaz) { + double HA, DEC, LAT, mul, altitude, azimuth; + + mul = location->north_south == 'S' ? -1.0 : 1.0; + + /* Convert to radians. */ + HA = siderealDegrees * (M_PI / 180.0) - (radec->ra * (M_PI / 180)); + DEC = radec->dec * (M_PI / 180.0); + LAT = (location->latitude * mul) * (M_PI / 180.0); + + altitude = atan2(- sin(HA) * cos(DEC), cos(LAT) * sin(DEC) - sin(LAT) * cos(DEC) * cos(HA)); + azimuth = asin(sin(LAT) * sin(DEC) + cos(LAT) * cos(DEC) * cos(HA)); + + // Convert to degrees and swing azimuth around if needed. + altaz->alt = azimuth * 180.0 / M_PI; + altaz->azm = altitude * 180.0 / M_PI; + if (altaz->azm < 0) altaz->azm += 360.0; + + return altaz; +} + +RaDec * altaz2radec(double siderealDegrees, GPS_LOCATION_AVERAGE *location, AltAz *altaz, RaDec *radec) { + double ALT, AZM, LAT, HA, DEC, mul; + + mul = location->north_south == 'S' ? -1.0 : 1.0; + + /* Convert to radians. */ + LAT = (location->latitude * mul) * (M_PI / 180.0); + ALT = altaz->alt * (M_PI / 180.0); + AZM = altaz->azm * (M_PI / 180.0); + + /* Calculate the declination. */ + DEC = asin( ( sin(ALT) * sin(LAT) ) + ( cos(ALT) * cos(LAT) * cos(AZM) ) ); + radec->dec = DEC * 180.0 / M_PI; + while (radec->dec < 0.0) radec->dec += 360.0; + while (radec->dec > 360.0) radec->dec -= 360.0; + + /* Calculate the hour angle. */ + HA = ( acos((sin(ALT) - sin(LAT) * sin(DEC)) / (cos(LAT) * cos(DEC)))) * 180.0 / M_PI; + if (sin(AZM) > 0.0) HA = 360.0 - HA; + + /* Correct the HA for our sidereal time. */ + HA = (siderealDegrees / 360.0 * 24.0) - (HA / 15.0); + if (HA < 0.0) HA += 24.0; + + /* Convert the HA into degrees for the return. */ + radec->ra = HA / 24.0 * 360.0; + + return radec; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/satapi/satapi.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,96 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef SATAPI_H +#define SATAPI_H + +#include "gps.h" +#include "sgp4sdp4.h" + +#define JD_SECOND (1. / 86400.) +#define JD_MINUTE (JD_SECOND * 60.) +#define JD_HOUR (JD_MINUTE * 60.) +#define JD_DAY (JD_HOUR * 24.) + +typedef struct _altaz { + double alt; + double azm; +} AltAz; + +typedef struct _radec { + double ra; + double dec; +} RaDec; + +typedef struct _eci { + double x; + double y; + double z; + double xdot; + double ydot; + double zdot; + double atTime; +} Eci; + +typedef struct _sat_pos_data { + + /* Inputs. */ + char elements[3][80]; + GPS_TIME time; + GPS_LOCATION_AVERAGE location; + + /* Semi-intermediates. + Set to zero for JD_UTC - SAT EPOCH. + If you want to know the satellite position say 5 seconds + into the furture set this to 5.0 The "real" tsince is + calculated by JD_UTC + (tsince * (1 / 86400.)) - JD_SAT_EPOCH */ + double tsince; + + /* Intermediates. */ + tle_t tle; /* Constructed from the elements arrays. */ + geodetic_t observer; /* Derived from input observer's location. */ + double jd_epoch; /* Computed from the TLE epoch time. */ + double jd_utc; /* Computed from the GPS_TIME t */ + double phase; + vector_t vel; + vector_t pos; + vector_t obs_set; + geodetic_t sat_geodetic; + + /* Outputs. */ + double azimuth; + double elevation; + double range; + double rangeRate; + double height; + double velocity; + +} SAT_POS_DATA; + +double satapi_aos(SAT_POS_DATA *q, bool goto_aos); +int satallite_calculate(SAT_POS_DATA *q); +SAT_POS_DATA * observer_now(SAT_POS_DATA *q); + +AltAz * radec2altaz(double siderealDegrees, GPS_LOCATION_AVERAGE *location, RaDec *radec, AltAz *altaz); +RaDec * altaz2radec(double siderealDegrees, GPS_LOCATION_AVERAGE *location, AltAz *altaz, RaDec *radec); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sdcard/sdcard.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,126 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#include "sowb.h" +#include "user.h" +#include "debug.h" +#include "rit.h" +#include "gps.h" +#include "gpio.h" +#include "ff.h" + +FATFS MyFileSystem; +bool card_detected_A; +bool card_detected_B; +bool card_mounted; +bool card_bad; +uint32_t sdcard_detect_shift_register; + +/** sdcard_is_mounted + * + * Tell the caller if an SD card is mounted. + * + * @return bool True if a card is mounted, false otherwise. + */ +bool sdcard_is_mounted(void) { + return card_mounted; +} + +/** sdcard_init() + */ +void sdcard_init(void) { + DEBUG_INIT_START; + card_bad = false; + card_mounted = false; + card_detected_A = false; + card_detected_B = false; + sdcard_detect_shift_register = 0; + rit_timer_set_counter(SDCARD_TIMER_CB, 10); + DEBUG_INIT_END; +} + +/** sdcard_process() + */ +void sdcard_process(void) { + int retry; + int f_return; + DIR root_directory; + + /* card_detected_A is set by the RIT timer callback below which performs + a rough debounce of the switch. So, if here we need to do a rising + edge detect so we only flag a card insertion once. */ + if (card_detected_A && !card_detected_B && !card_mounted && !card_bad) { + card_detected_B = true; + debug_printf("Card insertion detected.\r\n"); + /* Have found that some cards require a "kick" to bring them to + life. So we retry 3 times to init the card. If after 3 tries + it fails we mark the card as "bad". */ + for(retry = 0; retry < 3; retry++) { + KICK_WATCHDOG; + f_return = f_mount(0,&MyFileSystem); + if (f_return == FR_OK) { + f_return = f_opendir(&root_directory, "/"); + if (f_return == FR_OK) { + card_mounted = true; + debug_printf("SD card mounted.\r\n"); + retry = 3; /* Break loop. */ + } + } + } + + if (!card_mounted) { + card_bad = true; + debug_printf("Failed to mount SD Card\r\n"); + } + } +} + +/** _sdcard_timer_callback + * + * RIT timer callback. + * @see rit.c + */ +void _sdcard_timer_callback(int index) { + + /* Shift left 1bit... */ + sdcard_detect_shift_register = sdcard_detect_shift_register << 1; + + /* And then mask in bit0 position. */ + if (SDCARD_DETECT != 0) { + sdcard_detect_shift_register |= 1; + } + + /* 16 consecutive 1s mean card detected. Rough debouncing of the + mechanical "card detect" switch in the SD card holder. */ + if ((sdcard_detect_shift_register & 0x0000FFFFUL) == 0x0000FFFFUL) { + card_detected_A = true; + } + else { + card_bad = false; + card_mounted = false; + card_detected_A = false; + card_detected_B = false; + } + + /* Restart timer. */ + rit_timer_set_counter(SDCARD_TIMER_CB, 10); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sdcard/sdcard.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,30 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef SDCARD_H +#define SDCARD_H + +bool sdcard_is_mounted(void); +void sdcard_init(void); +void sdcard_process(void); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sgp4sdp4/sgp4sdp4.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,1077 @@ +/* + * Unit SGP4SDP4 + * Author: Dr TS Kelso + * Original Version: 1991 Oct 30 + * Current Revision: 1992 Sep 03 + * Version: 1.50 + * Copyright: 1991-1992, All Rights Reserved + * + * Ported to C by: Neoklis Kyriazis April 10 2001 + */ + +#include "sgp4sdp4.h" + +/* SGP4 */ +/* This function is used to calculate the position and velocity */ +/* of near-earth (period < 225 minutes) satellites. tsince is */ +/* time since epoch in minutes, tle is a pointer to a tle_t */ +/* structure with Keplerian orbital elements and pos and vel */ +/* are vector_t structures returning ECI satellite position and */ +/* velocity. Use Convert_Sat_State() to convert to km and km/s.*/ +void +SGP4(double tsince, tle_t *tle, vector_t *pos, vector_t *vel, double* phase) +{ + static double + aodp,aycof,c1,c4,c5,cosio,d2,d3,d4,delmo,omgcof, + eta,omgdot,sinio,xnodp,sinmo,t2cof,t3cof,t4cof,t5cof, + x1mth2,x3thm1,x7thm1,xmcof,xmdot,xnodcf,xnodot,xlcof; + + double + cosuk,sinuk,rfdotk,vx,vy,vz,ux,uy,uz,xmy,xmx, + cosnok,sinnok,cosik,sinik,rdotk,xinck,xnodek,uk, + rk,cos2u,sin2u,u,sinu,cosu,betal,rfdot,rdot,r,pl, + elsq,esine,ecose,epw,cosepw,x1m5th,xhdot1,tfour, + sinepw,capu,ayn,xlt,aynl,xll,axn,xn,beta,xl,e,a, + tcube,delm,delomg,templ,tempe,tempa,xnode,tsq,xmp, + omega,xnoddf,omgadf,xmdf,a1,a3ovk2,ao,betao,betao2, + c1sq,c2,c3,coef,coef1,del1,delo,eeta,eosq,etasq, + perige,pinvsq,psisq,qoms24,s4,temp,temp1,temp2, + temp3,temp4,temp5,temp6,theta2,theta4,tsi; + + int i; + + /* Initialization */ + if (isFlagClear(SGP4_INITIALIZED_FLAG)) + { + SetFlag(SGP4_INITIALIZED_FLAG); + + /* Recover original mean motion (xnodp) and */ + /* semimajor axis (aodp) from input elements. */ + a1 = pow(xke/tle->xno,tothrd); + cosio = cos(tle->xincl); + theta2 = cosio*cosio; + x3thm1 = 3*theta2-1.0; + eosq = tle->eo*tle->eo; + betao2 = 1-eosq; + betao = sqrt(betao2); + del1 = 1.5*ck2*x3thm1/(a1*a1*betao*betao2); + ao = a1*(1-del1*(0.5*tothrd+del1*(1+134/81*del1))); + delo = 1.5*ck2*x3thm1/(ao*ao*betao*betao2); + xnodp = tle->xno/(1+delo); + aodp = ao/(1-delo); + + /* For perigee less than 220 kilometers, the "simple" flag is set */ + /* and the equations are truncated to linear variation in sqrt a */ + /* and quadratic variation in mean anomaly. Also, the c3 term, */ + /* the delta omega term, and the delta m term are dropped. */ + if((aodp*(1-tle->eo)/ae) < (220/xkmper+ae)) + SetFlag(SIMPLE_FLAG); + else + ClearFlag(SIMPLE_FLAG); + + /* For perigee below 156 km, the */ + /* values of s and qoms2t are altered. */ + s4 = __s__; + qoms24 = qoms2t; + perige = (aodp*(1-tle->eo)-ae)*xkmper; + if(perige < 156) + { + if(perige <= 98) + s4 = 20; + else + s4 = perige-78; + qoms24 = pow((120-s4)*ae/xkmper,4); + s4 = s4/xkmper+ae; + }; /* End of if(perige <= 98) */ + + pinvsq = 1/(aodp*aodp*betao2*betao2); + tsi = 1/(aodp-s4); + eta = aodp*tle->eo*tsi; + etasq = eta*eta; + eeta = tle->eo*eta; + psisq = fabs(1-etasq); + coef = qoms24*pow(tsi,4); + coef1 = coef/pow(psisq,3.5); + c2 = coef1*xnodp*(aodp*(1+1.5*etasq+eeta*(4+etasq))+ + 0.75*ck2*tsi/psisq*x3thm1*(8+3*etasq*(8+etasq))); + c1 = tle->bstar*c2; + sinio = sin(tle->xincl); + a3ovk2 = -xj3/ck2*pow(ae,3); + c3 = coef*tsi*a3ovk2*xnodp*ae*sinio/tle->eo; + x1mth2 = 1-theta2; + c4 = 2*xnodp*coef1*aodp*betao2*(eta*(2+0.5*etasq)+ + tle->eo*(0.5+2*etasq)-2*ck2*tsi/(aodp*psisq)* + (-3*x3thm1*(1-2*eeta+etasq*(1.5-0.5*eeta))+0.75* + x1mth2*(2*etasq-eeta*(1+etasq))*cos(2*tle->omegao))); + c5 = 2*coef1*aodp*betao2*(1+2.75*(etasq+eeta)+eeta*etasq); + theta4 = theta2*theta2; + temp1 = 3*ck2*pinvsq*xnodp; + temp2 = temp1*ck2*pinvsq; + temp3 = 1.25*ck4*pinvsq*pinvsq*xnodp; + xmdot = xnodp+0.5*temp1*betao*x3thm1+ + 0.0625*temp2*betao*(13-78*theta2+137*theta4); + x1m5th = 1-5*theta2; + omgdot = -0.5*temp1*x1m5th+0.0625*temp2*(7-114*theta2+ + 395*theta4)+temp3*(3-36*theta2+49*theta4); + xhdot1 = -temp1*cosio; + xnodot = xhdot1+(0.5*temp2*(4-19*theta2)+ + 2*temp3*(3-7*theta2))*cosio; + omgcof = tle->bstar*c3*cos(tle->omegao); + xmcof = -tothrd*coef*tle->bstar*ae/eeta; + xnodcf = 3.5*betao2*xhdot1*c1; + t2cof = 1.5*c1; + xlcof = 0.125*a3ovk2*sinio*(3+5*cosio)/(1+cosio); + aycof = 0.25*a3ovk2*sinio; + delmo = pow(1+eta*cos(tle->xmo),3); + sinmo = sin(tle->xmo); + x7thm1 = 7*theta2-1; + if (isFlagClear(SIMPLE_FLAG)) + { + c1sq = c1*c1; + d2 = 4*aodp*tsi*c1sq; + temp = d2*tsi*c1/3; + d3 = (17*aodp+s4)*temp; + d4 = 0.5*temp*aodp*tsi*(221*aodp+31*s4)*c1; + t3cof = d2+2*c1sq; + t4cof = 0.25*(3*d3+c1*(12*d2+10*c1sq)); + t5cof = 0.2*(3*d4+12*c1*d3+6*d2*d2+15*c1sq*(2*d2+c1sq)); + }; /* End of if (isFlagClear(SIMPLE_FLAG)) */ + }; /* End of SGP4() initialization */ + + /* Update for secular gravity and atmospheric drag. */ + xmdf = tle->xmo+xmdot*tsince; + omgadf = tle->omegao+omgdot*tsince; + xnoddf = tle->xnodeo+xnodot*tsince; + omega = omgadf; + xmp = xmdf; + tsq = tsince*tsince; + xnode = xnoddf+xnodcf*tsq; + tempa = 1-c1*tsince; + tempe = tle->bstar*c4*tsince; + templ = t2cof*tsq; + if (isFlagClear(SIMPLE_FLAG)) + { + delomg = omgcof*tsince; + delm = xmcof*(pow(1+eta*cos(xmdf),3)-delmo); + temp = delomg+delm; + xmp = xmdf+temp; + omega = omgadf-temp; + tcube = tsq*tsince; + tfour = tsince*tcube; + tempa = tempa-d2*tsq-d3*tcube-d4*tfour; + tempe = tempe+tle->bstar*c5*(sin(xmp)-sinmo); + templ = templ+t3cof*tcube+tfour*(t4cof+tsince*t5cof); + }; /* End of if (isFlagClear(SIMPLE_FLAG)) */ + + a = aodp*pow(tempa,2); + e = tle->eo-tempe; + xl = xmp+omega+xnode+xnodp*templ; + beta = sqrt(1-e*e); + xn = xke/pow(a,1.5); + + /* Long period periodics */ + axn = e*cos(omega); + temp = 1/(a*beta*beta); + xll = temp*xlcof*axn; + aynl = temp*aycof; + xlt = xl+xll; + ayn = e*sin(omega)+aynl; + + /* Solve Kepler's' Equation */ + capu = FMod2p(xlt-xnode); + temp2 = capu; + + i = 0; + do + { + sinepw = sin(temp2); + cosepw = cos(temp2); + temp3 = axn*sinepw; + temp4 = ayn*cosepw; + temp5 = axn*cosepw; + temp6 = ayn*sinepw; + epw = (capu-temp4+temp3-temp2)/(1-temp5-temp6)+temp2; + if(fabs(epw-temp2) <= e6a) break; + temp2 = epw; + } + while( i++ < 10 ); + + /* Short period preliminary quantities */ + ecose = temp5+temp6; + esine = temp3-temp4; + elsq = axn*axn+ayn*ayn; + temp = 1-elsq; + pl = a*temp; + r = a*(1-ecose); + temp1 = 1/r; + rdot = xke*sqrt(a)*esine*temp1; + rfdot = xke*sqrt(pl)*temp1; + temp2 = a*temp1; + betal = sqrt(temp); + temp3 = 1/(1+betal); + cosu = temp2*(cosepw-axn+ayn*esine*temp3); + sinu = temp2*(sinepw-ayn-axn*esine*temp3); + u = AcTan(sinu, cosu); + sin2u = 2*sinu*cosu; + cos2u = 2*cosu*cosu-1; + temp = 1/pl; + temp1 = ck2*temp; + temp2 = temp1*temp; + + /* Update for short periodics */ + rk = r*(1-1.5*temp2*betal*x3thm1)+0.5*temp1*x1mth2*cos2u; + uk = u-0.25*temp2*x7thm1*sin2u; + xnodek = xnode+1.5*temp2*cosio*sin2u; + xinck = tle->xincl+1.5*temp2*cosio*sinio*cos2u; + rdotk = rdot-xn*temp1*x1mth2*sin2u; + rfdotk = rfdot+xn*temp1*(x1mth2*cos2u+1.5*x3thm1); + + /* Orientation vectors */ + sinuk = sin(uk); + cosuk = cos(uk); + sinik = sin(xinck); + cosik = cos(xinck); + sinnok = sin(xnodek); + cosnok = cos(xnodek); + xmx = -sinnok*cosik; + xmy = cosnok*cosik; + ux = xmx*sinuk+cosnok*cosuk; + uy = xmy*sinuk+sinnok*cosuk; + uz = sinik*sinuk; + vx = xmx*cosuk-cosnok*sinuk; + vy = xmy*cosuk-sinnok*sinuk; + vz = sinik*cosuk; + + /* Position and velocity */ + pos->x = rk*ux; + pos->y = rk*uy; + pos->z = rk*uz; + vel->x = rdotk*ux+rfdotk*vx; + vel->y = rdotk*uy+rfdotk*vy; + vel->z = rdotk*uz+rfdotk*vz; + + *phase = xlt-xnode-omgadf+twopi; + if(*phase < 0) *phase += twopi; + *phase = FMod2p(*phase); + + tle->omegao1=omega; + tle->xincl1=xinck; + tle->xnodeo1=xnodek; + +} /*SGP4*/ + +/*------------------------------------------------------------------*/ + +/* SDP4 */ +/* This function is used to calculate the position and velocity */ +/* of deep-space (period > 225 minutes) satellites. tsince is */ +/* time since epoch in minutes, tle is a pointer to a tle_t */ +/* structure with Keplerian orbital elements and pos and vel */ +/* are vector_t structures returning ECI satellite position and */ +/* velocity. Use Convert_Sat_State() to convert to km and km/s. */ +void +SDP4(double tsince, tle_t *tle, vector_t *pos, vector_t *vel, double* phase) +{ + int i; + + static double + x3thm1,c1,x1mth2,c4,xnodcf,t2cof,xlcof,aycof,x7thm1; + + double + a,axn,ayn,aynl,beta,betal,capu,cos2u,cosepw,cosik, + cosnok,cosu,cosuk,ecose,elsq,epw,esine,pl,theta4, + rdot,rdotk,rfdot,rfdotk,rk,sin2u,sinepw,sinik, + sinnok,sinu,sinuk,tempe,templ,tsq,u,uk,ux,uy,uz, + vx,vy,vz,xinck,xl,xlt,xmam,xmdf,xmx,xmy,xnoddf, + xnodek,xll,a1,a3ovk2,ao,c2,coef,coef1,x1m5th, + xhdot1,del1,r,delo,eeta,eta,etasq,perige, + psisq,tsi,qoms24,s4,pinvsq,temp,tempa,temp1, + temp2,temp3,temp4,temp5,temp6; + + static deep_arg_t deep_arg; + + /* Initialization */ + if (isFlagClear(SDP4_INITIALIZED_FLAG)) + { + SetFlag(SDP4_INITIALIZED_FLAG); + + /* Recover original mean motion (xnodp) and */ + /* semimajor axis (aodp) from input elements. */ + a1 = pow(xke/tle->xno,tothrd); + deep_arg.cosio = cos(tle->xincl); + deep_arg.theta2 = deep_arg.cosio*deep_arg.cosio; + x3thm1 = 3*deep_arg.theta2-1; + deep_arg.eosq = tle->eo*tle->eo; + deep_arg.betao2 = 1-deep_arg.eosq; + deep_arg.betao = sqrt(deep_arg.betao2); + del1 = 1.5*ck2*x3thm1/(a1*a1*deep_arg.betao*deep_arg.betao2); + ao = a1*(1-del1*(0.5*tothrd+del1*(1+134/81*del1))); + delo = 1.5*ck2*x3thm1/(ao*ao*deep_arg.betao*deep_arg.betao2); + deep_arg.xnodp = tle->xno/(1+delo); + deep_arg.aodp = ao/(1-delo); + + /* For perigee below 156 km, the values */ + /* of s and qoms2t are altered. */ + s4 = __s__; + qoms24 = qoms2t; + perige = (deep_arg.aodp*(1-tle->eo)-ae)*xkmper; + if(perige < 156) + { + if(perige <= 98) + s4 = 20; + else + s4 = perige-78; + qoms24 = pow((120-s4)*ae/xkmper,4); + s4 = s4/xkmper+ae; + } + pinvsq = 1/(deep_arg.aodp*deep_arg.aodp* + deep_arg.betao2*deep_arg.betao2); + deep_arg.sing = sin(tle->omegao); + deep_arg.cosg = cos(tle->omegao); + tsi = 1/(deep_arg.aodp-s4); + eta = deep_arg.aodp*tle->eo*tsi; + etasq = eta*eta; + eeta = tle->eo*eta; + psisq = fabs(1-etasq); + coef = qoms24*pow(tsi,4); + coef1 = coef/pow(psisq,3.5); + c2 = coef1*deep_arg.xnodp*(deep_arg.aodp*(1+1.5*etasq+eeta* + (4+etasq))+0.75*ck2*tsi/psisq*x3thm1*(8+3*etasq*(8+etasq))); + c1 = tle->bstar*c2; + deep_arg.sinio = sin(tle->xincl); + a3ovk2 = -xj3/ck2*pow(ae,3); + x1mth2 = 1-deep_arg.theta2; + c4 = 2*deep_arg.xnodp*coef1*deep_arg.aodp*deep_arg.betao2* + (eta*(2+0.5*etasq)+tle->eo*(0.5+2*etasq)-2*ck2*tsi/ + (deep_arg.aodp*psisq)*(-3*x3thm1*(1-2*eeta+etasq* + (1.5-0.5*eeta))+0.75*x1mth2*(2*etasq-eeta*(1+etasq))* + cos(2*tle->omegao))); + theta4 = deep_arg.theta2*deep_arg.theta2; + temp1 = 3*ck2*pinvsq*deep_arg.xnodp; + temp2 = temp1*ck2*pinvsq; + temp3 = 1.25*ck4*pinvsq*pinvsq*deep_arg.xnodp; + deep_arg.xmdot = deep_arg.xnodp+0.5*temp1*deep_arg.betao* + x3thm1+0.0625*temp2*deep_arg.betao* + (13-78*deep_arg.theta2+137*theta4); + x1m5th = 1-5*deep_arg.theta2; + deep_arg.omgdot = -0.5*temp1*x1m5th+0.0625*temp2* + (7-114*deep_arg.theta2+395*theta4)+ + temp3*(3-36*deep_arg.theta2+49*theta4); + xhdot1 = -temp1*deep_arg.cosio; + deep_arg.xnodot = xhdot1+(0.5*temp2*(4-19*deep_arg.theta2)+ + 2*temp3*(3-7*deep_arg.theta2))*deep_arg.cosio; + xnodcf = 3.5*deep_arg.betao2*xhdot1*c1; + t2cof = 1.5*c1; + xlcof = 0.125*a3ovk2*deep_arg.sinio*(3+5*deep_arg.cosio)/ + (1+deep_arg.cosio); + aycof = 0.25*a3ovk2*deep_arg.sinio; + x7thm1 = 7*deep_arg.theta2-1; + + /* initialize Deep() */ + Deep(dpinit, tle, &deep_arg); + }; /*End of SDP4() initialization */ + + /* Update for secular gravity and atmospheric drag */ + xmdf = tle->xmo+deep_arg.xmdot*tsince; + deep_arg.omgadf = tle->omegao+deep_arg.omgdot*tsince; + xnoddf = tle->xnodeo+deep_arg.xnodot*tsince; + tsq = tsince*tsince; + deep_arg.xnode = xnoddf+xnodcf*tsq; + tempa = 1-c1*tsince; + tempe = tle->bstar*c4*tsince; + templ = t2cof*tsq; + deep_arg.xn = deep_arg.xnodp; + + /* Update for deep-space secular effects */ + deep_arg.xll = xmdf; + deep_arg.t = tsince; + + Deep(dpsec, tle, &deep_arg); + + xmdf = deep_arg.xll; + a = pow(xke/deep_arg.xn,tothrd)*tempa*tempa; + deep_arg.em = deep_arg.em-tempe; + xmam = xmdf+deep_arg.xnodp*templ; + + /* Update for deep-space periodic effects */ + deep_arg.xll = xmam; + + Deep(dpper, tle, &deep_arg); + + xmam = deep_arg.xll; + xl = xmam+deep_arg.omgadf+deep_arg.xnode; + beta = sqrt(1-deep_arg.em*deep_arg.em); + deep_arg.xn = xke/pow(a,1.5); + + /* Long period periodics */ + axn = deep_arg.em*cos(deep_arg.omgadf); + temp = 1/(a*beta*beta); + xll = temp*xlcof*axn; + aynl = temp*aycof; + xlt = xl+xll; + ayn = deep_arg.em*sin(deep_arg.omgadf)+aynl; + + /* Solve Kepler's Equation */ + capu = FMod2p(xlt-deep_arg.xnode); + temp2 = capu; + + i = 0; + do + { + sinepw = sin(temp2); + cosepw = cos(temp2); + temp3 = axn*sinepw; + temp4 = ayn*cosepw; + temp5 = axn*cosepw; + temp6 = ayn*sinepw; + epw = (capu-temp4+temp3-temp2)/(1-temp5-temp6)+temp2; + if(fabs(epw-temp2) <= e6a) break; + temp2 = epw; + } + while( i++ < 10 ); + + /* Short period preliminary quantities */ + ecose = temp5+temp6; + esine = temp3-temp4; + elsq = axn*axn+ayn*ayn; + temp = 1-elsq; + pl = a*temp; + r = a*(1-ecose); + temp1 = 1/r; + rdot = xke*sqrt(a)*esine*temp1; + rfdot = xke*sqrt(pl)*temp1; + temp2 = a*temp1; + betal = sqrt(temp); + temp3 = 1/(1+betal); + cosu = temp2*(cosepw-axn+ayn*esine*temp3); + sinu = temp2*(sinepw-ayn-axn*esine*temp3); + u = AcTan(sinu,cosu); + sin2u = 2*sinu*cosu; + cos2u = 2*cosu*cosu-1; + temp = 1/pl; + temp1 = ck2*temp; + temp2 = temp1*temp; + + /* Update for short periodics */ + rk = r*(1-1.5*temp2*betal*x3thm1)+0.5*temp1*x1mth2*cos2u; + uk = u-0.25*temp2*x7thm1*sin2u; + xnodek = deep_arg.xnode+1.5*temp2*deep_arg.cosio*sin2u; + xinck = deep_arg.xinc+1.5*temp2*deep_arg.cosio*deep_arg.sinio*cos2u; + rdotk = rdot-deep_arg.xn*temp1*x1mth2*sin2u; + rfdotk = rfdot+deep_arg.xn*temp1*(x1mth2*cos2u+1.5*x3thm1); + + /* Orientation vectors */ + sinuk = sin(uk); + cosuk = cos(uk); + sinik = sin(xinck); + cosik = cos(xinck); + sinnok = sin(xnodek); + cosnok = cos(xnodek); + xmx = -sinnok*cosik; + xmy = cosnok*cosik; + ux = xmx*sinuk+cosnok*cosuk; + uy = xmy*sinuk+sinnok*cosuk; + uz = sinik*sinuk; + vx = xmx*cosuk-cosnok*sinuk; + vy = xmy*cosuk-sinnok*sinuk; + vz = sinik*cosuk; + + /* Position and velocity */ + pos->x = rk*ux; + pos->y = rk*uy; + pos->z = rk*uz; + vel->x = rdotk*ux+rfdotk*vx; + vel->y = rdotk*uy+rfdotk*vy; + vel->z = rdotk*uz+rfdotk*vz; + + /* Phase in rads */ + *phase = xlt-deep_arg.xnode-deep_arg.omgadf+twopi; + if(*phase < 0) *phase += twopi; + *phase = FMod2p(*phase); + + tle->omegao1=deep_arg.omgadf; + tle->xincl1=deep_arg.xinc; + tle->xnodeo1=deep_arg.xnode; +} /* SDP4 */ + +/*------------------------------------------------------------------*/ + +/* DEEP */ +/* This function is used by SDP4 to add lunar and solar */ +/* perturbation effects to deep-space orbit objects. */ +void +Deep(int ientry, tle_t *tle, deep_arg_t *deep_arg) +{ + static double + thgr,xnq,xqncl,omegaq,zmol,zmos,savtsn,ee2,e3,xi2, + xl2,xl3,xl4,xgh2,xgh3,xgh4,xh2,xh3,sse,ssi,ssg,xi3, + se2,si2,sl2,sgh2,sh2,se3,si3,sl3,sgh3,sh3,sl4,sgh4, + ssl,ssh,d3210,d3222,d4410,d4422,d5220,d5232,d5421, + d5433,del1,del2,del3,fasx2,fasx4,fasx6,xlamo,xfact, + xni,atime,stepp,stepn,step2,preep,pl,sghs,xli, + d2201,d2211,sghl,sh1,pinc,pe,shs,zsingl,zcosgl, + zsinhl,zcoshl,zsinil,zcosil; + + double + a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,ainv2,alfdp,aqnv, + sgh,sini2,sinis,sinok,sh,si,sil,day,betdp,dalf, + bfact,c,cc,cosis,cosok,cosq,ctem,f322,zx,zy, + dbet,dls,eoc,eq,f2,f220,f221,f3,f311,f321,xnoh, + f330,f441,f442,f522,f523,f542,f543,g200,g201, + g211,pgh,ph,s1,s2,s3,s4,s5,s6,s7,se,sel,ses,xls, + g300,g310,g322,g410,g422,g520,g521,g532,g533,gam, + sinq,sinzf,sis,sl,sll,sls,stem,temp,temp1,x1,x2, + x2li,x2omi,x3,x4,x5,x6,x7,x8,xl,xldot,xmao,xnddt, + xndot,xno2,xnodce,xnoi,xomi,xpidot,z1,z11,z12,z13, + z2,z21,z22,z23,z3,z31,z32,z33,ze,zf,zm,/* zmo, (see below) */zn, + zsing,zsinh,zsini,zcosg,zcosh,zcosi,delt=0,ft=0; + + /* Compiler complains defined but not used. I never like to + edit other peoples libraries but I also dislike compiler + warnings. AjK, 7th Sep 2010. */ + double zmo __attribute__((unused)); + + switch(ientry) + { + case dpinit : /* Entrance for deep space initialization */ + thgr = ThetaG(tle->epoch, deep_arg); + eq = tle->eo; + xnq = deep_arg->xnodp; + aqnv = 1/deep_arg->aodp; + xqncl = tle->xincl; + xmao = tle->xmo; + xpidot = deep_arg->omgdot+deep_arg->xnodot; + sinq = sin(tle->xnodeo); + cosq = cos(tle->xnodeo); + omegaq = tle->omegao; + + /* Initialize lunar solar terms */ + day = deep_arg->ds50+18261.5; /*Days since 1900 Jan 0.5*/ + if (day != preep) + { + preep = day; + xnodce = 4.5236020-9.2422029E-4*day; + stem = sin(xnodce); + ctem = cos(xnodce); + zcosil = 0.91375164-0.03568096*ctem; + zsinil = sqrt(1-zcosil*zcosil); + zsinhl = 0.089683511*stem/zsinil; + zcoshl = sqrt(1-zsinhl*zsinhl); + c = 4.7199672+0.22997150*day; + gam = 5.8351514+0.0019443680*day; + zmol = FMod2p(c-gam); + zx = 0.39785416*stem/zsinil; + zy = zcoshl*ctem+0.91744867*zsinhl*stem; + zx = AcTan(zx,zy); + zx = gam+zx-xnodce; + zcosgl = cos(zx); + zsingl = sin(zx); + zmos = 6.2565837+0.017201977*day; + zmos = FMod2p(zmos); + } /* End if(day != preep) */ + + /* Do solar terms */ + savtsn = 1E20; + zcosg = zcosgs; + zsing = zsings; + zcosi = zcosis; + zsini = zsinis; + zcosh = cosq; + zsinh = sinq; + cc = c1ss; + zn = zns; + ze = zes; + zmo = zmos; + xnoi = 1/xnq; + + /* Loop breaks when Solar terms are done a second */ + /* time, after Lunar terms are initialized */ + for(;;) + { + /* Solar terms done again after Lunar terms are done */ + a1 = zcosg*zcosh+zsing*zcosi*zsinh; + a3 = -zsing*zcosh+zcosg*zcosi*zsinh; + a7 = -zcosg*zsinh+zsing*zcosi*zcosh; + a8 = zsing*zsini; + a9 = zsing*zsinh+zcosg*zcosi*zcosh; + a10 = zcosg*zsini; + a2 = deep_arg->cosio*a7+ deep_arg->sinio*a8; + a4 = deep_arg->cosio*a9+ deep_arg->sinio*a10; + a5 = -deep_arg->sinio*a7+ deep_arg->cosio*a8; + a6 = -deep_arg->sinio*a9+ deep_arg->cosio*a10; + x1 = a1*deep_arg->cosg+a2*deep_arg->sing; + x2 = a3*deep_arg->cosg+a4*deep_arg->sing; + x3 = -a1*deep_arg->sing+a2*deep_arg->cosg; + x4 = -a3*deep_arg->sing+a4*deep_arg->cosg; + x5 = a5*deep_arg->sing; + x6 = a6*deep_arg->sing; + x7 = a5*deep_arg->cosg; + x8 = a6*deep_arg->cosg; + z31 = 12*x1*x1-3*x3*x3; + z32 = 24*x1*x2-6*x3*x4; + z33 = 12*x2*x2-3*x4*x4; + z1 = 3*(a1*a1+a2*a2)+z31*deep_arg->eosq; + z2 = 6*(a1*a3+a2*a4)+z32*deep_arg->eosq; + z3 = 3*(a3*a3+a4*a4)+z33*deep_arg->eosq; + z11 = -6*a1*a5+deep_arg->eosq*(-24*x1*x7-6*x3*x5); + z12 = -6*(a1*a6+a3*a5)+ deep_arg->eosq* + (-24*(x2*x7+x1*x8)-6*(x3*x6+x4*x5)); + z13 = -6*a3*a6+deep_arg->eosq*(-24*x2*x8-6*x4*x6); + z21 = 6*a2*a5+deep_arg->eosq*(24*x1*x5-6*x3*x7); + z22 = 6*(a4*a5+a2*a6)+ deep_arg->eosq* + (24*(x2*x5+x1*x6)-6*(x4*x7+x3*x8)); + z23 = 6*a4*a6+deep_arg->eosq*(24*x2*x6-6*x4*x8); + z1 = z1+z1+deep_arg->betao2*z31; + z2 = z2+z2+deep_arg->betao2*z32; + z3 = z3+z3+deep_arg->betao2*z33; + s3 = cc*xnoi; + s2 = -0.5*s3/deep_arg->betao; + s4 = s3*deep_arg->betao; + s1 = -15*eq*s4; + s5 = x1*x3+x2*x4; + s6 = x2*x3+x1*x4; + s7 = x2*x4-x1*x3; + se = s1*zn*s5; + si = s2*zn*(z11+z13); + sl = -zn*s3*(z1+z3-14-6*deep_arg->eosq); + sgh = s4*zn*(z31+z33-6); + sh = -zn*s2*(z21+z23); + if (xqncl < 5.2359877E-2) sh = 0; + ee2 = 2*s1*s6; + e3 = 2*s1*s7; + xi2 = 2*s2*z12; + xi3 = 2*s2*(z13-z11); + xl2 = -2*s3*z2; + xl3 = -2*s3*(z3-z1); + xl4 = -2*s3*(-21-9*deep_arg->eosq)*ze; + xgh2 = 2*s4*z32; + xgh3 = 2*s4*(z33-z31); + xgh4 = -18*s4*ze; + xh2 = -2*s2*z22; + xh3 = -2*s2*(z23-z21); + + if(isFlagSet(LUNAR_TERMS_DONE_FLAG)) break; + + /* Do lunar terms */ + sse = se; + ssi = si; + ssl = sl; + ssh = sh/deep_arg->sinio; + ssg = sgh-deep_arg->cosio*ssh; + se2 = ee2; + si2 = xi2; + sl2 = xl2; + sgh2 = xgh2; + sh2 = xh2; + se3 = e3; + si3 = xi3; + sl3 = xl3; + sgh3 = xgh3; + sh3 = xh3; + sl4 = xl4; + sgh4 = xgh4; + zcosg = zcosgl; + zsing = zsingl; + zcosi = zcosil; + zsini = zsinil; + zcosh = zcoshl*cosq+zsinhl*sinq; + zsinh = sinq*zcoshl-cosq*zsinhl; + zn = znl; + cc = c1l; + ze = zel; + zmo = zmol; + SetFlag(LUNAR_TERMS_DONE_FLAG); + } /* End of for(;;) */ + + sse = sse+se; + ssi = ssi+si; + ssl = ssl+sl; + ssg = ssg+sgh-deep_arg->cosio/deep_arg->sinio*sh; + ssh = ssh+sh/deep_arg->sinio; + + /* Geopotential resonance initialization for 12 hour orbits */ + ClearFlag(RESONANCE_FLAG); + ClearFlag(SYNCHRONOUS_FLAG); + + if( !((xnq < 0.0052359877) && (xnq > 0.0034906585)) ) + { + if( (xnq < 0.00826) || (xnq > 0.00924) ) return; + if (eq < 0.5) return; + SetFlag(RESONANCE_FLAG); + eoc = eq*deep_arg->eosq; + g201 = -0.306-(eq-0.64)*0.440; + if (eq <= 0.65) + { + g211 = 3.616-13.247*eq+16.290*deep_arg->eosq; + g310 = -19.302+117.390*eq-228.419* + deep_arg->eosq+156.591*eoc; + g322 = -18.9068+109.7927*eq-214.6334* + deep_arg->eosq+146.5816*eoc; + g410 = -41.122+242.694*eq-471.094* + deep_arg->eosq+313.953*eoc; + g422 = -146.407+841.880*eq-1629.014* + deep_arg->eosq+1083.435*eoc; + g520 = -532.114+3017.977*eq-5740* + deep_arg->eosq+3708.276*eoc; + } + else + { + g211 = -72.099+331.819*eq-508.738* + deep_arg->eosq+266.724*eoc; + g310 = -346.844+1582.851*eq-2415.925* + deep_arg->eosq+1246.113*eoc; + g322 = -342.585+1554.908*eq-2366.899* + deep_arg->eosq+1215.972*eoc; + g410 = -1052.797+4758.686*eq-7193.992* + deep_arg->eosq+3651.957*eoc; + g422 = -3581.69+16178.11*eq-24462.77* + deep_arg->eosq+ 12422.52*eoc; + if (eq <= 0.715) + g520 = 1464.74-4664.75*eq+3763.64*deep_arg->eosq; + else + g520 = -5149.66+29936.92*eq-54087.36* + deep_arg->eosq+31324.56*eoc; + } /* End if (eq <= 0.65) */ + + if (eq < 0.7) + { + g533 = -919.2277+4988.61*eq-9064.77* + deep_arg->eosq+5542.21*eoc; + g521 = -822.71072+4568.6173*eq-8491.4146* + deep_arg->eosq+5337.524*eoc; + g532 = -853.666+4690.25*eq-8624.77* + deep_arg->eosq+ 5341.4*eoc; + } + else + { + g533 = -37995.78+161616.52*eq-229838.2* + deep_arg->eosq+109377.94*eoc; + g521 = -51752.104+218913.95*eq-309468.16* + deep_arg->eosq+146349.42*eoc; + g532 = -40023.88+170470.89*eq-242699.48* + deep_arg->eosq+115605.82*eoc; + } /* End if (eq <= 0.7) */ + + sini2 = deep_arg->sinio*deep_arg->sinio; + f220 = 0.75*(1+2*deep_arg->cosio+deep_arg->theta2); + f221 = 1.5*sini2; + f321 = 1.875*deep_arg->sinio*(1-2*\ + deep_arg->cosio-3*deep_arg->theta2); + f322 = -1.875*deep_arg->sinio*(1+2* + deep_arg->cosio-3*deep_arg->theta2); + f441 = 35*sini2*f220; + f442 = 39.3750*sini2*sini2; + f522 = 9.84375*deep_arg->sinio*(sini2*(1-2*deep_arg->cosio-5* + deep_arg->theta2)+0.33333333*(-2+4*deep_arg->cosio+ + 6*deep_arg->theta2)); + f523 = deep_arg->sinio*(4.92187512*sini2*(-2-4* + deep_arg->cosio+10*deep_arg->theta2)+6.56250012 + *(1+2*deep_arg->cosio-3*deep_arg->theta2)); + f542 = 29.53125*deep_arg->sinio*(2-8* + deep_arg->cosio+deep_arg->theta2* + (-12+8*deep_arg->cosio+10*deep_arg->theta2)); + f543 = 29.53125*deep_arg->sinio*(-2-8*deep_arg->cosio+ + deep_arg->theta2*(12+8*deep_arg->cosio-10* + deep_arg->theta2)); + xno2 = xnq*xnq; + ainv2 = aqnv*aqnv; + temp1 = 3*xno2*ainv2; + temp = temp1*root22; + d2201 = temp*f220*g201; + d2211 = temp*f221*g211; + temp1 = temp1*aqnv; + temp = temp1*root32; + d3210 = temp*f321*g310; + d3222 = temp*f322*g322; + temp1 = temp1*aqnv; + temp = 2*temp1*root44; + d4410 = temp*f441*g410; + d4422 = temp*f442*g422; + temp1 = temp1*aqnv; + temp = temp1*root52; + d5220 = temp*f522*g520; + d5232 = temp*f523*g532; + temp = 2*temp1*root54; + d5421 = temp*f542*g521; + d5433 = temp*f543*g533; + xlamo = xmao+tle->xnodeo+tle->xnodeo-thgr-thgr; + bfact = deep_arg->xmdot+deep_arg->xnodot+ + deep_arg->xnodot-thdt-thdt; + bfact = bfact+ssl+ssh+ssh; + } /* if( !(xnq < 0.0052359877) && (xnq > 0.0034906585) ) */ + else + { + SetFlag(RESONANCE_FLAG); + SetFlag(SYNCHRONOUS_FLAG); + /* Synchronous resonance terms initialization */ + g200 = 1+deep_arg->eosq*(-2.5+0.8125*deep_arg->eosq); + g310 = 1+2*deep_arg->eosq; + g300 = 1+deep_arg->eosq*(-6+6.60937*deep_arg->eosq); + f220 = 0.75*(1+deep_arg->cosio)*(1+deep_arg->cosio); + f311 = 0.9375*deep_arg->sinio*deep_arg->sinio* + (1+3*deep_arg->cosio)-0.75*(1+deep_arg->cosio); + f330 = 1+deep_arg->cosio; + f330 = 1.875*f330*f330*f330; + del1 = 3*xnq*xnq*aqnv*aqnv; + del2 = 2*del1*f220*g200*q22; + del3 = 3*del1*f330*g300*q33*aqnv; + del1 = del1*f311*g310*q31*aqnv; + fasx2 = 0.13130908; + fasx4 = 2.8843198; + fasx6 = 0.37448087; + xlamo = xmao+tle->xnodeo+tle->omegao-thgr; + bfact = deep_arg->xmdot+xpidot-thdt; + bfact = bfact+ssl+ssg+ssh; + } /* End if( !(xnq < 0.0052359877) && (xnq > 0.0034906585) ) */ + + xfact = bfact-xnq; + + /* Initialize integrator */ + xli = xlamo; + xni = xnq; + atime = 0; + stepp = 720; + stepn = -720; + step2 = 259200; + /* End case dpinit: */ + return; + + case dpsec: /* Entrance for deep space secular effects */ + deep_arg->xll = deep_arg->xll+ssl*deep_arg->t; + deep_arg->omgadf = deep_arg->omgadf+ssg*deep_arg->t; + deep_arg->xnode = deep_arg->xnode+ssh*deep_arg->t; + deep_arg->em = tle->eo+sse*deep_arg->t; + deep_arg->xinc = tle->xincl+ssi*deep_arg->t; + if (deep_arg->xinc < 0) + { + deep_arg->xinc = -deep_arg->xinc; + deep_arg->xnode = deep_arg->xnode + pi; + deep_arg->omgadf = deep_arg->omgadf-pi; + } + if( isFlagClear(RESONANCE_FLAG) ) return; + + do + { + if( (atime == 0) || + ((deep_arg->t >= 0) && (atime < 0)) || + ((deep_arg->t < 0) && (atime >= 0)) ) + { + /* Epoch restart */ + if( deep_arg->t >= 0 ) + delt = stepp; + else + delt = stepn; + + atime = 0; + xni = xnq; + xli = xlamo; + } + else + { + if( fabs(deep_arg->t) >= fabs(atime) ) + { + if ( deep_arg->t > 0 ) + delt = stepp; + else + delt = stepn; + } + } + + do + { + if ( fabs(deep_arg->t-atime) >= stepp ) + { + SetFlag(DO_LOOP_FLAG); + ClearFlag(EPOCH_RESTART_FLAG); + } + else + { + ft = deep_arg->t-atime; + ClearFlag(DO_LOOP_FLAG); + } + + if( fabs(deep_arg->t) < fabs(atime) ) + { + if (deep_arg->t >= 0) + delt = stepn; + else + delt = stepp; + SetFlag(DO_LOOP_FLAG | EPOCH_RESTART_FLAG); + } + + /* Dot terms calculated */ + if( isFlagSet(SYNCHRONOUS_FLAG) ) + { + xndot = del1*sin(xli-fasx2)+del2*sin(2*(xli-fasx4)) + +del3*sin(3*(xli-fasx6)); + xnddt = del1*cos(xli-fasx2)+2*del2*cos(2*(xli-fasx4)) + +3*del3*cos(3*(xli-fasx6)); + } + else + { + xomi = omegaq+deep_arg->omgdot*atime; + x2omi = xomi+xomi; + x2li = xli+xli; + xndot = d2201*sin(x2omi+xli-g22) + +d2211*sin(xli-g22) + +d3210*sin(xomi+xli-g32) + +d3222*sin(-xomi+xli-g32) + +d4410*sin(x2omi+x2li-g44) + +d4422*sin(x2li-g44) + +d5220*sin(xomi+xli-g52) + +d5232*sin(-xomi+xli-g52) + +d5421*sin(xomi+x2li-g54) + +d5433*sin(-xomi+x2li-g54); + xnddt = d2201*cos(x2omi+xli-g22) + +d2211*cos(xli-g22) + +d3210*cos(xomi+xli-g32) + +d3222*cos(-xomi+xli-g32) + +d5220*cos(xomi+xli-g52) + +d5232*cos(-xomi+xli-g52) + +2*(d4410*cos(x2omi+x2li-g44) + +d4422*cos(x2li-g44) + +d5421*cos(xomi+x2li-g54) + +d5433*cos(-xomi+x2li-g54)); + } /* End of if (isFlagSet(SYNCHRONOUS_FLAG)) */ + + xldot = xni+xfact; + xnddt = xnddt*xldot; + + if(isFlagSet(DO_LOOP_FLAG)) + { + xli = xli+xldot*delt+xndot*step2; + xni = xni+xndot*delt+xnddt*step2; + atime = atime+delt; + } + } + while(isFlagSet(DO_LOOP_FLAG) && isFlagClear(EPOCH_RESTART_FLAG)); + } + while(isFlagSet(DO_LOOP_FLAG) && isFlagSet(EPOCH_RESTART_FLAG)); + + deep_arg->xn = xni+xndot*ft+xnddt*ft*ft*0.5; + xl = xli+xldot*ft+xndot*ft*ft*0.5; + temp = -deep_arg->xnode+thgr+deep_arg->t*thdt; + + if (isFlagClear(SYNCHRONOUS_FLAG)) + deep_arg->xll = xl+temp+temp; + else + deep_arg->xll = xl-deep_arg->omgadf+temp; + + return; + /*End case dpsec: */ + + case dpper: /* Entrance for lunar-solar periodics */ + sinis = sin(deep_arg->xinc); + cosis = cos(deep_arg->xinc); + if (fabs(savtsn-deep_arg->t) >= 30) + { + savtsn = deep_arg->t; + zm = zmos+zns*deep_arg->t; + zf = zm+2*zes*sin(zm); + sinzf = sin(zf); + f2 = 0.5*sinzf*sinzf-0.25; + f3 = -0.5*sinzf*cos(zf); + ses = se2*f2+se3*f3; + sis = si2*f2+si3*f3; + sls = sl2*f2+sl3*f3+sl4*sinzf; + sghs = sgh2*f2+sgh3*f3+sgh4*sinzf; + shs = sh2*f2+sh3*f3; + zm = zmol+znl*deep_arg->t; + zf = zm+2*zel*sin(zm); + sinzf = sin(zf); + f2 = 0.5*sinzf*sinzf-0.25; + f3 = -0.5*sinzf*cos(zf); + sel = ee2*f2+e3*f3; + sil = xi2*f2+xi3*f3; + sll = xl2*f2+xl3*f3+xl4*sinzf; + sghl = xgh2*f2+xgh3*f3+xgh4*sinzf; + sh1 = xh2*f2+xh3*f3; + pe = ses+sel; + pinc = sis+sil; + pl = sls+sll; + } + + pgh = sghs+sghl; + ph = shs+sh1; + deep_arg->xinc = deep_arg->xinc+pinc; + deep_arg->em = deep_arg->em+pe; + + if (xqncl >= 0.2) + { + /* Apply periodics directly */ + ph = ph/deep_arg->sinio; + pgh = pgh-deep_arg->cosio*ph; + deep_arg->omgadf = deep_arg->omgadf+pgh; + deep_arg->xnode = deep_arg->xnode+ph; + deep_arg->xll = deep_arg->xll+pl; + } + else + { + /* Apply periodics with Lyddane modification */ + sinok = sin(deep_arg->xnode); + cosok = cos(deep_arg->xnode); + alfdp = sinis*sinok; + betdp = sinis*cosok; + dalf = ph*cosok+pinc*cosis*sinok; + dbet = -ph*sinok+pinc*cosis*cosok; + alfdp = alfdp+dalf; + betdp = betdp+dbet; + deep_arg->xnode = FMod2p(deep_arg->xnode); + xls = deep_arg->xll+deep_arg->omgadf+cosis*deep_arg->xnode; + dls = pl+pgh-pinc*deep_arg->xnode*sinis; + xls = xls+dls; + xnoh = deep_arg->xnode; + deep_arg->xnode = AcTan(alfdp,betdp); + + /* This is a patch to Lyddane modification */ + /* suggested by Rob Matson. */ + if(fabs(xnoh-deep_arg->xnode) > pi) + { + if(deep_arg->xnode < xnoh) + deep_arg->xnode +=twopi; + else + deep_arg->xnode -=twopi; + } + + deep_arg->xll = deep_arg->xll+pl; + deep_arg->omgadf = xls-deep_arg->xll-cos(deep_arg->xinc)* + deep_arg->xnode; + } /* End case dpper: */ + return; + + } /* End switch(ientry) */ + +} /* End of Deep() */ + +/*------------------------------------------------------------------*/ + +/* Functions for testing and setting/clearing flags */ + +/* An int variable holding the single-bit flags */ +static int Flags = 0; + +int +isFlagSet(int flag) +{ + return (Flags & flag); +} + +int +isFlagClear(int flag) +{ + return (~Flags & flag); +} + +void +SetFlag(int flag) +{ + Flags |= flag; +} + +void +ClearFlag(int flag) +{ + Flags &= ~flag; +} + +/*------------------------------------------------------------------*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sgp4sdp4/sgp4sdp4.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,237 @@ +/* + * kelso.h April 9 2001 + * + * Header file for kelso + */ + +#ifndef KELSO_H +#define KELSO_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include <math.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <time.h> +/* #include <unistd.h> */ + +/* from David Kaelbling <drk@sgi.com> */ +#define select duplicate_select +//#include <unistd.h> +#undef select + + + +/** Type definitions **/ + +/* Two-line-element satellite orbital data */ +typedef struct +{ + double + epoch, xndt2o, xndd6o, bstar, + xincl, xnodeo, eo, omegao, xmo, xno; + int + catnr, /* Catalogue Number */ + elset, /* Element Set */ + revnum; /* Revolution Number */ + char + sat_name[25], /* Satellite name string */ + idesg[9]; /* International Designator */ + /* values needed for squint calculations */ + double xincl1, xnodeo1, omegao1; +} tle_t; + + +/* Geodetic position structure */ +typedef struct +{ + double + lat, lon, alt, theta; +} geodetic_t; + +/* General three-dimensional vector structure */ +typedef struct +{ + double + x, y, z, w; +} vector_t; + +/* Common arguments between deep-space functions */ +typedef struct +{ + /* Used by dpinit part of Deep() */ + double + eosq,sinio,cosio,betao,aodp,theta2,sing,cosg, + betao2,xmdot,omgdot,xnodot,xnodp; + /* Used by dpsec and dpper parts of Deep() */ + double + xll,omgadf,xnode,em,xinc,xn,t; + /* Used by thetg and Deep() */ + double + ds50; +} deep_arg_t; + +/** Table of constant values **/ +#define de2ra 1.74532925E-2 /* Degrees to Radians */ +#define pi 3.1415926535898 /* Pi */ +#define pio2 1.5707963267949 /* Pi/2 */ +#define x3pio2 4.71238898 /* 3*Pi/2 */ +#define twopi 6.2831853071796 /* 2*Pi */ +#define e6a 1.0E-6 +#define tothrd 6.6666667E-1 /* 2/3 */ +#define xj2 1.0826158E-3 /* J2 Harmonic */ +#define xj3 -2.53881E-6 /* J3 Harmonic */ +#define xj4 -1.65597E-6 /* J4 Harmonic */ +#define xke 7.43669161E-2 +#define xkmper 6.378135E3 /* Earth radius km */ +#define xmnpda 1.44E3 /* Minutes per day */ +#define ae 1.0 +#define ck2 5.413079E-4 +#define ck4 6.209887E-7 +#define __f 3.352779E-3 +#define ge 3.986008E5 +#define __s__ 1.012229 +#define qoms2t 1.880279E-09 +#define secday 8.6400E4 /* Seconds per day */ +#define omega_E 1.0027379 +#define omega_ER 6.3003879 +#define zns 1.19459E-5 +#define c1ss 2.9864797E-6 +#define zes 1.675E-2 +#define znl 1.5835218E-4 +#define c1l 4.7968065E-7 +#define zel 5.490E-2 +#define zcosis 9.1744867E-1 +#define zsinis 3.9785416E-1 +#define zsings -9.8088458E-1 +#define zcosgs 1.945905E-1 +#define zcoshs 1 +#define zsinhs 0 +#define q22 1.7891679E-6 +#define q31 2.1460748E-6 +#define q33 2.2123015E-7 +#define g22 5.7686396 +#define g32 9.5240898E-1 +#define g44 1.8014998 +#define g52 1.0508330 +#define g54 4.4108898 +#define root22 1.7891679E-6 +#define root32 3.7393792E-7 +#define root44 7.3636953E-9 +#define root52 1.1428639E-7 +#define root54 2.1765803E-9 +#define thdt 4.3752691E-3 +#define rho 1.5696615E-1 +#define mfactor 7.292115E-5 +#define __sr__ 6.96000E5 /*Solar radius - kilometers (IAU 76)*/ +#define SGPAU 1.49597870E8 /*Astronomical unit - kilometers (IAU 76)*/ + +/* Entry points of Deep() */ +#define dpinit 1 /* Deep-space initialization code */ +#define dpsec 2 /* Deep-space secular code */ +#define dpper 3 /* Deep-space periodic code */ + +/* Carriage return and line feed */ +#define CR 0x0A +#define LF 0x0D + +/* Flow control flag definitions */ +#define ALL_FLAGS -1 +#define SGP_INITIALIZED_FLAG 0x000001 +#define SGP4_INITIALIZED_FLAG 0x000002 +#define SDP4_INITIALIZED_FLAG 0x000004 +#define SGP8_INITIALIZED_FLAG 0x000008 +#define SDP8_INITIALIZED_FLAG 0x000010 +#define SIMPLE_FLAG 0x000020 +#define DEEP_SPACE_EPHEM_FLAG 0x000040 +#define LUNAR_TERMS_DONE_FLAG 0x000080 +#define NEW_EPHEMERIS_FLAG 0x000100 +#define DO_LOOP_FLAG 0x000200 +#define RESONANCE_FLAG 0x000400 +#define SYNCHRONOUS_FLAG 0x000800 +#define EPOCH_RESTART_FLAG 0x001000 +#define VISIBLE_FLAG 0x002000 +#define SAT_ECLIPSED_FLAG 0x004000 + + +/** Funtion prototypes **/ + +/* main.c */ +/* int main(void); */ +/* sgp4sdp4.c */ +void SGP4(double tsince, tle_t *tle, vector_t *pos, vector_t *vel, double* phase); +void SDP4(double tsince, tle_t *tle, vector_t *pos, vector_t *vel, double* phase); +void Deep(int ientry, tle_t *tle, deep_arg_t *deep_arg); +int isFlagSet(int flag); +int isFlagClear(int flag); +void SetFlag(int flag); +void ClearFlag(int flag); +/* sgp_in.c */ +int Checksum_Good(char *tle_set); +int Good_Elements(char *tle_set); +void Convert_Satellite_Data(char *tle_set, tle_t *tle); +int Get_Next_Tle_Set( char lines[3][80], tle_t *tle ); +void select_ephemeris(tle_t *tle); +/* sgp_math.c */ +int Sign(double arg); +double Sqr(double arg); +double Cube(double arg); +double Radians(double arg); +double Degrees(double arg); +double ArcSin(double arg); +double ArcCos(double arg); +void SgpMagnitude(vector_t *v); +void Vec_Add(vector_t *v1, vector_t *v2, vector_t *v3); +void Vec_Sub(vector_t *v1, vector_t *v2, vector_t *v3); +void Scalar_Multiply(double k, vector_t *v1, vector_t *v2); +void Scale_Vector(double k, vector_t *v); +double Dot(vector_t *v1, vector_t *v2); +double Angle(vector_t *v1, vector_t *v2); +void Cross(vector_t *v1, vector_t *v2, vector_t *v3); +void Normalize(vector_t *v); +double AcTan(double sinx, double cosx); +double FMod2p(double x); +double Modulus(double arg1, double arg2); +double Frac(double arg); +int Round(double arg); +double Int(double arg); +void Convert_Sat_State(vector_t *pos, vector_t *vel); +/* sgp_obs.c */ +void Calculate_User_PosVel(double _time, geodetic_t *geodetic, + vector_t *obs_pos, vector_t *obs_vel); +void Calculate_LatLonAlt(double _time, vector_t *pos, geodetic_t *geodetic); +void Calculate_Obs(double _time, vector_t *pos, vector_t *vel, + geodetic_t *geodetic, vector_t *obs_set); +void Calculate_RADec(double _time, vector_t *pos, vector_t *vel, + geodetic_t *geodetic, vector_t *obs_set); +/* sgp_time.c */ +double Julian_Date_of_Epoch(double epoch); +double Epoch_Time(double jd); +int DOY(int yr, int mo, int dy); +double Fraction_of_Day(int hr, int mi, int se); +void Calendar_Date(double jd, struct tm *cdate); +void Time_of_Day(double jd, struct tm *cdate); +double Julian_Date(struct tm *cdate); +void Date_Time(double jd, struct tm *cdate); +int Check_Date(struct tm *cdate); +struct tm Time_to_UTC(struct tm *cdate); +struct tm Time_from_UTC(struct tm *cdate); +double JD_to_UTC(double jt); +double JD_from_UTC(double jt); +double Delta_ET(double year); +double Julian_Date_of_Year(double year); +double ThetaG(double epoch, deep_arg_t *deep_arg); +double ThetaG_JD(double jd); +void UTC_Calendar_Now(struct tm *cdate); +/* solar.c */ +void Calculate_Solar_Position(double _time, vector_t *solar_vector); +int Sat_Eclipsed(vector_t *pos, vector_t *sol, double *depth); + +#ifdef __cplusplus +} +#endif + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sgp4sdp4/sgp_in.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,251 @@ +/* Unit SGP_In */ +/* Author: Dr TS Kelso */ +/* Original Version: 1992 Jun 25 */ +/* Current Revision: 1999 Nov 27 */ +/* Version: 2.10 */ +/* Copyright: 1992-1999, All Rights Reserved */ + +/* Ported to C by N. Kyriazis April 6 2001 */ + +#include "sgp4sdp4.h" + +/* Calculates the checksum mod 10 of a line from a TLE set and */ +/* returns 1 if it compares with checksum in column 68, else 0.*/ +/* tle_set is a character string holding the two lines read */ +/* from a text file containing NASA format Keplerian elements. */ +int +Checksum_Good( char *tle_set ) +{ + int i, check_digit, value, checksum = 0; + + for(i = 0; i < 68; i++) + { + if( (tle_set[i] >= '0') && (tle_set[i] <= '9') ) + value = tle_set[i] - '0'; + else if( tle_set[i] == '-' ) + value = 1; + else + value = 0; + + checksum += value; + } /* End for(i = 0; i < 68; i++) */ + + checksum %= 10; + check_digit = tle_set[68] - '0'; + + return( checksum == check_digit ); +} /* Function Checksums_Good */ + +/*------------------------------------------------------------------*/ + +/* Carries out various checks on a TLE set to verify its validity */ +/* tle_set is a character string holding the two lines read */ +/* from a text file containing NASA format Keplerian elements. */ +int +Good_Elements( char *tle_set ) +{ + /* Verify checksum of both lines of a TLE set */ + if( !Checksum_Good(&tle_set[0]) || !Checksum_Good(&tle_set[69]) ) + return (0); + /* Check the line number of each line */ + if( (tle_set[0] != '1') || (tle_set[69] != '2') ) + return (0); + /* Verify that Satellite Number is same in both lines */ + if( strncmp( &tle_set[2], &tle_set[71], 5 ) != 0 ) + return (0); + /* Check that various elements are in the right place */ + if( + (tle_set[ 23] != '.') || + (tle_set[ 34] != '.') || + (tle_set[ 80] != '.') || + (tle_set[ 89] != '.') || + (tle_set[106] != '.') || + (tle_set[115] != '.') || + (tle_set[123] != '.') || + (strncmp(&tle_set[61], " 0 ", 3) != 0) + ) + return (0); + + return(1); +} /* Function Good_Elements */ + +/*------------------------------------------------------------------*/ + +/* Converts the strings in a raw two-line element set */ +/* to their intended numerical values. No processing */ +/* of these values is done, e.g. from deg to rads etc. */ +/* This is done in the select_ephemeris() function. */ +void +Convert_Satellite_Data( char *tle_set, tle_t *tle ) +{ + char buff[15]; + + /** Decode Card 1 **/ + /* Satellite's catalogue number */ + strncpy( buff, &tle_set[2],5 ); + buff[5] = '\0'; + tle->catnr = atoi(buff); + + /* International Designator for satellite */ + strncpy( tle->idesg, &tle_set[9],8 ); + tle->idesg[8] = '\0'; + + /* Satellite's epoch */ + strncpy( buff, &tle_set[18],14 ); + buff[14] = '\0'; + tle->epoch = atof(buff); + + /* Satellite's First Time Derivative */ + strncpy( buff, &tle_set[33],10 ); + buff[10]='\0'; + tle->xndt2o = atof(buff); + + /* Satellite's Second Time Derivative */ + strncpy( buff, &tle_set[44],1 ); + buff[1] = '.'; + strncpy( &buff[2], &tle_set[45],5 ); + buff[7] = 'E'; + strncpy( &buff[8], &tle_set[50],2 ); + buff[10]='\0'; + tle->xndd6o = atof(buff); + + /* Satellite's bstar drag term */ + strncpy( buff, &tle_set[53],1 ); + buff[1] = '.'; + strncpy( &buff[2], &tle_set[54],5 ); + buff[7] = 'E'; + strncpy( &buff[8], &tle_set[59],2 ); + buff[10]='\0'; + tle->bstar = atof(buff); + + /* Element Number */ + strncpy( buff, &tle_set[64],4 ); + buff[4]='\0'; + tle->elset = atoi(buff); + + /** Decode Card 2 **/ + /* Satellite's Orbital Inclination (degrees) */ + strncpy( buff, &tle_set[77], 8 ); + buff[8]='\0'; + tle->xincl = atof(buff); + + /* Satellite's RAAN (degrees) */ + strncpy( buff, &tle_set[86], 8 ); + buff[8]='\0'; + tle->xnodeo = atof(buff); + + /* Satellite's Orbital Eccentricity */ + buff[0] = '.'; + strncpy( &buff[1], &tle_set[95], 7 ); + buff[8]='\0'; + tle->eo = atof(buff); + + /* Satellite's Argument of Perigee (degrees) */ + strncpy( buff, &tle_set[103], 8 ); + buff[8]='\0'; + tle->omegao = atof(buff); + + /* Satellite's Mean Anomaly of Orbit (degrees) */ + strncpy( buff, &tle_set[112], 8 ); + buff[8]='\0'; + tle->xmo = atof(buff); + + /* Satellite's Mean Motion (rev/day) */ + strncpy( buff, &tle_set[121], 10 ); + buff[10]='\0'; + tle->xno = atof(buff); + + /* Satellite's Revolution number at epoch */ + strncpy( buff, &tle_set[132], 5 ); + buff[5]='\0'; + tle->revnum = atof(buff); + +} /* Procedure Convert_Satellite_Data */ + +/*------------------------------------------------------------------*/ + +int +Get_Next_Tle_Set( char line[3][80], tle_t *tle) +{ + int idx, /* Index for loops and arrays */ + chr; /* Used for inputting characters */ + + char tle_set[139]; /* Two lines of a TLE set */ + + /* Read the satellite's name */ + for (idx = 0 ; idx < 25; idx++) + { + if( ((chr = line[0][idx]) != CR) && (chr != LF) && (chr != '\0')) + tle->sat_name[idx] = chr; + else + { + /* strip off trailing spaces */ + while ((chr = line[0][--idx]) == ' '); + tle->sat_name[++idx] = '\0'; + break; + } + } + + /* Read in first line of TLE set */ + strncpy(tle_set, line[1], 70); + + /* Read in second line of TLE set and terminate string */ + strncpy(&tle_set[69], line[2], 70); + tle_set[138]='\0'; + + /* Check TLE set and abort if not valid */ + if( !Good_Elements(tle_set) ) + return(-2); + + /* Convert the TLE set to orbital elements */ + Convert_Satellite_Data( tle_set, tle ); + + return(1); +} + +/*------------------------------------------------------------------*/ + +/* Selects the apropriate ephemeris type to be used */ +/* for predictions according to the data in the TLE */ +/* It also processes values in the tle set so that */ +/* they are apropriate for the sgp4/sdp4 routines */ +void +select_ephemeris(tle_t *tle) +{ + double ao,xnodp,dd1,dd2,delo,temp,a1,del1,r1; + + /* Preprocess tle set */ + tle->xnodeo *= de2ra; + tle-> omegao *= de2ra; + tle->xmo *= de2ra; + tle->xincl *= de2ra; + temp = twopi/xmnpda/xmnpda; + tle->xno = tle->xno*temp*xmnpda; + tle->xndt2o *= temp; + tle->xndd6o = tle->xndd6o*temp/xmnpda; + tle->bstar /= ae; + + /* Period > 225 minutes is deep space */ + dd1 = (xke/tle->xno); + dd2 = tothrd; + a1 = pow(dd1, dd2); + r1 = cos(tle->xincl); + dd1 = (1.0-tle->eo*tle->eo); + temp = ck2*1.5f*(r1*r1*3.0-1.0)/pow(dd1, 1.5); + del1 = temp/(a1*a1); + ao = a1*(1.0-del1*(tothrd*.5+del1* + (del1*1.654320987654321+1.0))); + delo = temp/(ao*ao); + xnodp = tle->xno/(delo+1.0); + + /* Select a deep-space/near-earth ephemeris */ + if (twopi/xnodp/xmnpda >= .15625) + SetFlag(DEEP_SPACE_EPHEM_FLAG); + else + ClearFlag(DEEP_SPACE_EPHEM_FLAG); + + return; +} /* End of select_ephemeris() */ + +/*------------------------------------------------------------------*/ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sgp4sdp4/sgp_math.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,286 @@ +/* + * Unit SGP_Math + * Author: Dr TS Kelso + * Original Version: 1991 Oct 30 + * Current Revision: 1998 Mar 17 + * Version: 3.00 + * Copyright: 1991-1998, All Rights Reserved + * + * ported to C by: Neoklis Kyriazis April 9 2001 + */ + +#include "sgp4sdp4.h" + +/* Returns sign of a double */ +int +Sign(double arg) +{ + if( arg > 0 ) + return( 1 ); + else if( arg < 0 ) + return( -1 ); + else + return( 0 ); +} /* Function Sign*/ + +/*------------------------------------------------------------------*/ + +/* Returns square of a double */ +double +Sqr(double arg) +{ + return( arg*arg ); +} /* Function Sqr */ + +/*------------------------------------------------------------------*/ + +/* Returns cube of a double */ +double +Cube(double arg) +{ + return( arg*arg*arg ); +} /*Function Cube*/ + +/*------------------------------------------------------------------*/ + +/* Returns angle in radians from arg id degrees */ +double +Radians(double arg) +{ + return( arg*de2ra ); +} /*Function Radians*/ + +/*------------------------------------------------------------------*/ + +/* Returns angle in degrees from arg in rads */ +double +Degrees(double arg) +{ + return( arg/de2ra ); +} /*Function Degrees*/ + +/*------------------------------------------------------------------*/ + +/* Returns the arcsine of the argument */ +double +ArcSin(double arg) +{ + if( fabs(arg) >= 1 ) + return( Sign(arg)*pio2 ); + else + return( atan(arg/sqrt(1-arg*arg)) ); +} /*Function ArcSin*/ + +/*------------------------------------------------------------------*/ + +/* Returns orccosine of rgument */ +double +ArcCos(double arg) +{ + return( pio2 - ArcSin(arg) ); +} /*Function ArcCos*/ + +/*------------------------------------------------------------------*/ + +/* Calculates scalar magnitude of a vector_t argument */ +void +SgpMagnitude(vector_t *v) +{ + v->w = sqrt(Sqr(v->x) + Sqr(v->y) + Sqr(v->z)); +} /*Procedure SgpMagnitude*/ + +/*------------------------------------------------------------------*/ + +/* Adds vectors v1 and v2 together to produce v3 */ +void +Vec_Add(vector_t *v1, vector_t *v2, vector_t *v3) +{ + v3->x = v1->x + v2->x; + v3->y = v1->y + v2->y; + v3->z = v1->z + v2->z; + + SgpMagnitude(v3); +} /*Procedure Vec_Add*/ + +/*------------------------------------------------------------------*/ + +/* Subtracts vector v2 from v1 to produce v3 */ +void +Vec_Sub(vector_t *v1, vector_t *v2, vector_t *v3) +{ + v3->x = v1->x - v2->x; + v3->y = v1->y - v2->y; + v3->z = v1->z - v2->z; + + SgpMagnitude(v3); +} /*Procedure Vec_Sub*/ + +/*------------------------------------------------------------------*/ + +/* Multiplies the vector v1 by the scalar k to produce the vector v2 */ +void +Scalar_Multiply(double k, vector_t *v1, vector_t *v2) +{ + v2->x = k * v1->x; + v2->y = k * v1->y; + v2->z = k * v1->z; + v2->w = fabs(k) * v1->w; +} /*Procedure Scalar_Multiply*/ + +/*------------------------------------------------------------------*/ + +/* Multiplies the vector v1 by the scalar k */ +void +Scale_Vector(double k, vector_t *v) +{ + v->x *= k; + v->y *= k; + v->z *= k; + SgpMagnitude(v); +} /* Procedure Scale_Vector */ + +/*------------------------------------------------------------------*/ + +/* Returns the dot product of two vectors */ +double +Dot(vector_t *v1, vector_t *v2) +{ + return( v1->x*v2->x + v1->y*v2->y + v1->z*v2->z ); +} /*Function Dot*/ + +/*------------------------------------------------------------------*/ + +/* Calculates the angle between vectors v1 and v2 */ +double +Angle(vector_t *v1, vector_t *v2) +{ + SgpMagnitude(v1); + SgpMagnitude(v2); + return( ArcCos(Dot(v1,v2)/(v1->w*v2->w)) ); +} /*Function Angle*/ + +/*------------------------------------------------------------------*/ + +/* Produces cross product of v1 and v2, and returns in v3 */ +void +Cross(vector_t *v1, vector_t *v2 ,vector_t *v3) +{ + v3->x = v1->y*v2->z - v1->z*v2->y; + v3->y = v1->z*v2->x - v1->x*v2->z; + v3->z = v1->x*v2->y - v1->y*v2->x; + SgpMagnitude(v3); +} /*Procedure Cross*/ + +/*------------------------------------------------------------------*/ + +/* Normalizes a vector */ +void +Normalize( vector_t *v ) +{ + v->x /= v->w; + v->y /= v->w; + v->z /= v->w; +} /*Procedure Normalize*/ + +/*------------------------------------------------------------------*/ + +/* Four-quadrant arctan function */ +double +AcTan(double sinx, double cosx) +{ + if(cosx == 0) + { + if(sinx > 0) + return (pio2); + else + return (x3pio2); + } + else + { + if(cosx > 0) + { + if(sinx > 0) + return ( atan(sinx/cosx) ); + else + return ( twopi + atan(sinx/cosx) ); + } + else + return ( pi + atan(sinx/cosx) ); + } + +} /* Function AcTan */ + +/*------------------------------------------------------------------*/ + +/* Returns mod 2pi of argument */ +double +FMod2p(double x) +{ + int i; + double ret_val; + + ret_val = x; + i = ret_val/twopi; + ret_val -= i*twopi; + if (ret_val < 0) ret_val += twopi; + + return (ret_val); +} /* fmod2p */ + +/*------------------------------------------------------------------*/ + +/* Returns arg1 mod arg2 */ +double +Modulus(double arg1, double arg2) +{ + int i; + double ret_val; + + ret_val = arg1; + i = ret_val/arg2; + ret_val -= i*arg2; + if (ret_val < 0) ret_val += arg2; + + return (ret_val); +} /* modulus */ + +/*------------------------------------------------------------------*/ + +/* Returns fractional part of double argument */ +double +Frac( double arg ) +{ + return( arg - floor(arg) ); +} /* Frac */ + +/*------------------------------------------------------------------*/ + +/* Returns argument rounded up to nearest integer */ +int +Round( double arg ) +{ + return( (int) floor(arg + 0.5) ); +} /* Round */ + +/*------------------------------------------------------------------*/ + +/* Returns the floor integer of a double arguement, as double */ +double +Int( double arg ) +{ + return( floor(arg) ); +} /* Int */ + +/*------------------------------------------------------------------*/ + +/* Converts the satellite's position and velocity */ +/* vectors from normalised values to km and km/sec */ +void +Convert_Sat_State( vector_t *pos, vector_t *vel ) +{ + Scale_Vector( xkmper, pos ); + Scale_Vector( xkmper*xmnpda/secday, vel ); + +} /* Procedure Convert_Sat_State */ + +/*------------------------------------------------------------------*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sgp4sdp4/sgp_obs.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,214 @@ +/* + * Unit SGP_Obs + * Author: Dr TS Kelso + * Original Version: 1992 Jun 02 + * Current Revision: 1992 Sep 28 + * Version: 1.40 + * Copyright: 1992, All Rights Reserved + * + * Ported to C by: Neoklis Kyriazis April 9 2001 + */ + +#include "sgp4sdp4.h" + +/* Procedure Calculate_User_PosVel passes the user's geodetic position */ +/* and the time of interest and returns the ECI position and velocity */ +/* of the observer. The velocity calculation assumes the geodetic */ +/* position is stationary relative to the earth's surface. */ +void +Calculate_User_PosVel(double _time, + geodetic_t *geodetic, + vector_t *obs_pos, + vector_t *obs_vel) +{ +/* Reference: The 1992 Astronomical Almanac, page K11. */ + + double c,sq,achcp; + + geodetic->theta = FMod2p(ThetaG_JD(_time) + geodetic->lon);/*LMST*/ + c = 1/sqrt(1 + __f*(__f - 2)*Sqr(sin(geodetic->lat))); + sq = Sqr(1 - __f)*c; + achcp = (xkmper*c + geodetic->alt)*cos(geodetic->lat); + obs_pos->x = achcp*cos(geodetic->theta);/*kilometers*/ + obs_pos->y = achcp*sin(geodetic->theta); + obs_pos->z = (xkmper*sq + geodetic->alt)*sin(geodetic->lat); + obs_vel->x = -mfactor*obs_pos->y;/*kilometers/second*/ + obs_vel->y = mfactor*obs_pos->x; + obs_vel->z = 0; + SgpMagnitude(obs_pos); + SgpMagnitude(obs_vel); +} /*Procedure Calculate_User_PosVel*/ + +/*------------------------------------------------------------------*/ + +/* Procedure Calculate_LatLonAlt will calculate the geodetic */ +/* position of an object given its ECI position pos and time. */ +/* It is intended to be used to determine the ground track of */ +/* a satellite. The calculations assume the earth to be an */ +/* oblate spheroid as defined in WGS '72. */ +void +Calculate_LatLonAlt(double _time, vector_t *pos, geodetic_t *geodetic) +{ + /* Reference: The 1992 Astronomical Almanac, page K12. */ + + double r,e2,phi,c; + + geodetic->theta = AcTan(pos->y,pos->x);/*radians*/ + geodetic->lon = FMod2p(geodetic->theta - ThetaG_JD(_time));/*radians*/ + r = sqrt(Sqr(pos->x) + Sqr(pos->y)); + e2 = __f*(2 - __f); + geodetic->lat = AcTan(pos->z,r);/*radians*/ + + do + { + phi = geodetic->lat; + c = 1/sqrt(1 - e2*Sqr(sin(phi))); + geodetic->lat = AcTan(pos->z + xkmper*c*e2*sin(phi),r); + } + while(fabs(geodetic->lat - phi) >= 1E-10); + + geodetic->alt = r/cos(geodetic->lat) - xkmper*c;/*kilometers*/ + + if( geodetic->lat > pio2 ) geodetic->lat -= twopi; + +} /*Procedure Calculate_LatLonAlt*/ + +/*------------------------------------------------------------------*/ + +/* The procedures Calculate_Obs and Calculate_RADec calculate */ +/* the *topocentric* coordinates of the object with ECI position, */ +/* {pos}, and velocity, {vel}, from location {geodetic} at {time}. */ +/* The {obs_set} returned for Calculate_Obs consists of azimuth, */ +/* elevation, range, and range rate (in that order) with units of */ +/* radians, radians, kilometers, and kilometers/second, respectively. */ +/* The WGS '72 geoid is used and the effect of atmospheric refraction */ +/* (under standard temperature and pressure) is incorporated into the */ +/* elevation calculation; the effect of atmospheric refraction on */ +/* range and range rate has not yet been quantified. */ + +/* The {obs_set} for Calculate_RADec consists of right ascension and */ +/* declination (in that order) in radians. Again, calculations are */ +/* based on *topocentric* position using the WGS '72 geoid and */ +/* incorporating atmospheric refraction. */ + +void +Calculate_Obs(double _time, + vector_t *pos, + vector_t *vel, + geodetic_t *geodetic, + vector_t *obs_set) + { + double + sin_lat,cos_lat, + sin_theta,cos_theta, + el,azim, + top_s,top_e,top_z; + + vector_t + obs_pos,obs_vel,range,rgvel; + + Calculate_User_PosVel(_time, geodetic, &obs_pos, &obs_vel); + + range.x = pos->x - obs_pos.x; + range.y = pos->y - obs_pos.y; + range.z = pos->z - obs_pos.z; + + rgvel.x = vel->x - obs_vel.x; + rgvel.y = vel->y - obs_vel.y; + rgvel.z = vel->z - obs_vel.z; + + SgpMagnitude(&range); + + sin_lat = sin(geodetic->lat); + cos_lat = cos(geodetic->lat); + sin_theta = sin(geodetic->theta); + cos_theta = cos(geodetic->theta); + top_s = sin_lat*cos_theta*range.x + + sin_lat*sin_theta*range.y + - cos_lat*range.z; + top_e = -sin_theta*range.x + + cos_theta*range.y; + top_z = cos_lat*cos_theta*range.x + + cos_lat*sin_theta*range.y + + sin_lat*range.z; + azim = atan(-top_e/top_s); /*Azimuth*/ + if( top_s > 0 ) + azim = azim + pi; + if( azim < 0 ) + azim = azim + twopi; + el = ArcSin(top_z/range.w); + obs_set->x = azim; /* Azimuth (radians) */ + obs_set->y = el; /* Elevation (radians)*/ + obs_set->z = range.w; /* Range (kilometers) */ + + /*Range Rate (kilometers/second)*/ + obs_set->w = Dot(&range, &rgvel)/range.w; + +/* Corrections for atmospheric refraction */ +/* Reference: Astronomical Algorithms by Jean Meeus, pp. 101-104 */ +/* Correction is meaningless when apparent elevation is below horizon */ + obs_set->y = obs_set->y + Radians((1.02/tan(Radians(Degrees(el)+ + 10.3/(Degrees(el)+5.11))))/60); + if( obs_set->y >= 0 ) + SetFlag(VISIBLE_FLAG); + else + { + obs_set->y = el; /*Reset to true elevation*/ + ClearFlag(VISIBLE_FLAG); + } /*else*/ + } /*Procedure Calculate_Obs*/ + +/*------------------------------------------------------------------*/ + +void +Calculate_RADec( double _time, + vector_t *pos, + vector_t *vel, + geodetic_t *geodetic, + vector_t *obs_set) +{ +/* Reference: Methods of Orbit Determination by */ +/* Pedro Ramon Escobal, pp. 401-402 */ + +double + phi,theta,sin_theta,cos_theta,sin_phi,cos_phi, + az,el,Lxh,Lyh,Lzh,Sx,Ex,Zx,Sy,Ey,Zy,Sz,Ez,Zz, + Lx,Ly,Lz,cos_delta,sin_alpha,cos_alpha; + + Calculate_Obs(_time,pos,vel,geodetic,obs_set); + +/* if( isFlagSet(VISIBLE_FLAG) ) + {*/ + az = obs_set->x; + el = obs_set->y; + phi = geodetic->lat; + theta = FMod2p(ThetaG_JD(_time) + geodetic->lon); + sin_theta = sin(theta); + cos_theta = cos(theta); + sin_phi = sin(phi); + cos_phi = cos(phi); + Lxh = -cos(az)*cos(el); + Lyh = sin(az)*cos(el); + Lzh = sin(el); + Sx = sin_phi*cos_theta; + Ex = -sin_theta; + Zx = cos_theta*cos_phi; + Sy = sin_phi*sin_theta; + Ey = cos_theta; + Zy = sin_theta*cos_phi; + Sz = -cos_phi; + Ez = 0; + Zz = sin_phi; + Lx = Sx*Lxh + Ex*Lyh + Zx*Lzh; + Ly = Sy*Lxh + Ey*Lyh + Zy*Lzh; + Lz = Sz*Lxh + Ez*Lyh + Zz*Lzh; + obs_set->y = ArcSin(Lz); /*Declination (radians)*/ + cos_delta = sqrt(1 - Sqr(Lz)); + sin_alpha = Ly/cos_delta; + cos_alpha = Lx/cos_delta; + obs_set->x = AcTan(sin_alpha,cos_alpha); /*Right Ascension (radians)*/ + obs_set->x = FMod2p(obs_set->x); + /*}*/ /*if*/ + } /* Procedure Calculate_RADec */ + +/*------------------------------------------------------------------*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sgp4sdp4/sgp_time.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,428 @@ +/* + * Unit SGP_Time + * Author: Dr TS Kelso + * Original Version: 1992 Jun 02 + * Current Revision: 2000 Jan 22 + * Modified for Y2K: 1999 Mar 07 + * Version: 2.05 + * Copyright: 1992-1999, All Rights Reserved + * Version 1.50 added Y2K support. Due to limitations in the current + * format of the NORAD two-line element sets, however, only dates + * through 2056 December 31/2359 UTC are valid. + * Version 1.60 modifies Calendar_Date to ensure date matches time + * resolution and modifies Time_of_Day to make it more robust. + * Version 2.00 adds Julian_Date, Date_Time, and Check_Date to support + * checking for valid date/times, permitting the use of Time_to_UTC and + * Time_from_UTC for UTC/local time conversions. + * Version 2.05 modifies UTC_offset to allow non-integer offsets. + * + * Ported to C by: Neoklis Kyriazis April 9 2001 + */ + +#include "sgp4sdp4.h" + +/* The function Julian_Date_of_Epoch returns the Julian Date of */ +/* an epoch specified in the format used in the NORAD two-line */ +/* element sets. It has been modified to support dates beyond */ +/* the year 1999 assuming that two-digit years in the range 00-56 */ +/* correspond to 2000-2056. Until the two-line element set format */ +/* is changed, it is only valid for dates through 2056 December 31. */ + +double +Julian_Date_of_Epoch(double epoch) +{ + double year,day; + + /* Modification to support Y2K */ + /* Valid 1957 through 2056 */ + day = modf(epoch*1E-3, &year)*1E3; + if( year < 57 ) + year = year + 2000; + else + year = year + 1900; + /* End modification */ + + return( Julian_Date_of_Year(year) + day ); +} /*Function Julian_Date_of_Epoch*/ + +/*------------------------------------------------------------------*/ + +/* Converts a Julian epoch to NORAD TLE epoch format */ +double +Epoch_Time(double jd) +{ + double yr,_time,epoch_time; + struct tm edate; + + Calendar_Date(jd, &edate); + yr = edate.tm_year - 100*(edate.tm_year/100) ; + _time = Frac(jd + 0.5); + epoch_time = yr*1000 + + DOY(edate.tm_year, edate.tm_mon, edate.tm_mday) + + _time; + + return( epoch_time ); +} /*Function Epoch_Time*/ + +/*------------------------------------------------------------------*/ + +/* The function DOY calculates the day of the year for the specified */ +/* date. The calculation uses the rules for the Gregorian calendar */ +/* and is valid from the inception of that calendar system. */ +int +DOY(int yr, int mo, int dy) +{ + const int days[] = {31,28,31,30,31,30,31,31,30,31,30,31}; + int i,day; + + day = 0; + for( i = 0; i < mo-1; i++ ) + day += days[i]; + day = day + dy; + + /* Leap year correction */ + if( + (yr%4 == 0) && ((yr%100 != 0) || (yr%400 == 0)) && (mo>2) + ) + day++; + + return( day ); +} /*Function DOY*/ + +/*------------------------------------------------------------------*/ + +/* Fraction_of_Day calculates the fraction of */ +/* a day passed at the specified input time. */ +double +Fraction_of_Day(int hr,int mi,int se) +{ + return( (hr + (mi + se/60.0)/60.0)/24.0 ); +} /*Function Fraction_of_Day*/ + +/*------------------------------------------------------------------*/ + +/* The function Calendar_Date converts a Julian Date to a struct tm. */ +/* Only the members tm_year, tm_mon and tm_mday are calculated and set */ +void +Calendar_Date(double jd, struct tm *cdate) +{ + /* Astronomical Formulae for Calculators, Jean Meeus, pages 26-27 */ + int Z,month; + double A,B,C,D,E,F,alpha,day,year,factor; + + factor = 0.5/secday/1000; + F = Frac(jd + 0.5); + if (F + factor >= 1.0) + { + jd = jd + factor; + F = 0.0; + } /*if*/ + Z = Round(jd); + if( Z < 2299161 ) + A = Z; + else + { + alpha = Int((Z - 1867216.25)/36524.25); + A = Z + 1 + alpha - Int(alpha/4); + } /*else*/ + B = A + 1524; + C = Int((B - 122.1)/365.25); + D = Int(365.25 * C); + E = Int((B - D)/30.6001); + day = B - D - Int(30.6001 * E) + F; + + if( E < 13.5 ) + month = Round(E - 1); + else + month = Round(E - 13); + if( month > 2.5 ) + year = C - 4716; + else + year = C - 4715; + + cdate->tm_year = (int) year; + cdate->tm_mon = month; + cdate->tm_mday = (int) floor(day); + +} /*Function Calendar_Date*/ + +/*------------------------------------------------------------------*/ + +/* Time_of_Day takes a Julian Date and calculates the clock time */ +/* portion of that date. Only tm_hour, tm_min and tm_sec are set */ +void +Time_of_Day(double jd, struct tm *cdate) +{ + int hr,mn,sc; + double _time; + + _time = Frac(jd - 0.5)*secday; + _time = Round(_time); + hr = floor(_time/3600.0); + _time = _time - 3600.0*hr; + if( hr == 24 ) hr = 0; + mn = floor(_time/60.0); + sc = _time - 60.0*mn; + cdate->tm_hour = hr; + cdate->tm_min = mn; + cdate->tm_sec = sc; + +} /*Function Time_of_Day*/ + +/*------------------------------------------------------------------*/ + +/* The function Julian_Date converts a standard calendar */ +/* date and time to a Julian Date. The procedure Date_Time */ +/* performs the inverse of this function. */ +double +Julian_Date(struct tm *cdate) +{ + double julian_date; + + julian_date = Julian_Date_of_Year(cdate->tm_year) + + DOY(cdate->tm_year,cdate->tm_mon,cdate->tm_mday) + + Fraction_of_Day(cdate->tm_hour,cdate->tm_min,cdate->tm_sec); + + return( julian_date ); +} /*Function Julian_Date */ + +/*------------------------------------------------------------------*/ + + +/* Date_Time() + * + * The function Date_Time() converts a Julian Date to + * standard calendar date and time. The function + * Julian_Date() performs the inverse of this function. + */ + +void +Date_Time(double julian_date, struct tm *cdate) +{ + time_t jtime; + + jtime = (julian_date - 2440587.5)*86400.; + *cdate = *gmtime( &jtime ); + +} /* End of Date_Time() */ + + +/*------------------------------------------------------------------*/ + +/* The procedure Check_Date can be used as a check to see if a calendar */ +/* date and time are valid. It works by first converting the calendar */ +/* date and time to a Julian Date (which allows for irregularities, such */ +/* as a time greater than 24 hours) and then converting back and comparing.*/ +int +Check_Date(struct tm *cdate) +{ + double jt; + struct tm chkdate; + + jt = Julian_Date(cdate); + Date_Time(jt, &chkdate); + + if( (cdate->tm_year == chkdate.tm_year) && + (cdate->tm_mon == chkdate.tm_mon ) && + (cdate->tm_mday == chkdate.tm_mday) && + (cdate->tm_hour == chkdate.tm_hour) && + (cdate->tm_min == chkdate.tm_min ) && + (cdate->tm_sec == chkdate.tm_sec ) ) + return ( 1 ); + else + return( 0 ); + +} /*Procedure Check_Date*/ + +/*------------------------------------------------------------------*/ + +/* Procedures Time_to_UTC and Time_from_UTC are used to */ +/* convert 'struct tm' dates between UTC and local time. */ +/* The procedures JD_to_UTC and JD_from_UTC are used to */ +/* do the same thing working directly with Julian dates. */ + +struct tm +Time_to_UTC(struct tm *cdate) +{ + time_t tdate; + + tdate = mktime(cdate); + return( *gmtime(&tdate) ); +} /*Procedure Time_to_UTC*/ + +/*------------------------------------------------------------------*/ + +struct tm +Time_from_UTC(struct tm *cdate) +{ + time_t tdate; + + tdate = mktime(cdate); + return( *localtime(&tdate) ); +} /*Procedure Time_from_UTC*/ + +/*------------------------------------------------------------------*/ + +/* + BSD systems don't define the timezone variable, so the following two + routines won't work. They're not used anyway in the example main(), + so we might as well comment them out. +*/ + +#if 0 + +double +JD_to_UTC(double jt) +{ + extern long timezone; + struct tm cdate; + + time_t t = 0; + + cdate = *localtime( &t ); + jt = jt - timezone/secday; + if( cdate.tm_isdst ) + jt= jt - 1.0/24.0; + + return( jt ); +} /*Procedure JD_to_UTC*/ + +/*------------------------------------------------------------------*/ + +double +JD_from_UTC(double jt) +{ + extern long timezone; + struct tm cdate; + time_t t = 0; + + cdate = *localtime( &t ); + jt = jt + timezone/secday; + if( cdate.tm_isdst ) + jt= jt + 1.0/24.0; + + return( jt ); +} /*Procedure JD_from_UTC*/ + +#endif + +/*------------------------------------------------------------------*/ + +/* The function Delta_ET has been added to allow calculations on */ +/* the position of the sun. It provides the difference between UT */ +/* (approximately the same as UTC) and ET (now referred to as TDT).*/ +/* This function is based on a least squares fit of data from 1950 */ +/* to 1991 and will need to be updated periodically. */ + +double +Delta_ET(double year) +{ + /* Values determined using data from 1950-1991 in the 1990 + Astronomical Almanac. See DELTA_ET.WQ1 for details. */ + + double delta_et; + + delta_et = 26.465 + 0.747622*(year - 1950) + + 1.886913*sin(twopi*(year - 1975)/33); + + return( delta_et ); +} /*Function Delta_ET*/ + +/*------------------------------------------------------------------*/ + +/* The function Julian_Date_of_Year calculates the Julian Date */ +/* of Day 0.0 of {year}. This function is used to calculate the */ +/* Julian Date of any date by using Julian_Date_of_Year, DOY, */ +/* and Fraction_of_Day. */ + +double +Julian_Date_of_Year(double year) +{ + /* Astronomical Formulae for Calculators, Jean Meeus, */ + /* pages 23-25. Calculate Julian Date of 0.0 Jan year */ + + long A,B,i; + double jdoy; + + year = year-1; + i = year/100; + A = i; + i = A/4; + B = 2-A+i; + i = 365.25*year; + i += 30.6001*14; + jdoy = i+1720994.5+B; + + return (jdoy); +} /*Function Julian_Date_of_Year*/ + +/*------------------------------------------------------------------*/ + +/* The function ThetaG calculates the Greenwich Mean Sidereal Time */ +/* for an epoch specified in the format used in the NORAD two-line */ +/* element sets. It has now been adapted for dates beyond the year */ +/* 1999, as described above. The function ThetaG_JD provides the */ +/* same calculation except that it is based on an input in the */ +/* form of a Julian Date. */ + +double +ThetaG(double epoch, deep_arg_t *deep_arg) +{ +/* Reference: The 1992 Astronomical Almanac, page B6. */ + + double year,day,UT,jd,TU,GMST,_ThetaG; + +/* Modification to support Y2K */ +/* Valid 1957 through 2056 */ + day = modf(epoch*1E-3,&year)*1E3; + if(year < 57) + year += 2000; + else + year += 1900; + /* End modification */ + + UT = modf(day,&day); + jd = Julian_Date_of_Year(year)+day; + TU = (jd-2451545.0)/36525; + GMST = 24110.54841+TU*(8640184.812866+TU*(0.093104-TU* 6.2E-6)); + GMST = Modulus(GMST+secday*omega_E*UT,secday); + _ThetaG = twopi*GMST/secday; + deep_arg->ds50 = jd-2433281.5+UT; + _ThetaG = FMod2p(6.3003880987*deep_arg->ds50+1.72944494); + + return (_ThetaG); +} /* Function ThetaG */ + +/*------------------------------------------------------------------*/ + +double +ThetaG_JD(double jd) +{ +/* Reference: The 1992 Astronomical Almanac, page B6. */ + + double UT,TU,GMST; + + UT = Frac(jd + 0.5); + jd = jd - UT; + TU = (jd - 2451545.0)/36525; + GMST = 24110.54841 + TU * (8640184.812866 + TU * (0.093104 - TU * 6.2E-6)); + GMST = Modulus(GMST + secday*omega_E*UT,secday); + + return( twopi * GMST/secday ); +} /*Function ThetaG_JD*/ + +/*------------------------------------------------------------------*/ + +/* Gets calendar time from time() and produces a UTC calendar date */ +void +UTC_Calendar_Now( struct tm *cdate ) +{ + time_t t; + + t = time(0); + *cdate = *gmtime(&t); + cdate->tm_year += 1900; + cdate->tm_mon += 1; + +} /* End UTC_Calendar_Now */ +/*------------------------------------------------------------------*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sgp4sdp4/solar.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,69 @@ +/* + * Unit Solar + * Author: Dr TS Kelso + * Original Version: 1990 Jul 29 + * Current Revision: 1999 Nov 27 + * Version: 1.30 + * Copyright: 1990-1999, All Rights Reserved + * + * Ported to C by: Neoklis Kyriazis April 1 2001 + */ + +#include "sgp4sdp4.h" + +/* Calculates solar position vector */ +void +Calculate_Solar_Position(double _time, vector_t *solar_vector) +{ + double mjd,year,T,M,L,e,C,O,Lsa,nu,R,eps; + + mjd = _time - 2415020.0; + year = 1900 + mjd/365.25; + T = (mjd + Delta_ET(year)/secday)/36525.0; + M = Radians(Modulus(358.47583 + Modulus(35999.04975*T,360.0) + - (0.000150 + 0.0000033*T)*Sqr(T),360.0)); + L = Radians(Modulus(279.69668 + Modulus(36000.76892*T,360.0) + + 0.0003025*Sqr(T),360.0)); + e = 0.01675104 - (0.0000418 + 0.000000126*T)*T; + C = Radians((1.919460 - (0.004789 + 0.000014*T)*T)*sin(M) + + (0.020094 - 0.000100*T)*sin(2*M) + 0.000293*sin(3*M)); + O = Radians(Modulus(259.18 - 1934.142*T,360.0)); + Lsa = Modulus(L + C - Radians(0.00569 - 0.00479*sin(O)),twopi); + nu = Modulus(M + C,twopi); + R = 1.0000002*(1 - Sqr(e))/(1 + e*cos(nu)); + eps = Radians(23.452294 - (0.0130125 + (0.00000164 - + 0.000000503*T)*T)*T + 0.00256*cos(O)); + R = SGPAU*R; + solar_vector->x = R*cos(Lsa); + solar_vector->y = R*sin(Lsa)*cos(eps); + solar_vector->z = R*sin(Lsa)*sin(eps); + solar_vector->w = R; +} /*Procedure Calculate_Solar_Position*/ + +/*------------------------------------------------------------------*/ + +/* Calculates stellite's eclipse status and depth */ +int +Sat_Eclipsed(vector_t *pos, vector_t *sol, double *depth) +{ + double sd_sun, sd_earth, delta; + vector_t Rho, earth; + + /* Determine partial eclipse */ + sd_earth = ArcSin(xkmper/pos->w); + Vec_Sub(sol,pos,&Rho); + sd_sun = ArcSin(__sr__/Rho.w); + Scalar_Multiply(-1,pos,&earth); + delta = Angle(sol,&earth); + *depth = sd_earth - sd_sun - delta; + if( sd_earth < sd_sun ) + return( 0 ); + else + if( *depth >= 0 ) + return( 1 ); + else + return( 0 ); + +} /*Function Sat_Eclipsed*/ + +/*------------------------------------------------------------------*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sowb.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,34 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef SOWB_H +#define SOWB_H + +#include <LPC17xx.h> +#include <cmsis_nvic.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <time.h> + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/predict_th.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,117 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#include "string.h" +#include "sowb.h" +#include "osd.h" +#include "sgp4sdp4.h" +#include "predict_th.h" +#include "gps.h" +#include "gpio.h" +#include "satapi.h" +#include "debug.h" + +#ifdef PREDICT_TH_RUN + +tle_t ISS_TLE; + + + +int sgp4sdp4_th_init(void) { + char buf[128]; + GPS_TIME t; + double jd_epoch, jd_utc, tsince, phase; + vector_t vel = { 0, 0, 0 }; + vector_t pos = { 0, 0, 0 }; + vector_t obs_set; + geodetic_t obs_geodetic; + geodetic_t sat_geodetic; + tle_t tle, localtle; + char elements[3][80]; + + /* Prepare to begin ISS */ + strcpy(elements[0], "ISS (ZARYA)"); + strcpy(elements[1], "1 25544U 98067A 10278.19511664 .00012217 00000-0 97221-4 0 147"); + strcpy(elements[2], "2 25544 051.6473 027.7875 0007506 064.6316 006.5147 15.71651651680777"); + + debug_printf("SGP4SDP4 TH starting 1\r\n"); + + ClearFlag(ALL_FLAGS); + Get_Next_Tle_Set(elements, &tle); + memcpy(&localtle, &tle, sizeof(tle_t)); + select_ephemeris(&tle); + + gps_get_time(&t); + + if (!t.is_valid) { + debug_printf("SGP4SDP4 TH Abort, invalid time.\r\n"); + return 0; + } + + jd_utc = gps_julian_date(&t); + jd_epoch = Julian_Date_of_Epoch(tle.epoch); + tsince = (jd_utc - jd_epoch) * xmnpda; + + if (isFlagSet(DEEP_SPACE_EPHEM_FLAG)) { + //debug_printf("Using SDP4\r\n"); + SDP4(tsince, &tle, &pos, &vel, &phase); + } + else { + //debug_printf("Using SGP4\r\n"); + SGP4(tsince, &tle, &pos, &vel, &phase); + } + + Convert_Sat_State(&pos, &vel); + //SgpMagnitude(&vel); // scalar magnitude, not brightness... + //double velocity = vel.w; + + GPS_LOCATION_AVERAGE loc; + gps_get_location_average(&loc); + if (loc.east_west == 'W') loc.longitude *= -1.; + if (loc.north_south == 'S') loc.latitude *= -1.; + + obs_geodetic.lat = loc.latitude * de2ra; // * 56.1920; + obs_geodetic.lon = loc.longitude * de2ra; // * -3.0339; + obs_geodetic.alt = loc.height / 1000.; + + Calculate_Obs(jd_utc, &pos, &vel, &obs_geodetic, &obs_set); + Calculate_LatLonAlt(jd_utc, &pos, &sat_geodetic); + + double azimuth = Degrees(obs_set.x); + double elevation = Degrees(obs_set.y); + double range = obs_set.z; + //double rangeRate = obs_set.w; + //double height = sat_geodetic.alt; + + //sprintf(buf, "JD UTC : %.5f JD SAT : %.5f DIF : %f\r\n", jd_utc, jd_epoch, jd_utc - jd_epoch); + //debug_printf("%s", buf); + + sprintf(buf, "ISS El:%.1f AZ:%.1f %dKm\r\n\n", elevation, azimuth, (int)range); + osd_string_xy(0, 14, buf); + debug_printf("%s", buf); + return 1; + + +} + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/predict_th.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,34 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef PREDICT_TH_H +#define PREDICT_TH_H + +#define PREDICT_TH_RUN + +#ifdef PREDICT_TH_RUN + +int sgp4sdp4_th_init(void); + +#endif + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/th_xbox360gamepad.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,123 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef TH_XBOX360GAMEPAD_C +#define TH_XBOX360GAMEPAD_C +#endif + +#include "mbed.h" +#include "usbeh.h" +#include "usbeh_endpoint.h" +#include "usbeh_device.h" +#include "usbeh_controller.h" +#include "usbeh_api.h" +#include "xbox360gamepad.h" +#include "th_xbox360gamepad.h" + +#include "main.h" +#include "debug.h" + + +const char *button_text[] = { "","LS","RS","XBOX","Unused","A","B","X","Y","DPAD UP","DPAD DOWN","DPAD LEFT","DPAG RIGHT","START","BACK","LEFT HAT","RIGHT HAT" }; + +/* Define globals to hold Xbox360 stick data. */ +XBOX360_STICK *stick; +XBOX360_STICK stick_left_previous; +XBOX360_STICK stick_right_previous; +unsigned char trigger_left = 0, trigger_left_last = 0; +unsigned char trigger_right = 0, trigger_right_last = 0; + +void th_xbox360gamepad_init(void) { + stick = xbox360gamepad_get_stick_left(); + stick_left_previous.x = stick->x; + stick_left_previous.y = stick->y; + stick = xbox360gamepad_get_stick_right(); + stick_right_previous.x = stick->x; + stick_right_previous.y = stick->y; +} + +void th_xbox360gamepad(void) { + unsigned char button; + if ((button = xbox360gamepad_get_button()) != 0) { + if (button > 0) { + debug_printf("Button "); + if (button > (BUTT_RIGHT_HAT_PRESS + 16)) { + debug_printf("%s held\r\n", button_text[button - 32]); + } + else if (button > BUTT_RIGHT_HAT_PRESS) { + debug_printf("%s released\r\n", button_text[button - 16]); + } + else { + debug_printf("%s pressed\r\n", button_text[button]); + switch (button) { + case BUTT_A_PRESS: + xbox360gamepad_led(LED_1_FLASH_THEN_ON); + break; + case BUTT_B_PRESS: + xbox360gamepad_led(LED_2_FLASH_THEN_ON); + break; + case BUTT_X_PRESS: + xbox360gamepad_led(LED_3_FLASH_THEN_ON); + break; + case BUTT_Y_PRESS: + xbox360gamepad_led(LED_4_FLASH_THEN_ON); + break; + } + } + } + } + + if ((trigger_left = xbox360gamepad_get_trigger_left()) != trigger_left_last) { + debug_printf("Left trigger: %d\r\n", trigger_left); + trigger_left_last = trigger_left; + } + + if ((trigger_right = xbox360gamepad_get_trigger_right()) != trigger_right_last) { + debug_printf("Right trigger: %d\r\n", trigger_right); + trigger_right_last = trigger_right; + } + + unsigned char xbox360gamepad_get_trigger_right(void); + + stick = xbox360gamepad_get_stick_left(); + if (stick->x/STICK_DIVISOR != stick_left_previous.x/STICK_DIVISOR || stick->y/STICK_DIVISOR != stick_left_previous.y/STICK_DIVISOR) { + stick_left_previous.x = stick->x; + stick_left_previous.y = stick->y; + // Don't bother printing for now, the sticks are too sensitive! + int x = stick->x/STICK_DIVISOR, y = stick->y/STICK_DIVISOR; + if (1 || (x > 10 || x < -10) || (y > 10 || y < -10) ) { + debug_printf("New LEFT stick position x = %d y = %d\r\n", stick->x/STICK_DIVISOR, stick->y/STICK_DIVISOR); + } + } + + stick = xbox360gamepad_get_stick_right(); + if (stick->x/STICK_DIVISOR != stick_right_previous.x/STICK_DIVISOR || stick->y/STICK_DIVISOR != stick_right_previous.y/STICK_DIVISOR) { + stick_right_previous.x = stick->x; + stick_right_previous.y = stick->y; + // Don't bother printing for now, the sticks are too sensitive! + int x = stick->x/STICK_DIVISOR, y = stick->y/STICK_DIVISOR; + if (1 || (x > 10 || x < -10) || (y > 10 || y < -10) ) { + debug_printf("New RIGHT stick position x = %d y = %d\r\n", stick->x/STICK_DIVISOR, stick->y/STICK_DIVISOR); + } + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/th_xbox360gamepad.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,52 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef TH_XBOX360GAMEPAD_H +#define TH_XBOX360GAMEPAD_H + +#ifndef BUTT_LS_PRESS +#define BUTT_LS_PRESS 1 +#define BUTT_RS_PRESS 2 +#define BUTT_XBOX_PRESS 3 +#define BUTT_UNUSED_PRESS 4 +#define BUTT_A_PRESS 5 +#define BUTT_B_PRESS 6 +#define BUTT_X_PRESS 7 +#define BUTT_Y_PRESS 8 +#define BUTT_DPAD_UP_PRESS 9 +#define BUTT_DPAD_DOWN_PRESS 10 +#define BUTT_DPAD_LEFT_PRESS 11 +#define BUTT_DPAD_RIGHT_PRESS 12 +#define BUTT_START_PRESS 13 +#define BUTT_BACK_PRESS 14 +#define BUTT_LEFT_HAT_PRESS 15 +#define BUTT_RIGHT_HAT_PRESS 16 +#endif + +#define STICK_DIVISOR 1024 + + +void th_xbox360gamepad_init(void); +void th_xbox360gamepad(void); + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbeh/readme.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,65 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + /************************************************************************** + + The USB Embedded Host software is originally derived from the work of + Peter Barrett [1] and his BlueUSB project [2]. + + Although heavily re-styled, modified and revised for the SOWB project, + the "core" of the embedded host is based on Peter's work. Peter's + original copyright is acknowledge and reproduced below. + + Thank you Peter for allowing others to stand on the shoulders of giants ;) + + [1] http://mbed.org/users/peterbarrett1967/ + [2] http://mbed.org/users/peterbarrett1967/programs/BlueUSB/5yn1q + + Side note, I found some bugs that I fixed. I sent these back to Peter + to update his project. As yet I've had no reply and last time I looked + the bugs were still there. Basically, if a USB device has multiple + interfaces, in Peter's design only the even numbered interfaces will + be enumerated and assigned endpoints. All odd numbered interfaces are + skipped over and ignored. + +****************************************************************************/ +/* +Copyright (c) 2010 Peter Barrett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbeh/usbeh.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,366 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef USBEH_H +#define USBEH_H + +#include "sowb.h" + +/* Definitions */ +#define USBEH_HcRevision LPC_USB->HcRevision +#define USBEH_HcControl LPC_USB->HcControl +#define USBEH_HcCommandStatus LPC_USB->HcCommandStatus +#define USBEH_HcInterruptStatus LPC_USB->HcInterruptStatus +#define USBEH_HcInterruptEnable LPC_USB->HcInterruptEnable +#define USBEH_HcInterruptDisable LPC_USB->HcInterruptDisable +#define USBEH_HcHCCA LPC_USB->HcHCCA +#define USBEH_entED LPC_USB->entED +#define USBEH_HcControlHeadED LPC_USB->HcControlHeadED +#define USBEH_HcControlCurrentED LPC_USB->HcControlCurrentED +#define USBEH_HcBulkHeadED LPC_USB->HcBulkHeadED +#define USBEH_HcBulkCurrentED LPC_USB->HcBulkCurrentED +#define USBEH_HcDoneHead LPC_USB->HcDoneHead +#define USBEH_HcFmInterval LPC_USB->HcFmInterval +#define USBEH_HcFmRemaining LPC_USB->HcFmRemaining +#define USBEH_HcFmNumber LPC_USB->HcFmNumber +#define USBEH_HcPeriodicStart LPC_USB->HcPeriodicStart +#define USBEH_HcLSTreshold LPC_USB->HcLSTreshold +#define USBEH_HcRhDescriptorA LPC_USB->HcRhDescriptorA +#define USBEH_HcRhDescriptorB LPC_USB->HcRhDescriptorB +#define USBEH_HcRhStatus LPC_USB->HcRhStatus +#define USBEH_HcRhPortStatus1 LPC_USB->HcRhPortStatus1 +#define USBEH_HcRhPortStatus2 LPC_USB->HcRhPortStatus2 +#define USBEH_Module_ID LPC_USB->Module_ID +#define USBEH_OTGIntSt LPC_USB->OTGIntSt +#define USBEH_OTGIntEn LPC_USB->OTGIntEn +#define USBEH_OTGIntSet LPC_USB->OTGIntSet +#define USBEH_OTGIntClr LPC_USB->OTGIntClr +#define USBEH_OTGStCtrl LPC_USB->OTGStCtrl +#define USBEH_OTGTmr LPC_USB->OTGTmr +#define USBEH_USBDevIntSt LPC_USB->USBDevIntSt +#define USBEH_USBDevIntEn LPC_USB->USBDevIntEn +#define USBEH_USBDevIntClr LPC_USB->USBDevIntClr +#define USBEH_USBDevIntSet LPC_USB->USBDevIntSet +#define USBEH_USBCmdCode LPC_USB->USBCmdCode +#define USBEH_USBCmdData LPC_USB->USBCmdData +#define USBEH_USBRxData LPC_USB->USBRxData +#define USBEH_USBTxData LPC_USB->USBTxData +#define USBEH_USBRxPLen LPC_USB->USBRxPLen +#define USBEH_USBTxPLen LPC_USB->USBTxPLen +#define USBEH_USBCtrl LPC_USB->USBCtrl +#define USBEH_USBDevIntPri LPC_USB->USBDevIntPri +#define USBEH_USBEpIntSt LPC_USB->USBEpIntSt +#define USBEH_USBEpIntEn LPC_USB->USBEpIntEn +#define USBEH_USBEpIntClr LPC_USB->USBEpIntClr +#define USBEH_USBEpIntSet LPC_USB->USBEpIntSet +#define USBEH_USBEpIntPri LPC_USB->USBEpIntPri +#define USBEH_USBReEp LPC_USB->USBReEp +#define USBEH_USBEpInd LPC_USB->USBEpInd +#define USBEH_USBMaxPSize LPC_USB->USBMaxPSize +#define USBEH_USBDMARSt LPC_USB->USBDMARSt +#define USBEH_USBDMARClr LPC_USB->USBDMARClr +#define USBEH_USBDMARSet LPC_USB->USBDMARSet +#define USBEH_USBUDCAH LPC_USB->USBUDCAH +#define USBEH_USBEpDMASt LPC_USB->USBEpDMASt +#define USBEH_USBEpDMAEn LPC_USB->USBEpDMAEn +#define USBEH_USBEpDMADis LPC_USB->USBEpDMADis +#define USBEH_USBDMAIntSt LPC_USB->USBDMAIntSt +#define USBEH_USBDMAIntEn LPC_USB->USBDMAIntEn +#define USBEH_USBEoTIntSt LPC_USB->USBEoTIntSt +#define USBEH_USBEoTIntClr LPC_USB->USBEoTIntClr +#define USBEH_USBEoTIntSet LPC_USB->USBEoTIntSet +#define USBEH_USBNDDRIntSt LPC_USB->USBNDDRIntSt +#define USBEH_USBNDDRIntClr LPC_USB->USBNDDRIntClr +#define USBEH_USBNDDRIntSet LPC_USB->USBNDDRIntSet +#define USBEH_USBSysErrIntSt LPC_USB->USBSysErrIntSt +#define USBEH_USBSysErrIntClr LPC_USB->USBSysErrIntClr +#define USBEH_USBSysErrIntSet LPC_USB->USBSysErrIntSet +#define USBEH_I2C_RX LPC_USB->I2C_RX +#define USBEH_I2C_WO LPC_USB->I2C_WO +#define USBEH_I2C_STS LPC_USB->I2C_STS +#define USBEH_I2C_CTL LPC_USB->I2C_CTL +#define USBEH_I2C_CLKHI LPC_USB->I2C_CLKHI +#define USBEH_I2C_CLKLO LPC_USB->I2C_CLKLO +#define USBEH_USBClkCtrl LPC_USB->USBClkCtrl +#define USBEH_OTGClkCtrl LPC_USB->OTGClkCtrl +#define USBEH_USBClkSt LPC_USB->USBClkSt +#define USBEH_OTGClkSt LPC_USB->OTGClkSt + +void user_wait_ms(uint32_t ms); +//#define USBEH_OS_DELAY_MS(x) wait_ms(x); +#define USBEH_OS_DELAY_MS(x) user_wait_ms(x); + +#define USBEH_U32 uint32_t +#define USBEH_U16 unsigned short int +#define USBEH_U08 unsigned char +#define USBEH_S32 int32_t +#define USBEH_S16 short int +#define USBEH_S08 char + +#define USBEH_MAX_ENDPOINTS_TOTAL 16 +#define USBEH_MAX_DEVICES 8 +#define USBEH_MAX_ENDPOINTS_PER_DEVICE 8 + +#define USBEH_ENDPOINT_CONTROL 0 +#define USBEH_ENDPOINT_ISOCRONOUS 1 +#define USBEH_ENDPOINT_BULK 2 +#define USBEH_ENDPOINT_INTERRUPT 3 + +#define USBEH_DESCRIPTOR_TYPE_DEVICE 1 +#define USBEH_DESCRIPTOR_TYPE_CONFIGURATION 2 +#define USBEH_DESCRIPTOR_TYPE_STRING 3 +#define USBEH_DESCRIPTOR_TYPE_INTERFACE 4 +#define USBEH_DESCRIPTOR_TYPE_ENDPOINT 5 + +#define USBEH_DESCRIPTOR_TYPE_HID 0x21 +#define USBEH_DESCRIPTOR_TYPE_REPORT 0x22 +#define USBEH_DESCRIPTOR_TYPE_PHYSICAL 0x23 +#define USBEH_DESCRIPTOR_TYPE_HUB 0x29 + +#define USBEH_HOST_CLK_EN (1 << 0) +#define USBEH_PORTSEL_CLK_EN (1 << 3) +#define USBEH_AHB_CLK_EN (1 << 4) +#define USBEH_CLOCK_MASK (USBEH_HOST_CLK_EN | USBEH_PORTSEL_CLK_EN | USBEH_AHB_CLK_EN) +#define USBEH_FRAMEINTERVAL (12000-1) // 1ms +#define USBEH_DEFAULT_FMINTERVAL ((((6 * (USBEH_FRAMEINTERVAL - 210)) / 7) << 16) | USBEH_FRAMEINTERVAL) +#define USBEH_HOST_CONTROLLER_RESET 0x01 +#define USBEH_HOST_CONTROLLER_FUNCTIONAL_STATE 0xC0 +#define USBEH_OPERATIONAL_MASK 0x80 +#define USBEH_SET_GLOBAL_POWER 0x00010000 + +#define USBEH_WRITEBACK_DONE_HEAD 0x00000002 +#define USBEH_START_OF_FRAME 0x00000004 +#define USBEH_RESUME_DETECTED 0x00000008 +#define USBEH_UNRECOVERABLE_ERROR 0x00000010 +#define USBEH_FRAME_NUMBER_OVERFLOW 0x00000020 +#define USBEH_ROOT_HUB_STATUS_CHANGE 0x00000040 +#define USBEH_OWNERSHIP_CHANGE 0x00000080 +#define USBEH_MASTER_IRQ_ENABLE 0x80000000 + +enum USB_CLASS_CODE { + CLASS_DEVICE, + CLASS_AUDIO, + CLASS_COMM_AND_CDC_CONTROL, + CLASS_HID, + CLASS_PHYSICAL = 0x05, + CLASS_STILL_IMAGING, + CLASS_PRINTER, + CLASS_MASS_STORAGE, + CLASS_HUB, + CLASS_CDC_DATA, + CLASS_SMART_CARD, + CLASS_CONTENT_SECURITY = 0x0D, + CLASS_VIDEO = 0x0E, + CLASS_DIAGNOSTIC_DEVICE = 0xDC, + CLASS_WIRELESS_CONTROLLER = 0xE0, + CLASS_MISCELLANEOUS = 0xEF, + CLASS_APP_SPECIFIC = 0xFE, + CLASS_VENDOR_SPECIFIC = 0xFF +}; + +#define USBEH_DEVICE_TO_HOST 0x80 +#define USBEH_HOST_TO_DEVICE 0x00 +#define USBEH_REQUEST_TYPE_CLASS 0x20 +#define USBEH_RECIPIENT_DEVICE 0x00 +#define USBEH_RECIPIENT_INTERFACE 0x01 +#define USBEH_RECIPIENT_ENDPOINT 0x02 +#define USBEH_RECIPIENT_OTHER 0x03 + +#define USBEH_SETUP_TYPE_MASK_STANDARD 0x00 +#define USBEH_SETUP_TYPE_MASK_CLASS 0x20 +#define USBEH_SETUP_TYPE_MASK_VENDOR 0x40 +#define USBEH_SETUP_TYPE_MASK_RESERVED 0x60 + +#define USBEH_GET_STATUS 0 +#define USBEH_CLEAR_FEATURE 1 +#define USBEH_SET_FEATURE 3 +#define USBEH_SET_ADDRESS 5 +#define USBEH_GET_DESCRIPTOR 6 +#define USBEH_SET_DESCRIPTOR 7 +#define USBEH_GET_CONFIGURATION 8 +#define USBEH_SET_CONFIGURATION 9 +#define USBEH_GET_INTERFACE 10 +#define USBEH_SET_INTERFACE 11 +#define USBEH_SYNCH_FRAME 11 + +// Status flags from hub +#define USBEH_PORT_CONNECTION 0 +#define USBEH_PORT_ENABLE 1 +#define USBEH_PORT_SUSPEND 2 +#define USBEH_PORT_OVER_CURRENT 3 +#define USBEH_PORT_RESET 4 +#define USBEH_PORT_POWER 8 +#define USBEH_PORT_LOW_SPEED 9 + +#define USBEH_C_PORT_CONNECTION 16 +#define USBEH_C_PORT_ENABLE 17 +#define USBEH_C_PORT_SUSPEND 18 +#define USBEH_C_PORT_OVER_CURRENT 19 +#define USBEH_C_PORT_RESET 20 + +#define USBEH_IO_PENDING -100 +#define USBEH_ERR_ENDPOINT_NONE_LEFT -101 +#define USBEH_ERR_ENDPOINT_NOT_FOUND -102 +#define USBEH_ERR_DEVICE_NOT_FOUND -103 +#define USBEH_ERR_DEVICE_NONE_LEFT -104 +#define USBEH_ERR_HUB_INIT_FAILED -105 +#define USBEH_ERR_INTERFACE_NOT_FOUND -106 + +#define USBEH_TOKEN_SETUP 0 +#define USBEH_TOKEN_IN 1 +#define USBEH_TOKEN_OUT 2 + +#define USBEH_TD_ROUNDING (USBEH_U32)0x00040000 +#define USBEH_TD_SETUP (USBEH_U32)0x00000000 +#define USBEH_TD_IN (USBEH_U32)0x00100000 +#define USBEH_TD_OUT (USBEH_U32)0x00080000 +#define USBEH_TD_DELAY_INT(x) (USBEH_U32)((x) << 21) +#define USBEH_TD_TOGGLE_0 (USBEH_U32)0x02000000 +#define USBEH_TD_TOGGLE_1 (USBEH_U32)0x03000000 +#define USBEH_TD_CC (USBEH_U32)0xF0000000 + +typedef struct { + USBEH_U08 bLength; + USBEH_U08 bDescriptorType; + USBEH_U16 bcdUSB; + USBEH_U08 bDeviceClass; + USBEH_U08 bDeviceSubClass; + USBEH_U08 bDeviceProtocol; + USBEH_U08 bMaxPacketSize; + USBEH_U16 idVendor; + USBEH_U16 idProduct; + USBEH_U16 bcdDevice; + USBEH_U08 iManufacturer; + USBEH_U08 iProduct; + USBEH_U08 iSerialNumber; + USBEH_U08 bNumConfigurations; +} USBEH_deviceDescriptor; + +typedef struct { + USBEH_U08 bLength; + USBEH_U08 bDescriptorType; + USBEH_U16 wTotalLength; + USBEH_U08 bNumInterfaces; + USBEH_U08 bConfigurationValue; + USBEH_U08 iConfiguration; + USBEH_U08 bmAttributes; + USBEH_U08 bMaxPower; +} USBEH_configurationDescriptor; + +typedef struct { + USBEH_U08 bLength; + USBEH_U08 bDescriptorType; + USBEH_U08 bInterfaceNumber; + USBEH_U08 bAlternateSetting; + USBEH_U08 bNumEndpoints; + USBEH_U08 bInterfaceClass; + USBEH_U08 bInterfaceSubClass; + USBEH_U08 bInterfaceProtocol; + USBEH_U08 iInterface; +} USBEH_interfaceDescriptor; + +typedef struct { + USBEH_U08 bLength; + USBEH_U08 bDescriptorType; + USBEH_U08 bEndpointAddress; + USBEH_U08 bmAttributes; + USBEH_U16 wMaxPacketSize; + USBEH_U08 bInterval; +} USBEH_endpointDescriptor; + +typedef struct { + USBEH_U08 bLength; + USBEH_U08 bDescriptorType; + USBEH_U16 bcdHID; + USBEH_U08 bCountryCode; + USBEH_U08 bNumDescriptors; + USBEH_U08 bDescriptorType2; + USBEH_U16 wDescriptorLength; +} USBEH_HIDDescriptor; + +typedef struct { + volatile USBEH_U32 control; + volatile USBEH_U32 tailTd; + volatile USBEH_U32 headTd; + volatile USBEH_U32 next; +} USBEH_HCED; + +typedef struct { + volatile USBEH_U32 control; + volatile USBEH_U32 currentBufferPointer; + volatile USBEH_U32 next; + volatile USBEH_U32 bufferEnd; +} USBEH_HCTD; + +typedef struct { + volatile USBEH_U32 interruptTable[32]; + volatile USBEH_U16 frameNumber; + volatile USBEH_U16 frameNumberPad; + volatile USBEH_U32 doneHead; + volatile USBEH_U08 Reserved[120]; +} USBEH_HCCA; + +typedef struct { + USBEH_U08 bm_request_type; + USBEH_U08 b_request; + USBEH_U16 w_value; + USBEH_U16 w_index; + USBEH_U16 w_length; +} USBEH_Setup; + +typedef void (*USBEH_callback)(int device, int endpoint, int status, USBEH_U08* data, int len, void* userData); + +#define USBEH_SOF_COUNTER_INC 1 +#define USBEH_SOF_COUNTER_DEC 2 +#define USBEH_SOF_COUNTER_DEC_HALT_AT_ZERO 4 +#define USBEH_SOF_COUNTER_RELOAD 8 + +typedef struct _sof_counter { + USBEH_U08 mode; + USBEH_U08 flag; + USBEH_U32 counter; + USBEH_U32 reload; + USBEH_U32 userData; + void (*callback)(struct _sof_counter *); + _sof_counter *next; +} USBEH_SOF_COUNTER; + +//typedef void (*USBCallback)(int device, int endpoint, int status, USBEH_U08* data, int len, void* userData); + + +// Macros. + +#define USBEH_CURRENT_CONNECT_STATUS 0x01 +#define USBEH_CONNECT_STATUS_CHANGE (USBEH_CURRENT_CONNECT_STATUS << 16) +#define USBEH_PORT_RESET_STATUS 0x10 +#define USBEH_PORT_RESET_STATUS_CAHNGE (USBEH_PORT_RESET_STATUS << 16) +#define USBEH_CONTROL_LIST_ENABLE 0x10 +#define USBEH_CONTROL_LIST_FILLED 0x02; +#define USBEH_BULK_LIST_ENABLE 0x20 +#define USBEH_BULK_LIST_FILLED 0x04 +#define USBEH_PERIODIC_LIST_ENABLE 0x04 +#define USBEH_PORT_RESET_STATUS 0x10 +#define USBEH_PORT_RESET_STATUS_CHANGE (USBEH_PORT_RESET_STATUS << 16) +#define USBEH_LOW_SPEED_DEVICE 0x200 +#define USBEH_HIGH_SPEED_DEVICE 0x400 + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbeh/usbeh_api.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,290 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#include "sowb.h" +#include "usbeh_api.h" +#include "usbeh_endpoint.h" +#include "usbeh_device.h" +#include "usbeh_controller.h" + +#include "main.h" +#include "debug.h" + +/* Device driver headers. */ +#include "xbox360gamepad.h" + +#define DEBUG_USB_API 1 + +USBEH_device_info_callback usb_devices_callback_map[] = { + (xbox360gamepad_onload_callback), + NULL +}; + +int usbeh_no_device_found(int device, USBEH_deviceDescriptor *deviceDesc, USBEH_interfaceDescriptor **interfaceDesc) { + USBEH_interfaceDescriptor *iface; + int interfaceCounter = 0; + debug_printf("%s CALLBACK ACTIVATED for device %d\r\n", __FUNCTION__, device); + debug_printf(" VendorId = %04X ProductId = %04X \r\n", deviceDesc->idVendor, deviceDesc->idProduct); + while ((iface = interfaceDesc[interfaceCounter]) != (USBEH_interfaceDescriptor *)NULL) { + debug_printf(" interface%d:- \r\n", interfaceCounter); + debug_printf(" InterfaceClass = %02X \r\n", iface->bInterfaceClass); + debug_printf(" InterfaceSubClass = %02X \r\n", iface->bInterfaceSubClass); + debug_printf(" InterfaceProtocol = %02X \r\n", iface->bInterfaceProtocol); + interfaceCounter++; + } + debug_printf(" No device driver loaded.\r\n"); + return 0; +} + +/* Create an instance of the USBEH controller and place + it within the AHB static ram area. */ +USBEH_Controller sys_usb_controller __attribute__((at(0x2007C000))); + + +void usbeh_api_on_load_device(int device, USBEH_deviceDescriptor* deviceDesc, USBEH_interfaceDescriptor **interfaceDesc) { + int i, slen, driver_loaded = 0; + char s[3][128]; + + memset((char *)s, 0, 3 * 128); + + /* Get device strings. */ + for (i = 1; i < 3; i++) { + slen = usbeh_api_get_string(device, i, s[i - 1], 128); + if (slen < 0) { + break; + } + } + + /* Scan through the device driver onLoad callbacks to see who wants to claim it. */ + for (i = 0; usb_devices_callback_map[i] != NULL && driver_loaded == 0; i++) { + driver_loaded = (usb_devices_callback_map[i])(device,deviceDesc,interfaceDesc); + } + + if (driver_loaded == 0) { + usbeh_no_device_found(device, deviceDesc, interfaceDesc); + } +} + +int usbeh_api_init(void) { + DEBUG_INIT_START; + sys_usb_controller.init(); + DEBUG_INIT_END; + return 0; +} + +void usbeh_api_process(void) { + sys_usb_controller.process(); +} + +int usbeh_api_set_address(int device, int new_addr) { + return usbeh_api_control_transfer(device, USBEH_HOST_TO_DEVICE | USBEH_RECIPIENT_DEVICE, USBEH_SET_ADDRESS, new_addr, 0, 0, 0, 0, 0); +} + +int usbeh_api_get_descriptor(int device, int descType,int descIndex, USBEH_U08* data, int length) { + return usbeh_api_control_transfer(device, USBEH_DEVICE_TO_HOST | USBEH_RECIPIENT_DEVICE, USBEH_GET_DESCRIPTOR, (descType << 8)|(descIndex), 0, data, length, 0, 0); +} + +static USBEH_Setup* usbeh_api_get_setup(int device) { + if (device == 0) { + return &sys_usb_controller.setupZero; + } + + if (device < 1 || device > USBEH_MAX_DEVICES) { + return 0; + } + + return &sys_usb_controller.devices[device-1].setupBuffer; +} + +static int usbeh_api_wait_IO_done(USBEH_Endpoint* endpoint) { + + if (endpoint->currentState == USBEH_Endpoint::notQueued) { + return 0; + } + + while (endpoint->currentState != USBEH_Endpoint::idle) { + usbeh_api_process(); + } + + int status = endpoint->status(); + if (status == 0) { + return endpoint->length; + } + + #ifdef DEBUG_USB_DRIVER + debug_printf("usbeh_api_wait_IO_done() error with 0x%x at line %d\r\n", status, __LINE__); + #endif + + return -status; +} + + +int usbeh_api_get_port_status(int device, int port, USBEH_U32 *status) { + return usbeh_api_control_transfer_short(device, USBEH_DEVICE_TO_HOST | USBEH_REQUEST_TYPE_CLASS | USBEH_RECIPIENT_OTHER, USBEH_GET_STATUS, 0, port, (USBEH_U08 *)status, 4); +} + +int usbeh_api_clear_port_feature(int device, int feature, int index) { + return usbeh_api_control_transfer(device, USBEH_HOST_TO_DEVICE | USBEH_REQUEST_TYPE_CLASS | USBEH_RECIPIENT_OTHER, USBEH_CLEAR_FEATURE, feature, index, 0, 0, 0, 0); +} + +int usbeh_api_set_port_power(int device, int port) { + int result = usbeh_api_set_port_feature(device, USBEH_PORT_POWER, port); + USBEH_OS_DELAY_MS(20); + return result; +} + +int usbeh_api_set_port_feature(int device, int feature, int index) { + return usbeh_api_control_transfer(device, USBEH_HOST_TO_DEVICE | USBEH_REQUEST_TYPE_CLASS | USBEH_RECIPIENT_OTHER, USBEH_SET_FEATURE, feature, index, 0, 0, 0, 0); +} + +int usbeh_api_set_configuration(int device, int configNum) { + return usbeh_api_control_transfer(device, USBEH_HOST_TO_DEVICE | USBEH_RECIPIENT_DEVICE, USBEH_SET_CONFIGURATION, configNum, 0, 0, 0, 0, 0); +} + +int usbeh_api_set_port_reset(int device, int port) { + return usbeh_api_set_port_feature(device, USBEH_PORT_RESET, port); +} + +int usbeh_api_get_string(int device, int index, char *dst, int length) { + + USBEH_U08 buffer[255]; + + int le = usbeh_api_get_descriptor(device, USBEH_DESCRIPTOR_TYPE_STRING, index, buffer, sizeof(buffer)); + + if (le < 0) { + return le; + } + + if (length < 1) { + return -1; + } + + length <<= 1; + + if (le > length) { + le = length; + } + + for (int j = 2; j < le; j += 2) { + *dst++ = buffer[j]; + } + + *dst = 0; + + return (le >> 1) - 1; +} + +int usbeh_api_transfer(int device, int ep, USBEH_U08 flags, USBEH_U08 *data, int length, USBEH_callback callback, void *userData) { + USBEH_Endpoint *endpoint = sys_usb_controller.getEndpoint(device, ep); + if (!endpoint) { + #ifdef DEBUG_USB_DRIVER + debug_printf("sys_usb_controller.getEndpoint() failed at line %d\r\n", __LINE__); + #endif + return USBEH_ERR_ENDPOINT_NOT_FOUND; + } + + usbeh_api_wait_IO_done(endpoint); + + endpoint->flags = flags; + endpoint->data = data; + endpoint->length = length; + endpoint->callback = callback; + endpoint->userData = userData; + + if (ep == 0) { + sys_usb_controller.transfer(endpoint, USBEH_TOKEN_SETUP, (USBEH_U08 *)usbeh_api_get_setup(device), 8, USBEH_Endpoint::setupQueued); + } + else { + sys_usb_controller.transfer(endpoint, flags & 0x80 ? USBEH_TOKEN_IN : USBEH_TOKEN_OUT, data, length, USBEH_Endpoint::dataQueued); + } + + if (callback) { + return USBEH_IO_PENDING; + } + + return usbeh_api_wait_IO_done(endpoint); +} + +int usbeh_api_interrupt_transfer(int device, int ep, USBEH_U08 *data, int length, USBEH_callback callback, void *userData) { + return usbeh_api_transfer(device, ep, (ep & 0x80) | USBEH_ENDPOINT_INTERRUPT, data, length, callback, userData); +} + +int usbeh_api_control_transfer_short(int device, int request_type, int request, int value, int index, USBEH_U08 *data, int length) { + return usbeh_api_control_transfer(device, request_type, request, value, index, data, length, 0, 0); +} + +int usbeh_api_control_transfer(int device, int request_type, int request, int value, int index, USBEH_U08 *data, int length, USBEH_callback callback, void *userData) { + USBEH_Setup* setup = usbeh_api_get_setup(device); + if (!setup) { + #ifdef DEBUG_USB_DRIVER + debug_printf("usbeh_api_get_setup() failed at line %d\r\n", __LINE__); + #endif + return USBEH_ERR_DEVICE_NOT_FOUND; + } + + usbeh_api_wait_IO_done(sys_usb_controller.getEndpoint(device,0)); + + setup->bm_request_type = request_type; + setup->b_request = request; + setup->w_value = value; + setup->w_index = index; + setup->w_length = length; + + return usbeh_api_transfer(device, 0, request_type & USBEH_DEVICE_TO_HOST, data, length, callback, userData); +} + +void usbeh_sof_counter_init(USBEH_SOF_COUNTER *q, USBEH_U08 mode, USBEH_U32 count) { + q->mode = mode; + q->flag = 0; + q->counter = count; + q->reload = count; + q->callback = NULL; + q->next = NULL; +} + +extern USBEH_SOF_COUNTER *sof_counter_head; +void usbeh_sof_counter_register(USBEH_SOF_COUNTER *q) { + q->next = sof_counter_head; + sof_counter_head = q; +} + +void usbeh_sof_counter_unregister(USBEH_SOF_COUNTER *q) { + USBEH_SOF_COUNTER *list; + for (list = sof_counter_head; list != NULL; list = list->next) { + if (list->next == q) { + list->next = q->next; + return; + } + } +} + + +void usbeh_api_list_endpoints(void) { + debug_printf("List system endpoints\r\n"); + for (int i = 0; i < USBEH_MAX_ENDPOINTS_TOTAL; i++) { + printf("Index %d: 0x%02X Status:%02X State:%d\r\n", i, + sys_usb_controller.endpoints[i].address(), + sys_usb_controller.endpoints[i].status(), + sys_usb_controller.endpoints[i].currentState + ); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbeh/usbeh_api.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,68 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef USBEH_API_H +#define USBEH_API_H + +#include "usbeh.h" +#include "usbeh_endpoint.h" +#include "usbeh_device.h" +#include "usbeh_controller.h" + +/* Define a callback for device driver OnLoad handlers. + Cast *info as (USBEH_DEVICE_INFO *) as that's what + will be passed. */ +typedef int (*USBEH_device_info_callback)(int device, USBEH_deviceDescriptor *deviceDesc, USBEH_interfaceDescriptor **interfaceDesc); + +/* Called for a device insertion. Define the driver in this function. */ +void usbeh_api_on_load_device(int device, USBEH_deviceDescriptor* deviceDesc, USBEH_interfaceDescriptor **interfaceDesc); + +/* Local statics. */ +static USBEH_Setup* usbeh_api_get_setup(int device); +static int usbeh_api_wait_IO_done(USBEH_Endpoint* endpoint); + +/* The exported API. */ +int usbeh_api_init(void); +void usbeh_api_process(void); +int usbeh_api_set_address(int device, int new_addr); +int usbeh_api_get_descriptor(int device, int descType,int descIndex, USBEH_U08* data, int length); +int usbeh_api_get_string(int device, int index, char *dst, int length); +int usbeh_api_get_port_status(int device, int port, USBEH_U32 *status); +int usbeh_api_clear_port_feature(int device, int feature, int index); +int usbeh_api_set_port_feature(int device, int feature, int index); +int usbeh_api_set_port_power(int device, int port); +int usbeh_api_set_configuration(int device, int configNum); +int usbeh_api_set_port_reset(int device, int port); +int usbeh_api_transfer(int device, int ep, USBEH_U08 flags, USBEH_U08 *data, int length, USBEH_callback callback, void* userData); +int usbeh_api_interrupt_transfer(int device, int ep, USBEH_U08* data, int length, USBEH_callback callback, void* userData); +int usbeh_api_control_transfer_short(int device, int request_type, int request, int value, int index, USBEH_U08 *data, int length); +int usbeh_api_control_transfer(int device, int request_type, int request, int value, int index, USBEH_U08 *data, int length, USBEH_callback callback, void *userData); + +void usbeh_sof_counter_init(USBEH_SOF_COUNTER *q, USBEH_U08 mode, USBEH_U32 count); +void usbeh_sof_counter_register(USBEH_SOF_COUNTER *q); +void usbeh_sof_counter_unregister(USBEH_SOF_COUNTER *q); + +/* Debugging. */ +void usbeh_api_list_endpoints(void); + +// END #ifndef USBEH_API_H +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbeh/usbeh_controller.cpp Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,602 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#include "sowb.h" +#include "usbeh_endpoint.h" +#include "usbeh_device.h" +#include "usbeh_controller.h" +#include "usbeh_api.h" + +#include "main.h" +#include "debug.h" + +void USBEH_Controller::process(void) { + USBEH_Endpoint *endpoint; + USBEH_U16 elapsed = hcca.frameNumber - (USBEH_U16)this->frameNumber; + this->frameNumber += elapsed; + + while (this->callbacksPending) { + for (int i = 0; i < USBEH_MAX_ENDPOINTS_TOTAL; i++) { + endpoint = this->endpoints + i; + if (endpoint->currentState == USBEH_Endpoint::callbackPending) { + this->callbacksPending--; + endpoint->currentState = USBEH_Endpoint::idle; + endpoint->callback( + endpoint->device(), + endpoint->address(), + endpoint->status(), + (USBEH_U08 *)endpoint->userData, + endpoint->length, + endpoint->userData); + } + } + } + + if (this->rootHubStatusChange) { + USBEH_U32 status = USBEH_HcRhPortStatus1; + this->rootHubStatusChange = 0; + if (status >> 16) { + hubStatusChange(0, 1, status); + USBEH_HcRhPortStatus1 = status & 0xFFFF0000; + } + } + + if (this->connectCountdown) { + if (elapsed >= this->connectCountdown) { + this->connectCountdown = 0; + connect(this->connectHub, this->connectPort & 0x7F, this->connectPort & 0x80); + } + else { + this->connectCountdown -= elapsed; + } + } +} + +void USBEH_Controller::init(void) { + memset(this, 0, sizeof(USBEH_Controller)); + endpointZero.currentState = USBEH_Endpoint::notQueued; + initHW(&hcca); + delayMS(10); +} + +void USBEH_Controller::hubInterrupt(int device) { + USBEH_Device *dev = &devices[device - 1]; + + for (int i = 0; i < dev->hubPortCount; i++) { + int port = i + 1; + if (dev->hubInterruptData * (1 << port)) { + USBEH_U32 status = 0; + usbeh_api_get_port_status(device, port, &status); + if (status >> 16) { + if (connectPending && (status & USBEH_CONNECT_STATUS_CHANGE)) { + hubStatusChange(device, port, status); + if (status & USBEH_CONNECT_STATUS_CHANGE) { + usbeh_api_clear_port_feature(device, USBEH_C_PORT_CONNECTION, port); + } + if (status & USBEH_PORT_RESET_STATUS_CAHNGE) { + usbeh_api_clear_port_feature(device, USBEH_C_PORT_RESET, port); + } + } + } + } + } +} + +void USBEH_Controller::hubInterruptCallback(int device, int endpoint, int status, USBEH_U08 *data, int length, void *userData) { + USBEH_Controller *controller = (USBEH_Controller *)userData; + if (status == 0) { + controller->hubInterrupt(device); + } + usbeh_api_interrupt_transfer(device, endpoint, data, 1, hubInterruptCallback, userData); +} + +int USBEH_Controller::initHub(int device) { + USBEH_U08 buffer[16]; + int r = usbeh_api_control_transfer(device, USBEH_DEVICE_TO_HOST | USBEH_REQUEST_TYPE_CLASS | USBEH_RECIPIENT_DEVICE, USBEH_GET_DESCRIPTOR, (USBEH_DESCRIPTOR_TYPE_HUB << 8), 0, buffer, sizeof(buffer), 0, 0); + if (r < 0) return -1; + + USBEH_Device *dev = &this->devices[device - 1]; + + int ports = buffer[2]; + + for (int i = 0; i < ports; i++) { + usbeh_api_set_port_power(device, i + 1); + } + + return usbeh_api_interrupt_transfer(device, 0x81, &dev->hubInterruptData,1, hubInterruptCallback, this); +} + +int USBEH_Controller::transfer(USBEH_Endpoint *endpoint, int token, USBEH_U08 *data, int len, int state) { + + int toggle = 0; + + if (endpoint->address() == 0) { + toggle = (token == USBEH_TOKEN_SETUP) ? USBEH_TD_TOGGLE_0 : USBEH_TD_TOGGLE_1; + } + + if (token != USBEH_TOKEN_SETUP) { + token = (token == USBEH_TOKEN_IN ? USBEH_TD_IN : USBEH_TD_OUT); + } + + USBEH_HCTD *head = &endpoint->tdHead; + USBEH_HCTD *tail = &this->commonTail; + + head->control = USBEH_TD_ROUNDING | token | USBEH_TD_DELAY_INT(0) | toggle | USBEH_TD_CC; + head->currentBufferPointer = (USBEH_U32)data; + head->bufferEnd = (USBEH_U32)(data + len - 1); + head->next = (USBEH_U32)tail; + + USBEH_HCED *ed = &endpoint->endpointDescriptor; + ed->headTd = (USBEH_U32)head | (ed->headTd & 0x00000002); + ed->tailTd = (USBEH_U32)tail; + + switch (endpoint->flags & 3) { + case USBEH_ENDPOINT_CONTROL: + USBEH_HcControlHeadED = endpoint->queue(USBEH_HcControlHeadED); + endpoint->currentState = state; + USBEH_HcCommandStatus = USBEH_HcCommandStatus | USBEH_CONTROL_LIST_FILLED; + USBEH_HcControl |= USBEH_CONTROL_LIST_ENABLE; + break; + case USBEH_ENDPOINT_BULK: + USBEH_HcBulkHeadED = endpoint->queue(USBEH_HcBulkHeadED); + endpoint->currentState = state; + USBEH_HcCommandStatus = USBEH_HcCommandStatus | USBEH_BULK_LIST_FILLED; + USBEH_HcControl |= USBEH_BULK_LIST_ENABLE; + break; + case USBEH_ENDPOINT_INTERRUPT: + hcca.interruptTable[0] = endpoint->queue(hcca.interruptTable[0]); + endpoint->currentState = state; + USBEH_HcControl |= USBEH_PERIODIC_LIST_ENABLE; + break; + } + + return 0; +} + +bool USBEH_Controller::remove(USBEH_HCED *ed, volatile USBEH_HCED **queue) { + if (*queue == 0) return false; + if (*queue == (volatile USBEH_HCED *)ed) { + *queue = (volatile USBEH_HCED *)ed->next; + return true; + } + + volatile USBEH_HCED *head = *queue; + while (head) { + if (head->next == (USBEH_U32)ed) { + head->next = ed->next; + return true; + } + head = (volatile USBEH_HCED *)head->next; + } + + return false; +} + +void USBEH_Controller::release(USBEH_Endpoint *endpoint) { + if (endpoint->currentState != USBEH_Endpoint::notQueued) { + USBEH_HCED *ed = (USBEH_HCED *)endpoint; + ed->control |= 0x4000; + switch (endpoint->flags & 0x3) { + case USBEH_ENDPOINT_CONTROL: + remove(ed, (volatile USBEH_HCED **)&USBEH_HcControlHeadED); + break; + case USBEH_ENDPOINT_BULK: + remove(ed, (volatile USBEH_HCED **)&USBEH_HcBulkHeadED); + break; + case USBEH_ENDPOINT_INTERRUPT: + for (int i = 0; i < 32; i++) { + remove(ed, (volatile USBEH_HCED **)&hcca.interruptTable[i]); + } + break; + } + + USBEH_U16 fn = hcca.frameNumber; + while (fn == hcca.frameNumber) ; + } + + memset(endpoint, 0, sizeof(USBEH_Endpoint)); +} + +int USBEH_Controller::addEndpoint(int device, USBEH_endpointDescriptor *endpoint) { + return addEndpoint(device, endpoint->bEndpointAddress, endpoint->bmAttributes, endpoint->wMaxPacketSize, endpoint->bInterval); +} + +int USBEH_Controller::addEndpoint(int device, int endpoint, int attributes, int maxPacketSize, int interval) { + USBEH_Device *dev = &this->devices[device - 1]; + USBEH_Endpoint *ep = allocateEndpoint(device, endpoint, attributes, maxPacketSize); + if (!ep) { + return -1; + } + dev->setEndpointIndex(endpoint, ep - this->endpoints); + ep->endpointDescriptor.control |= dev->flags; + return 0; + +} + +USBEH_Endpoint * USBEH_Controller::allocateEndpoint(int device, int endpointAddress, int type, int maxPacketSize) { + for (int i = 0; i < USBEH_MAX_ENDPOINTS_TOTAL; i++) { + USBEH_Endpoint *ep = &this->endpoints[i]; + if (ep->currentState == 0) { + ep->flags = (endpointAddress & 0x80) | (type & 0x3); + ep->currentState = USBEH_Endpoint::notQueued; + ep->endpointDescriptor.control = (maxPacketSize << 16) | ((endpointAddress & 0x7F) << 7) | device; + return ep; + } + } + return 0; +} + +int USBEH_Controller::addDevice(int hub, int port, bool isLowSpeed) { + int device = addDeviceCore(hub, port, isLowSpeed); + if (device < 0) { + disconnect(hub, port); + resetPort(hub, port); + return -1; + } + return device; +} + +int USBEH_Controller::addDeviceCore(int hub, int port, bool isLowSpeed) { + + int lowSpeed = isLowSpeed ? 0x2000 : 0; + + USBEH_deviceDescriptor desc; + + endpointZero.endpointDescriptor.control = (8 << 16) | lowSpeed; + + int result = usbeh_api_get_descriptor(0, USBEH_DESCRIPTOR_TYPE_DEVICE, 0, (USBEH_U08 *)&desc, 8); + + if (result < 0) { + #ifdef DEBUG_USB_DRIVER + debug_printf("usbeh_api_get_descriptor() failed with %d (0x%x) at line %d\r\n", result, result, __LINE__); + #endif + return result; + } + + endpointZero.endpointDescriptor.control = (desc.bMaxPacketSize << 16) | lowSpeed; + + result = usbeh_api_get_descriptor(0, USBEH_DESCRIPTOR_TYPE_DEVICE, 0, (USBEH_U08 *)&desc, sizeof(desc)); + if (result < 0) { + #ifdef DEBUG_USB_DRIVER + debug_printf("usbeh_api_get_descriptor() failed with %d at line %d\r\n", result, __LINE__); + #endif + return result; + } + + int device = 0; + for (int i = 0; i < USBEH_MAX_DEVICES; i++) { + if (devices[i].port == 0) { + device = i + 1; + break; + } + } + + if (!device) { + return -1; + } + + result = usbeh_api_set_address(0, device); + if (result) { + return result; + } + + delayMS(2); + + USBEH_Device *dev = &devices[device - 1]; + dev->init(&desc, hub, port, device, lowSpeed); + addEndpoint(device, 0, USBEH_ENDPOINT_CONTROL, desc.bMaxPacketSize, 0); + this->connectPending = 0; + + if ((result = usbeh_api_get_descriptor(device, USBEH_DESCRIPTOR_TYPE_DEVICE, 0, (USBEH_U08 *)&desc, sizeof(desc))) < 0) { + #ifdef DEBUG_USB_DRIVER + debug_printf("usbeh_api_get_descriptor() failed with %d at line %d\r\n", result, __LINE__); + #endif + return result; + } + + result = setConfigurationAndInterface(device, 1, -1, &desc); + + if (desc.bDeviceClass == CLASS_HUB) { + initHub(device); + } + + return device; +} + +int USBEH_Controller::setConfigurationAndInterface(int device, int configuration, int interfaceNumber, USBEH_deviceDescriptor *desc) { + USBEH_U08 buffer[255]; + USBEH_interfaceDescriptor *found[16]; + USBEH_endpointDescriptor *ed; + + for (int i = 0; i < 16; i++) { + found[i] = (USBEH_interfaceDescriptor *)NULL; + } + + int err = usbeh_api_get_descriptor(device, USBEH_DESCRIPTOR_TYPE_CONFIGURATION, 0, buffer, sizeof(buffer)); + if (err < 0) { + #ifdef DEBUG_USB_DRIVER + debug_printf("GET_DESCRIPTOR failed at line %d\r\n", __LINE__); + #endif + return err; + } + + err = usbeh_api_set_configuration(device, configuration); + if (err < 0) { + return err; + } + + int interfaceCounter = 0; + int len = buffer[2] | (buffer[3] << 8); + USBEH_U08 *d = buffer; + USBEH_U08 *end = d + len; + while (d < end) { + //printf("Testing descriptor type %02x\n\r", d[1]); + if (d[1] == USBEH_DESCRIPTOR_TYPE_INTERFACE) { + //printf(" Found interface descriptor type %02x\n\r", d[1]); + USBEH_interfaceDescriptor *id = (USBEH_interfaceDescriptor *)d; + if (interfaceNumber == -1 || id->bInterfaceNumber == interfaceNumber) { + found[interfaceCounter++] = id; + d += d[0]; + while (d < end && d[1] != USBEH_DESCRIPTOR_TYPE_INTERFACE) { + switch (d[1]) { + case USBEH_DESCRIPTOR_TYPE_ENDPOINT: + ed = (USBEH_endpointDescriptor *)d; + //printf(" Adding endpoint 0x%02x for interface %d\r\n", ed->bEndpointAddress, id->bInterfaceNumber); + addEndpoint(device, ed); + break; + default: + // Skip unknown descriptor. + //printf(" Unknown descriptor type: %02x\r\n", d[1]); + break; + } + d += d[0]; + } + } + } + else { + d += d[0]; + } + } + + if (interfaceCounter == 0) { + return USBEH_ERR_INTERFACE_NOT_FOUND; + } + + usbeh_api_on_load_device(device, desc, found); + + return 0; +} + +void USBEH_Controller::processDoneQueue(USBEH_U32 tdList) { + USBEH_Endpoint *endpoint; + USBEH_HCTD *list = reverse((USBEH_HCTD *)tdList); + while (list) { + endpoint = (USBEH_Endpoint *)(list - 1); + list = (USBEH_HCTD *)list->next; + int ep = endpoint->address(); + bool in = endpoint->flags & 0x80; + int status = (endpoint->tdHead.control >> 28) & 0xF; + + if (status != 0) { + endpoint->currentState = USBEH_Endpoint::idle; + } + else { + switch (endpoint->currentState) { + case USBEH_Endpoint::setupQueued: + if (endpoint->length == 0) { + transfer(endpoint, in ? USBEH_TOKEN_OUT : USBEH_TOKEN_IN, 0, 0, USBEH_Endpoint::statusQueued); + } + else { + transfer(endpoint, in ? USBEH_TOKEN_IN : USBEH_TOKEN_OUT, (USBEH_U08 *)endpoint->data, endpoint->length, USBEH_Endpoint::dataQueued); + } + break; + + case USBEH_Endpoint::dataQueued: + if (endpoint->tdHead.currentBufferPointer) { + endpoint->length = endpoint->tdHead.currentBufferPointer - (USBEH_U32)endpoint->data; + } + + if (ep == 0) { + transfer(endpoint, in ? USBEH_TOKEN_OUT : USBEH_TOKEN_IN, 0, 0, USBEH_Endpoint::statusQueued); + } + else { + endpoint->currentState = USBEH_Endpoint::idle; + } + break; + + case USBEH_Endpoint::statusQueued: + endpoint->currentState = USBEH_Endpoint::idle; + break; + } + } + + if (endpoint->callback && endpoint->currentState == USBEH_Endpoint::idle) { + //if (endpoint->address() != 0x81) printf("\r\nCallback pending for 0x%02X\r\n", endpoint->address()); + endpoint->currentState = USBEH_Endpoint::callbackPending; + this->callbacksPending++; + } + } +} + +void USBEH_Controller::resetPort(int hub, int port) { + this->connectPending++; + if (hub == 0) { + USBEH_HcRhPortStatus1 = USBEH_PORT_RESET_STATUS; + } + else { + usbeh_api_set_port_reset(hub, port); + } +} + +void USBEH_Controller::connect(int hub, int port, bool lowSpeed) { + #ifdef DEBUG_USB_DRIVER + debug_printf("%s called at line %d\r\n", __FUNCTION__, __LINE__); + #endif + addDevice(hub, port, lowSpeed); +} + +void USBEH_Controller::disconnect(int hub, int port) { + for (int i = 0; i < USBEH_MAX_DEVICES; i++) { + USBEH_Device *dev = this->devices + i; + if (dev->port == port && dev->hub == hub) { + for (int p = 0; p < dev->hubPortCount; p++) { + disconnect(i + 1, p + 1); + } + for (int j = 1; j < USBEH_MAX_ENDPOINTS_PER_DEVICE * 2; j += 2) { + USBEH_U08 endpointIndex = dev->endpoints[j]; + if (endpointIndex != 0xFF) { + release(this->endpoints + endpointIndex); + } + dev->port = 0; + dev->flags = 0; + return; + } + } + } +} + +void USBEH_Controller::hubStatusChange(int hub, int port, USBEH_U32 status) { + if (status & USBEH_CONNECT_STATUS_CHANGE) { + if (status & USBEH_CURRENT_CONNECT_STATUS) { + resetPort(hub, port); + } + else { + disconnect(hub, port); + } + } + + if (status & USBEH_PORT_RESET_STATUS_CHANGE) { + if (!(status & USBEH_PORT_RESET_STATUS)) { + this->connectCountdown = 200; + if (status & USBEH_LOW_SPEED_DEVICE) { + port |= 0x80; + } + this->connectHub = hub; + this->connectPort = port; + } + } +} + +void USBEH_Controller::delayMS(int ms) { + USBEH_U16 f = ms + hcca.frameNumber; + while (f != hcca.frameNumber) ; +} + +void USBEH_Controller::initHW(USBEH_HCCA *cca) { + NVIC_DisableIRQ(USB_IRQn); + + LPC_SC->PCONP |= (1UL << 31); + LPC_USB->USBClkCtrl |= USBEH_CLOCK_MASK; + while ((LPC_USB->USBClkSt & USBEH_CLOCK_MASK) != USBEH_CLOCK_MASK); + + USBEH_OTGStCtrl |= 1; + USBEH_USBClkCtrl &= ~USBEH_PORTSEL_CLK_EN; + + LPC_PINCON->PINSEL1 &= ~( (3<<26) | (3<<28) ); + LPC_PINCON->PINSEL1 |= ( (1<<26) | (1<<28)); + + USBEH_HcControl = 0; + USBEH_HcControlHeadED = 0; + USBEH_HcBulkHeadED = 0; + USBEH_HcCommandStatus = USBEH_HOST_CONTROLLER_RESET; + USBEH_HcFmInterval = USBEH_DEFAULT_FMINTERVAL; + USBEH_HcPeriodicStart = USBEH_FRAMEINTERVAL * 90 / 100; + + USBEH_HcControl = (USBEH_HcControl & (~USBEH_HOST_CONTROLLER_FUNCTIONAL_STATE)) | USBEH_OPERATIONAL_MASK; + USBEH_HcRhStatus = USBEH_SET_GLOBAL_POWER; + + USBEH_HcHCCA = (USBEH_U32)cca; + USBEH_HcInterruptStatus |= USBEH_HcInterruptStatus; + USBEH_HcInterruptEnable |= USBEH_MASTER_IRQ_ENABLE | USBEH_WRITEBACK_DONE_HEAD | USBEH_ROOT_HUB_STATUS_CHANGE | USBEH_FRAME_NUMBER_OVERFLOW | USBEH_START_OF_FRAME; + + NVIC_EnableIRQ(USB_IRQn); + while (cca->frameNumber < 10); +} + +USBEH_HCTD * USBEH_Controller::reverse(USBEH_HCTD *current) { + USBEH_HCTD *result = NULL, *temp; + while (current) { + temp = (USBEH_HCTD *)current->next; + current->next = (USBEH_U32)result; + result = current; + current = temp; + } + return result; +} + +USBEH_Endpoint * USBEH_Controller::getEndpoint(int device, int ep) { + if (device == 0) { + return &endpointZero; + } + if (device > USBEH_MAX_DEVICES) { + return 0; + } + int i = devices[device - 1].getEndpointIndex(ep); + if (i == -1) { + return 0; + } + return endpoints + i; +} + +/* The controller is defined withinn the API section. */ +extern USBEH_Controller sys_usb_controller; + +USBEH_SOF_COUNTER *sof_counter_head = NULL; + +/* The USB interrupt handler. */ +extern "C" void USB_IRQHandler (void) __irq { + + USBEH_U32 int_status = USBEH_HcInterruptStatus; + + if (int_status & USBEH_ROOT_HUB_STATUS_CHANGE) { + sys_usb_controller.rootHubStatusChange++; + } + + USBEH_U32 head = 0; + + if (int_status & USBEH_WRITEBACK_DONE_HEAD) { + head = sys_usb_controller.hcca.doneHead; + sys_usb_controller.hcca.doneHead = 0; + } + + if (int_status & USBEH_START_OF_FRAME) { + for (USBEH_SOF_COUNTER *list = sof_counter_head; list != NULL; list = list->next) { + if (list->mode & USBEH_SOF_COUNTER_DEC && list->flag == 0) { + if (list->counter > 0) list->counter--; + if (list->counter == 0) { + list->flag = 1; + list->counter = list->reload; + if (list->callback != NULL) { + (list->callback)((struct _sof_counter *)list); + } + } + } + } + } + + USBEH_HcInterruptStatus = int_status; + + if (head) { + sys_usb_controller.processDoneQueue(head); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbeh/usbeh_controller.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,82 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef USBEH_CONTROLLER_H +#define USBEH_CONTROLLER_H + +#include "usbeh.h" +#include "usbeh_device.h" +#include "usbeh_endpoint.h" + +class USBEH_Controller { + + public: + + USBEH_HCCA hcca; + USBEH_Endpoint endpoints[USBEH_MAX_ENDPOINTS_TOTAL]; + USBEH_Endpoint endpointZero; + USBEH_HCTD commonTail; + USBEH_Setup setupZero; + USBEH_Device devices[USBEH_MAX_DEVICES]; + + USBEH_U32 frameNumber; + USBEH_U08 callbacksPending; + USBEH_U08 rootHubStatusChange; + USBEH_U08 unused0; + USBEH_U08 unused1; + USBEH_U08 connectPending; + USBEH_U08 connectCountdown; + USBEH_U08 connectHub; + USBEH_U08 connectPort; + + USBEH_U08 SRAM[0]; + + // Methods. + void init(void); + void process(void); + int initHub(int device); + int transfer(USBEH_Endpoint *endpoint, int token, USBEH_U08 *data, int length, int state); + bool remove(USBEH_HCED *ed, volatile USBEH_HCED **queue); + void release(USBEH_Endpoint *endpoint); + int addEndpoint(int device, USBEH_endpointDescriptor *endpoint); + int addEndpoint(int device, int endpoint, int attributes, int maxPacketSize, int interval); + int addDevice(int hub, int port, bool isLowSpeed); + int addDeviceCore(int hub, int port, bool isLowSpeed); + int setConfigurationAndInterface(int device, int configuration, int interfaceNumber, USBEH_deviceDescriptor *desc); + void processDoneQueue(USBEH_U32 tdList); + void resetPort(int hub, int port); + void connect(int hub, int port, bool lowSpeed); + void disconnect(int hub, int port); + void hubStatusChange(int hub, int port, USBEH_U32 status); + void delayMS(int ms); + void initHW(USBEH_HCCA *cca); + void hubInterrupt(int device); + static void hubInterruptCallback(int device, int endpoint, int status, USBEH_U08 *data, int length, void *userData); + USBEH_HCTD * reverse(USBEH_HCTD *current); + USBEH_Endpoint * getEndpoint(int device, int ep); + USBEH_Endpoint * allocateEndpoint(int device, int endpointAddress, int type, int maxPacketSize); + +}; + + +// END #ifndef USBEH_CONTROLLER_H +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbeh/usbeh_device.cpp Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,55 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#include "sowb.h" +#include "usbeh.h" +#include "usbeh_endpoint.h" +#include "usbeh_device.h" + +int USBEH_Device::init(USBEH_deviceDescriptor *d, int hub, int port, int addr, int lowSpeed) { + this->hub = hub; + this->port = port; + this->addr = addr; + this->flags = lowSpeed; + memset(endpoints,0xFF,sizeof(endpoints)); + return 0; +} + + +int USBEH_Device::setEndpointIndex (int endpoint, int endpointIndex) { + for (int i = 0; i < 16; i += 2) { + if (endpoints[i] == 0xFF) { + endpoints[i+0] = endpoint; + endpoints[i+1] = endpointIndex; + return 0; + } + } + return -1; +} + +int USBEH_Device::getEndpointIndex (int endpoint) { + for (int i = 0; i < 16; i += 2) { + if (endpoints[i] == endpoint) return endpoints[i+1]; + if (endpoints[i] == 0xFF) break; + } + return -1; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbeh/usbeh_device.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,57 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef USBEH_DEVICE_H +#define USBEH_DEVICE_H + +#ifndef USBEH_H +#include "usbeh.h" +#endif + +class USBEH_Device { + + public: + + USBEH_U08 endpoints[16 * 2]; + USBEH_U08 hub; + USBEH_U08 port; + USBEH_U08 addr; + USBEH_U08 pad; + + USBEH_U08 hubPortCount; + USBEH_U08 hubInterruptData; + USBEH_U08 hubMap; + USBEH_U08 hubMask; + + int flags; + USBEH_Setup setupBuffer; + + // Member functions. + int init(USBEH_deviceDescriptor *d, int hub, int port, int addr, int lowSpeed); + int setEndpointIndex (int endpoint, int endpointIndex); + int getEndpointIndex (int endpoint); + +}; + + +// END #ifndef USBEH_DEVICE_H +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbeh/usbeh_endpoint.cpp Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,50 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#include "sowb.h" +#include "usbeh.h" +#include "usbeh_endpoint.h" + +int USBEH_Endpoint::address(void) { + int address = (endpointDescriptor.control >> 7) & 0xf; + if (address) { + address |= flags & 0x80; + } + return address; +} + +int USBEH_Endpoint::device(void) { + return endpointDescriptor.control & 0x7f; +} + +int USBEH_Endpoint::status(void) { + return (tdHead.control >> 28) & 0xF; +} + +USBEH_U32 USBEH_Endpoint::queue(USBEH_U32 head) { + if (currentState == notQueued) { + endpointDescriptor.next = head; + head = (USBEH_U32)&endpointDescriptor; + currentState = idle; + } + return head; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbeh/usbeh_endpoint.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,63 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef USBEH_ENDPOINT_H +#define USBEH_ENDPOINT_H + +#ifndef USBEH_H +#include "usbeh.h" +#endif + +class USBEH_Endpoint { + + public: + USBEH_HCED endpointDescriptor; + USBEH_HCTD tdHead; + + // State definitions. + enum state { + free, // 0 + notQueued, // 1 + idle, // 2 + setupQueued, // 3 + dataQueued, // 4 + statusQueued, // 5 + callbackPending // 6 + }; + + // Local data. + volatile USBEH_U08 currentState; + USBEH_U08 flags; + USBEH_U16 length; + USBEH_U08 *data; + USBEH_callback callback; + void *userData; + + // Member functions. + int address(void); + int device(void); + int status(void); + USBEH_U32 queue(USBEH_U32); +}; + +// END #ifndef USBEH_ENDPOINT_H +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbeh/xbox360gamepad.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,707 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#include "sowb.h" +#include "debug.h" +#include "usbeh_api.h" +#include "usbeh_endpoint.h" +#include "usbeh_device.h" +#include "usbeh_controller.h" +#include "xbox360gamepad.h" + +#include "main.h" + +/* Define an array of data structures for the buttons. */ +static XBOX360_BUTTON buttons[16]; +static unsigned char button_buffer[16]; +static unsigned char button_buffer_in; +static unsigned char button_buffer_out; + +/* Place holders for left and right triggers. */ +static unsigned char trigger_left; +static unsigned char trigger_right; + +static XBOX360_STICK stick_left; +static XBOX360_STICK stick_right; + +/* A map of wired Xbox 360 controllers. + Data copied from the Linux xboxdrv project, thx :) + http://pingus.seul.org/~grumbel/xboxdrv */ +static XBOX360_DEVICE xbox360_devices[] = { + { 0x045e, 0x028e, "Microsoft Xbox 360 Controller" }, + { 0x0738, 0x4716, "Mad Catz Xbox 360 Controller" }, + { 0x0738, 0x4726, "Mad Catz Xbox 360 Controller" }, + { 0x0738, 0x4740, "Mad Catz Beat Pad" }, + { 0x0738, 0xf738, "Super SFIV FightStick TE S" }, + { 0x0f0d, 0x000a, "Hori Co. DOA4 FightStick" }, + { 0x0f0d, 0x000d, "Hori Fighting Stick Ex2" }, + { 0x0f0d, 0x0016, "Hori Real Arcade Pro Ex" }, + { 0x162e, 0xbeef, "Joytech Neo-Se Take2" }, + { 0x046d, 0xc242, "Logitech ChillStream" }, + { 0x0738, 0xcb03, "Saitek P3200 Rumble Pad - PC/Xbox 360" }, + { 0x0e6f, 0x0201, "Pelican TSZ360 Pad" }, + { 0x0738, 0xb726, "Mad Catz Xbox controller - MW2" }, // Here's one I found that isn't in the Linux distro. + { 0x0000, 0x0000, "End of list" } +}; + +/* Although Microsoft has not published any data or specifications + regarding the Xbox360 gamepad/controller, it's basic makeup is + well known. Define here the pipes for the interfaces we are + interested in. */ + +#define XBOX360_GAMEPAD_PIPE_BUFFER_SIZE 32 + +typedef struct { + USBEH_U08 data_in[XBOX360_GAMEPAD_PIPE_BUFFER_SIZE]; + USBEH_U08 data_out[XBOX360_GAMEPAD_PIPE_BUFFER_SIZE]; + USBEH_U08 ep_number_in; + USBEH_U08 ep_number_out; +} XBOX360_PIPE; + +typedef struct { + USBEH_U08 data_in[256]; + USBEH_U08 data_out[256]; + USBEH_U08 ep_number_in; + USBEH_U08 ep_number_out; +} XBOX360_CONTROL_PIPE; + +struct _xbox360_gamepad_vendor { + XBOX360_CONTROL_PIPE pipe[1]; +} IF_VENDOR __attribute__((aligned(256))); + +struct _xbox360_gamepad_interface0 { + XBOX360_PIPE pipe[1]; +} IF_ZERO __attribute__((aligned(256))); + +struct _xbox360_gamepad_interface1 { + XBOX360_PIPE pipe[2]; +} IF_ONE __attribute__((aligned(256))); + +struct _xbox360_gamepad_interface2 { + XBOX360_PIPE pipe[1]; +} IF_TWO __attribute__((aligned(256))); + +int deviceNumber; + +int xbox360gamepad_init(void) { + DEBUG_INIT_START; + for (int i = 0; i < 16; i++) { + buttons[i].state = BUTTON_RELEASED; + buttons[i].count = 0; + button_buffer[i] = 0xFF; + usbeh_sof_counter_init(&buttons[i].pressHold, USBEH_SOF_COUNTER_DEC | USBEH_SOF_COUNTER_RELOAD, BUTTON_HOLD_TIME); + buttons[i].pressHold.userData = i; + buttons[i].pressHold.callback = xbox360gamepad_button_hold_callback; + usbeh_sof_counter_register(&buttons[i].pressHold); + } + button_buffer_in = 0; + button_buffer_out = 0; + trigger_left = 0; + trigger_right = 0; + stick_left.x = 0; + stick_left.y = 0; + stick_right.x = 0; + stick_right.y = 0; + DEBUG_INIT_END; + return 0; +} + +void xbox360gamepad_process(void) { + // This currently does nothing. +} + +void xbox360gamepad_button_press(unsigned char button) { + button_buffer[button_buffer_in] = button; + button_buffer_in++; + button_buffer_in &= 0x0F; +} + +char xbox360gamepad_get_button(void) { + if (button_buffer_in == button_buffer_out) { + return 0; + } + + char button = button_buffer[button_buffer_out]; + button_buffer_out++; + button_buffer_out &= 0x0F; + return button; +} + +char xbox360gamepad_get_button_preview(void) { + if (button_buffer_in == button_buffer_out) { + return 0; + } + + char button = button_buffer[button_buffer_out]; + return button; +} + +unsigned char xbox360gamepad_get_trigger_left(void) { + return trigger_left; +} + +unsigned char xbox360gamepad_get_trigger_right(void) { + return trigger_right; +} + +XBOX360_STICK * xbox360gamepad_get_stick_left(void) { + return &stick_left; +} + +XBOX360_STICK * xbox360gamepad_get_stick_right(void) { + return &stick_right; +} + +void xbox360gamepad_button_hold_callback(USBEH_SOF_COUNTER *q) { + int i = (int)q->userData; + if (buttons[i].state == BUTTON_PRESSED) { + xbox360gamepad_button_press((char)(i + 1 + 32)); + } +} + +/** + * xbox360gamepad_interface_0_in + * + * A callback function to handle interface0 pipe0 data. + */ +void xbox360gamepad_interface_0_in(int device, int endpoint, int status, USBEH_U08 *data, int len, void *userData) { + unsigned button_flags; + + /* Is this a button press report? */ + if(IF_ZERO.pipe[(int)userData].data_in[0] == 0 && IF_ZERO.pipe[(int)userData].data_in[1] == 0x14) { + + /* Handle the button flags. */ + button_flags = ((IF_ZERO.pipe[(int)userData].data_in[2] & 0xFF) << 8) | (IF_ZERO.pipe[(int)userData].data_in[3] & 0xFF); + for (int i = 0; i < 16; i++) { + if ((button_flags & (1 << i)) != 0) { + if (buttons[i].state == BUTTON_RELEASED) { + buttons[i].state = BUTTON_PRESSED; + buttons[i].count++; + buttons[i].pressHold.flag = 0; + xbox360gamepad_button_press((char)(i + 1)); + } + } + else { + if (buttons[i].state == BUTTON_PRESSED) { + buttons[i].state = BUTTON_RELEASED; + buttons[i].pressHold.flag = 1; + buttons[i].pressHold.counter = BUTTON_HOLD_TIME; + buttons[i].count = 0; + xbox360gamepad_button_press((char)(i + 1 + 16)); + } + } + } + + /* Handle the analogue triggers. */ + trigger_left = (unsigned char)IF_ZERO.pipe[(int)userData].data_in[4]; + trigger_right = (unsigned char)IF_ZERO.pipe[(int)userData].data_in[5]; + + /* Handle the analogue sticks. */ + { + short x, y; + x = (short)((IF_ZERO.pipe[(int)userData].data_in[6]) | IF_ZERO.pipe[(int)userData].data_in[7] << 8); + y = (short)((IF_ZERO.pipe[(int)userData].data_in[8]) | IF_ZERO.pipe[(int)userData].data_in[9] << 8); + if (x != stick_left.x_previous) { + stick_left.x_previous = stick_left.x; + stick_left.x = x; + } + if (y != stick_left.y_previous) { + stick_left.y_previous = stick_left.y; + stick_left.y = y; + } + x = (short)((IF_ZERO.pipe[(int)userData].data_in[10]) | IF_ZERO.pipe[(int)userData].data_in[11] << 8); + y = (short)((IF_ZERO.pipe[(int)userData].data_in[12]) | IF_ZERO.pipe[(int)userData].data_in[13] << 8); + if (x != stick_right.x_previous) { + stick_right.x_previous = stick_right.x; + stick_right.x = x; + } + if (y != stick_right.y_previous) { + stick_right.y_previous = stick_right.y; + stick_right.y = y; + } + } + } + else if(len == 3) { + /* Chatpad return? */ + #ifdef DEBUG_USB_DRIVER_IF_0 + debug_printf("Got %02x %02x %02x \r\n", buf[0], buf[1], buf[2]); + #endif + } + else { + #ifdef DEBUG_USB_DRIVER_IF_0 + DEBUG_UNKNOWN_PACKET_IF_0 + #endif + } + + /* Schedule another transfer to keep the IN flow of data coming. */ + usbeh_api_interrupt_transfer(device, endpoint, IF_ZERO.pipe[(int)userData].data_in, XBOX360_GAMEPAD_PIPE_BUFFER_SIZE, xbox360gamepad_interface_0_in, userData); +} + +void xbox360gamepad_interface_1_in(int device, int endpoint, int status, USBEH_U08 *data, int len, void *userData) { + /* We don't currently do anything with Interface:1 */ + #ifdef DEBUG_USB_DRIVER_IF_1 + DEBUG_UNKNOWN_PACKET_IF_1 + #endif + + /* Schedule another transfer to keep the IN flow of data coming. */ + usbeh_api_interrupt_transfer(device, endpoint, IF_ONE.pipe[(int)userData].data_in, XBOX360_GAMEPAD_PIPE_BUFFER_SIZE, xbox360gamepad_interface_1_in, userData); +} + +void xbox360gamepad_interface_2_in(int device, int endpoint, int status, USBEH_U08 *data, int len, void *userData) { + /* We don't currently do anything with Interface:2 */ + #ifdef DEBUG_USB_DRIVER_IF_2 + DEBUG_UNKNOWN_PACKET_IF_2 + #endif + + /* Schedule another transfer to keep the IN flow of data coming. */ + usbeh_api_interrupt_transfer(device, endpoint, IF_TWO.pipe[(int)userData].data_in, XBOX360_GAMEPAD_PIPE_BUFFER_SIZE, xbox360gamepad_interface_2_in, userData); +} + +int xbox360gamepad_add_interface(int device, USBEH_interfaceDescriptor *iface, USBEH_endpointDescriptor *ed) { + + /* Handle interrupt IN transfers. */ + if ((ed->bmAttributes & 3) != USBEH_ENDPOINT_INTERRUPT) { + return 0; + } + + if (iface->bInterfaceNumber == 0) { + int pipe = 0; + if (ed->bEndpointAddress & 0x80) { + #ifdef DEBUG_USB_DRIVER + DEBUG_USB_MSG_ALLOCATION + #endif + IF_ZERO.pipe[pipe].ep_number_in = ed->bEndpointAddress; + usbeh_api_interrupt_transfer(device, ed->bEndpointAddress, IF_ZERO.pipe[0].data_in, XBOX360_GAMEPAD_PIPE_BUFFER_SIZE, xbox360gamepad_interface_0_in, (void *)pipe); + } + else { + #ifdef DEBUG_USB_DRIVER + DEBUG_USB_MSG_ALLOCATION + #endif + IF_ZERO.pipe[pipe].ep_number_out = ed->bEndpointAddress; + } + } + + if (iface->bInterfaceNumber == 1) { + int pipe = (IF_ONE.pipe[0].ep_number_in == 0) ? 0 : 1; + if (ed->bEndpointAddress & 0x80) { + IF_ONE.pipe[pipe].ep_number_in = ed->bEndpointAddress; + #ifdef DEBUG_USB_DRIVER + DEBUG_USB_MSG_ALLOCATION + #endif + usbeh_api_interrupt_transfer(device, ed->bEndpointAddress, IF_ONE.pipe[pipe].data_in, XBOX360_GAMEPAD_PIPE_BUFFER_SIZE, xbox360gamepad_interface_1_in, (void *)pipe); + } + else { + #ifdef DEBUG_USB_DRIVER + DEBUG_USB_MSG_ALLOCATION + #endif + IF_ONE.pipe[pipe].ep_number_out = ed->bEndpointAddress; + } + } + + + if (iface->bInterfaceNumber == 2) { + int pipe = (IF_TWO.pipe[0].ep_number_in == 0) ? 0 : 1; + if (ed->bEndpointAddress & 0x80) { + IF_TWO.pipe[pipe].ep_number_in = ed->bEndpointAddress; + #ifdef DEBUG_USB_DRIVER + DEBUG_USB_MSG_ALLOCATION + #endif + usbeh_api_interrupt_transfer(device, ed->bEndpointAddress, IF_TWO.pipe[pipe].data_in, XBOX360_GAMEPAD_PIPE_BUFFER_SIZE, xbox360gamepad_interface_2_in, (void *)pipe); + } + else { + #ifdef DEBUG_USB_DRIVER + DEBUG_USB_MSG_ALLOCATION + #endif + IF_TWO.pipe[pipe].ep_number_out = ed->bEndpointAddress; + } + } + + return 1; +} + +static XBOX360_DEVICE * xbox360gamepad_vendor_product_check(uint16_t vendorId, uint16_t productId) { + for (int i = 0; xbox360_devices[i].idVendor != 0; i++) { + if (xbox360_devices[i].idVendor == vendorId && xbox360_devices[i].idProduct == productId) { + return &xbox360_devices[i]; + } + } + return (XBOX360_DEVICE *)NULL; +} + +void xbox360gamepad_led(int code) { + IF_ZERO.pipe[0].data_out[0] = 0x01; + IF_ZERO.pipe[0].data_out[1] = 0x03; + IF_ZERO.pipe[0].data_out[2] = code; + usbeh_api_interrupt_transfer(deviceNumber, IF_ZERO.pipe[0].ep_number_out, IF_ZERO.pipe[0].data_out, 3, NULL, NULL); +} + +USBEH_U08 noise[] = "\x0\x8\x0\x0\x0\x0\x0\x0"; + +void xbox360_noise(int device, int endpoint, int status, USBEH_U08 *data, int len, void *userData) { + usbeh_api_interrupt_transfer(deviceNumber, IF_ZERO.pipe[0].ep_number_out, noise, 8, xbox360_noise, NULL); +} + +int xbox360gamepad_onload_callback(int device, USBEH_deviceDescriptor *deviceDesc, USBEH_interfaceDescriptor **interfaceDesc) { + USBEH_interfaceDescriptor *iface; + int length, endpoint_count, interfaceCounter = 0; + USBEH_U08 *start, *end; + + /* Is this a Microsoft Xbox360 wired Gamepad? */ + XBOX360_DEVICE *xd = xbox360gamepad_vendor_product_check(deviceDesc->idVendor, deviceDesc->idProduct); + if (!xd) { + /* If not, don't claim it. */ + return 0; + } + + #ifdef DEBUG_USB_DRIVER + debug_printf("Found device '%s'\r\n", xd->name); + #endif + + /* Save our device number in a global. */ + deviceNumber = device; + + memset((char *)&IF_VENDOR, 0, sizeof(IF_VENDOR)); + memset((char *)&IF_ZERO, 0, sizeof(IF_ZERO)); + memset((char *)&IF_ONE, 0, sizeof(IF_ONE)); + memset((char *)&IF_TWO, 0, sizeof(IF_TWO)); + + #ifdef DEBUG_USB_DRIVER + debug_printf("%s() ACTIVATED for device id = %d\r\n", __FUNCTION__, device); + debug_printf(" OnLoad VendorId = 0x%04x ProductId = 0x%04x \r\n", deviceDesc->idVendor, deviceDesc->idProduct); + #endif + + /* Parse the interface configuration and setup the endpoint handlers. */ + while ((iface = interfaceDesc[interfaceCounter]) != (USBEH_interfaceDescriptor *)NULL) { + #ifdef DEBUG_USB_DRIVER + debug_printf(" interface%d:- \r\n", interfaceCounter); + debug_printf(" InterfaceClass = %02x \r\n", iface->bInterfaceClass); + debug_printf(" InterfaceSubClass = %02x \r\n", iface->bInterfaceSubClass); + debug_printf(" InterfaceProtocol = %02x \r\n", iface->bInterfaceProtocol); + #endif + start = (USBEH_U08 *)iface; + length = start[0]; + end = start + length; + #ifdef DEBUG_USB_DRIVER + debug_printf(" Scanning at start:%08x length:%d end:%08x \r\n", start, length, end); + #endif + while (start < end) { + if (start[1] == USBEH_DESCRIPTOR_TYPE_INTERFACE) { + USBEH_interfaceDescriptor *id = (USBEH_interfaceDescriptor *)start; + //int interfaceNumber = (int)id->bInterfaceNumber; + endpoint_count = (int)id->bNumEndpoints; + #ifdef DEBUG_USB_DRIVER + debug_printf(" found definition for if:%d with %d endpoints.\r\n", interfaceNumber, endpoint_count); + #endif + start += start[0]; + while (endpoint_count > 0) { + if (start[1] == USBEH_DESCRIPTOR_TYPE_ENDPOINT) { + USBEH_endpointDescriptor *ed = (USBEH_endpointDescriptor *)start; + #ifdef DEBUG_USB_DRIVER + debug_printf(" found endpoint 0x%02X\r\n", ed->bEndpointAddress); + #endif + xbox360gamepad_add_interface(device, id, ed); + endpoint_count--; + } + else { + #ifdef DEBUG_USB_DRIVER + debug_printf(" no endpoint for interface, descriptor class: %02X\r\n", start[1]); + #endif + } + start += start[0]; + } + } + else { + #ifdef DEBUG_USB_DRIVER + debug_printf(" no IF descr found at %08x\r\n", start); + #endif + start += start[0]; + } + } + + interfaceCounter++; + } + + #ifdef DEBUG_USB_DRIVER + debug_printf("Device claimed by %s().\r\n\n", __FUNCTION__); + #endif + + /* When the gamepad boots up, the LED ring flashes after it's + configuration is set. Let's flash the led and go steady. */ + xbox360gamepad_led(LED_1_FLASH_THEN_ON); + + /* Lets just send "noise" to the headset and see what happens. */ + //usbeh_api_interrupt_transfer(deviceNumber, IF_ZERO.pipe[0].ep_number_out, noise, 8, xbox360_noise, NULL); + + /* I give up, wtf is it with this chatpad that MS needs to keep so secret? */ + //xbox360_chatpad_init(); + + /* Tell the USB embedded host that we have claimed this device. */ + return 1; +} + +#ifdef NEVERCOMPILETHISCODE +/* + +UPDATE: Everything below is ABANDONED when I basically figured out from one replay to the next +that MS use the security channel to "handshake" init the chatpad. Many people believe +the security device in the gamepad is to "tell the xbox I am a real auth MS gamepad". However, +as I have discovered, it's "two-way". There also exists the "tell the gamepad that an auth +Xbox360 is the host" and without that the chatpad will not function. I have no interest in +trying to crack anyones security chips so no further work will be done on this. + +Everything below here is related to the chatpad attachment for the Xbox360 gamepad controller. +Unlike the sticks, triggers and buttons, the chatpad appears to require some sort of initialization +in order to start running. Since MS have not published any sort of USB protocol specifications +for their gamepad, what we do here is basically a "replay attack" based on packets sent and received +between an Xbox and a gamepad with a USB protocol analyser in the middle. A classic man-in-the-middle +type of attack. + +Here's the basic sequence we attempt to follow:- + + 1. -> Vendor request IN EP0 (0x01) + -> SETUP C0 01 00 00 00 00 04 00 + <- IN 80 03 0D 47 + 2. -> Vendor request OUT EP0 (0xA9) + -> 40 A9 0C A3 23 44 00 + <- Expect STALLED no data + 3. -> Vendor request OUT EP0 (0xA9) + -> 40 A9 44 23 03 7F 00 00 + <- Expect STALLED no data + 4. -> Vendor request OUT EP0 (0xA9) + -> 40 A9 39 58 32 68 00 00 + <- Expect STALLED no data + 5. <- IN IF:0 EP2 3 bytes 01 03 0E + 6. -> Vendor request IN EP0 (0xA1) + -> SETUP C0 A1 00 00 16 E4 02 00 + <- IN 01 00 + 7. -> OUT IF:0 EP1 3 bytes 01 03 01 + 8. -> Vendor request OUT EP0 (0xA1) + -> SETUP 40 A1 00 00 16 E4 02 00 + -> OUT 09 00 + 9. -> Vendor request IN EP0 (0xA1) + -> SETUP C0 A1 00 00 16 E4 02 00 + -> IN 09 00 (echo previous OUT?) +10. <- IN IF:0 EP 1 3 bytes 02 03 00 +11. <- IN IF:0 EP 1 3 bytes 03 03 03 +12. <- IN IF:0 EP 1 3 bytes 08 03 00 +13. <- IN IF:0 EP 1 3 bytes 01 03 01 +14. -> Vendor request OUT EP0 (0x00) + -> SETUP 41 00 1F 00 02 00 00 00 + -> IN No data +15. -> Vendor request OUT EP0 (0x00) + -> SETUP 41 00 1E 00 02 00 00 00 + -> IN No data + +Note that 14. and 15. are 1second apart and repeat continuely +toggling between 1F and 1E each second. + +16. <- IN IF:2 EP4 (IF:2 PIPE1) 5 bytes F0 03 00 01 01 +17. -> Vendor request OUT EP0 (0x00) + -> SETUP 41 00 1B 00 02 00 00 00 + -> IN No data +18. <- IN IF:2 EP4 (IF:2 PIPE1) 5 bytes F0 03 00 01 01 +19. -> Vendor request OUT EP0 (0x00) + -> SETUP 41 00 1B 00 02 00 00 00 + -> IN No data + + +After this we start receiving data from IF:2 PIPE1 + +*/ +USBEH_U08 chatpad_trash_buffer[256]; +USBEH_U08 chatpad_toggle; +USBEH_U08 chatpad_send_toggle; +USBEH_U08 chatpad_toggle_1Bsent; +USBEH_SOF_COUNTER chatpad_toggle_timer; + +void xbox360_chatpad_toggle(int device, int endpoint, int status, USBEH_U08 *data, int len, void *userData) { + int result = usbeh_api_control_transfer(deviceNumber, + USBEH_HOST_TO_DEVICE | USBEH_SETUP_TYPE_MASK_VENDOR | USBEH_RECIPIENT_INTERFACE, + 0x00, + (int)userData, + 0x0002, + chatpad_trash_buffer, + 0, + xbox360_chatpad_toggle, + (userData == (void *)0x1E) ? (void *)0x001F : (void *)0x001E); + //debug.printf("TOGGLE = 0x%x\r\n", -result & 0xf); +} + +void xbox360_chatpad_timed_toggle(USBEH_SOF_COUNTER *q) { + int result; + + debug_printf("%s() called.\r\n", __FUNCTION__); + + result = usbeh_api_control_transfer(deviceNumber, + USBEH_HOST_TO_DEVICE | USBEH_SETUP_TYPE_MASK_VENDOR | USBEH_RECIPIENT_INTERFACE, + 0x00, + (int)q->userData == 0x1F ? 0x001F : 0x001E, + 0x0002, + chatpad_trash_buffer, + 0, + 0, 0); + + debug_printf("repeat! 1F/E = 0x%x\r\n", -result & 0xf); + + if (1 && !chatpad_toggle_1Bsent) { + chatpad_toggle_1Bsent = 1; + + result = usbeh_api_control_transfer(deviceNumber, + USBEH_HOST_TO_DEVICE | USBEH_SETUP_TYPE_MASK_VENDOR | USBEH_RECIPIENT_INTERFACE, + 0x00, + 0x001B, + 0x0002, + chatpad_trash_buffer, + 0, + 0, 0); + } + + debug_printf("repeat! 1B = 0x%x\r\n", -result & 0xf); + + //usbeh_sof_counter_unregister(&chatpad_toggle_timer); + //usbeh_sof_counter_init(&chatpad_toggle_timer, USBEH_SOF_COUNTER_DEC | USBEH_SOF_COUNTER_RELOAD, 1700); + //chatpad_toggle_timer.userData = (int)q->userData == 0x1F ? 0x001F : 0x001E; + //chatpad_toggle_timer.callback = xbox360_chatpad_timed; + //chatpad_toggle_timer.flag = 0; + //usbeh_sof_counter_register(&chatpad_toggle_timer); + + +} + +void xbox360_chatpad_init(void) { + int result; + USBEH_U08 buffer[256]; + USBEH_U08 data[256]; + + // int usbeh_api_control_transfer(int device, + // int request_type, + // int request, + // int value, + // int index, + // USBEH_U08 *data, + // int length, + // USBEH_callback callback, void *userData) { + // int r = usbeh_api_control_transfer(device, USBEH_DEVICE_TO_HOST | USBEH_REQUEST_TYPE_CLASS | USBEH_RECIPIENT_DEVICE, USBEH_GET_DESCRIPTOR, (USBEH_DESCRIPTOR_TYPE_HUB << 8), 0, buffer, sizeof(buffer), 0, 0); + + result = usbeh_api_control_transfer(deviceNumber, + USBEH_DEVICE_TO_HOST | USBEH_SETUP_TYPE_MASK_VENDOR | USBEH_RECIPIENT_DEVICE, + 0x01, + 0x0000, + 0x0000, + buffer, + 4, + 0, 0); + debug_printf("Step 1 = 0x%x %02x %02x %02x %02x \r\n", result, buffer[0], buffer[1], buffer[2], buffer[3]); + + result = usbeh_api_control_transfer(deviceNumber, + USBEH_HOST_TO_DEVICE | USBEH_SETUP_TYPE_MASK_VENDOR | USBEH_RECIPIENT_DEVICE, + 0xA9, + 0xA30C, + 0x4423, + buffer, + 0, + 0, 0); + debug_printf("Step 2 = 0x%x %02x %02x %02x %02x \r\n", result, buffer[0], buffer[1], buffer[2], buffer[3]); + + result = usbeh_api_control_transfer(deviceNumber, + USBEH_HOST_TO_DEVICE | USBEH_SETUP_TYPE_MASK_VENDOR | USBEH_RECIPIENT_DEVICE, + 0xA9, + 0x2344, + 0x7F03, + buffer, + 0, + 0, 0); + debug_printf("Step 3 = 0x%x %02x %02x %02x %02x \r\n", result, buffer[0], buffer[1], buffer[2], buffer[3]); + + result = usbeh_api_control_transfer(deviceNumber, + USBEH_HOST_TO_DEVICE | USBEH_SETUP_TYPE_MASK_VENDOR | USBEH_RECIPIENT_DEVICE, + 0xA9, + 0x5839, + 0x6832, + buffer, + 0, + 0, 0); + debug_printf("Step 4 = 0x%x %02x %02x %02x %02x \r\n", result, buffer[0], buffer[1], buffer[2], buffer[3]); + + result = usbeh_api_control_transfer(deviceNumber, + USBEH_DEVICE_TO_HOST | USBEH_SETUP_TYPE_MASK_VENDOR | USBEH_RECIPIENT_DEVICE, + 0xA1, + 0x0000, + 0xE416, + buffer, + 2, + 0, 0); + debug_printf("Step 5 = 0x%x %02x %02x %02x %02x \r\n", result, buffer[0], buffer[1], buffer[2], buffer[3]); + + data[0] = 9; data[1] = 0; + result = usbeh_api_control_transfer(deviceNumber, + USBEH_HOST_TO_DEVICE | USBEH_SETUP_TYPE_MASK_VENDOR | USBEH_RECIPIENT_DEVICE, + 0xA1, + 0x5839, + 0xE416, + data, + 2, + 0, 0); + debug_printf("Step 6 = 0x%x %02x %02x %02x %02x \r\n", result, buffer[0], buffer[1], buffer[2], buffer[3]); + + result = usbeh_api_control_transfer(deviceNumber, + USBEH_DEVICE_TO_HOST | USBEH_SETUP_TYPE_MASK_VENDOR | USBEH_RECIPIENT_DEVICE, + 0xA1, + 0x0000, + 0xE416, + buffer, + 2, + 0, 0); + debug_printf("Step 7 = 0x%x %02x %02x %02x %02x \r\n", result, buffer[0], buffer[1], buffer[2], buffer[3]); + + // Now begin toggling 1F / 1E + chatpad_toggle = 0x1E; + result = usbeh_api_control_transfer(deviceNumber, + USBEH_HOST_TO_DEVICE | USBEH_SETUP_TYPE_MASK_VENDOR | USBEH_RECIPIENT_INTERFACE, + 0x00, + 0x001F, + 0x0002, + chatpad_trash_buffer, + 0, + xbox360_chatpad_toggle, + (void *)0x1E); + debug_printf("Step 8 TOGGLE = 0x%x %02x %02x %02x %02x \r\n", result, buffer[0], buffer[1], buffer[2], buffer[3]); + + result = usbeh_api_control_transfer(deviceNumber, + USBEH_HOST_TO_DEVICE | USBEH_SETUP_TYPE_MASK_VENDOR | USBEH_RECIPIENT_INTERFACE, + 0x00, + 0x0003, + 0x0002, + chatpad_trash_buffer, + 0, + 0, + 0); + debug_printf("Step 9 OUT 0x03 = 0x%x %02x %02x %02x %02x \r\n", result, buffer[0], buffer[1], buffer[2], buffer[3]); + + //usbeh_sof_counter_init(&chatpad_toggle_timer, USBEH_SOF_COUNTER_DEC | USBEH_SOF_COUNTER_RELOAD, 1700); + //chatpad_toggle_timer.userData = (int)chatpad_toggle; + //chatpad_toggle_timer.callback = xbox360_chatpad_timed; + //usbeh_sof_counter_register(&chatpad_toggle_timer); + +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbeh/xbox360gamepad.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,139 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef XBOX360GAMEPAD_H +#define XBOX360GAMEPAD_H + +#include "usbeh_api.h" + +#define BUTTON_PRESSED 1 +#define BUTTON_RELEASED 0 + +#define BUTTON_HOLD_TIME 3000 + +#define BUTT_LS_PRESS 1 +#define BUTT_RS_PRESS 2 +#define BUTT_XBOX_PRESS 3 +#define BUTT_UNUSED_PRESS 4 +#define BUTT_A_PRESS 5 +#define BUTT_B_PRESS 6 +#define BUTT_X_PRESS 7 +#define BUTT_Y_PRESS 8 +#define BUTT_DPAD_UP_PRESS 9 +#define BUTT_DPAD_DOWN_PRESS 10 +#define BUTT_DPAD_LEFT_PRESS 11 +#define BUTT_DPAD_RIGHT_PRESS 12 +#define BUTT_START_PRESS 13 +#define BUTT_BACK_PRESS 14 +#define BUTT_LEFT_HAT_PRESS 15 +#define BUTT_RIGHT_HAT_PRESS 16 + +#define BUTT_LS_RELEASE (BUTT_LS_PRESS + 16) +#define BUTT_RS_RELEASE (BUTT_RS_PRESS + 16) +#define BUTT_XBOX_RELEASE (BUTT_XBOX_PRESS + 16) +#define BUTT_UNUSED_RELEASE (BUTT_UNUSED_PRESS + 16) +#define BUTT_A_RELEASE (BUTT_A_PRESS + 16) +#define BUTT_B_RELEASE (BUTT_B_PRESS + 16) +#define BUTT_X_RELEASE (BUTT_X_PRESS + 16) +#define BUTT_Y_RELEASE (BUTT_Y_PRESS + 16) +#define BUTT_DPAD_UP_RELEASE (BUTT_DPAD_UP_PRESS + 16) +#define BUTT_DPAD_DOWN_RELEASE (BUTT_DPAD_DOWN_PRESS + 16) +#define BUTT_DPAD_LEFT_RELEASE (BUTT_DPAD_LEFT_PRESS + 16) +#define BUTT_DPAD_RIGHT_RELEASE (BUTT_DPAD_RIGHT_PRESS + 16) +#define BUTT_START_RELEASE (BUTT_START_PRESS + 16) +#define BUTT_BACK_RELEASE (BUTT_BACK_PRESS + 16) +#define BUTT_LEFT_HAT_RELEASE (BUTT_LEFT_HAT_PRESS + 16) +#define BUTT_RIGHT_HAT_RELEASE (BUTT_RIGHT_HAT_PRESS + 16) + +#define BUTT_LS_HOLD (BUTT_LS_PRESS + 32) +#define BUTT_RS_HOLD (BUTT_RS_PRESS + 32) +#define BUTT_XBOX_HOLD (BUTT_XBOX_PRESS + 32) +#define BUTT_UNUSED_HOLD (BUTT_UNUSED_PRESS + 32) +#define BUTT_A_HOLD (BUTT_A_PRESS + 32) +#define BUTT_B_HOLD (BUTT_B_PRESS + 32) +#define BUTT_X_HOLD (BUTT_X_PRESS + 32) +#define BUTT_Y_HOLD (BUTT_Y_PRESS + 32) +#define BUTT_DPAD_UP_HOLD (BUTT_DPAD_UP_PRESS + 32) +#define BUTT_DPAD_DOWN_HOLD (BUTT_DPAD_DOWN_PRESS + 32) +#define BUTT_DPAD_LEFT_HOLD (BUTT_DPAD_LEFT_PRESS + 32) +#define BUTT_DPAD_RIGHT_HOLD (BUTT_DPAD_RIGHT_PRESS + 32) +#define BUTT_START_HOLD (BUTT_START_PRESS + 32) +#define BUTT_BACK_HOLD (BUTT_BACK_PRESS + 32) +#define BUTT_LEFT_HAT_HOLD (BUTT_LEFT_HAT_PRESS + 32) +#define BUTT_RIGHT_HAT_HOLD (BUTT_RIGHT_HAT_PRESS + 32) + +#define LED_ALL_OFF 0x00 +#define LED_ALL_BLINKING 0x01 +#define LED_1_FLASH_THEN_ON 0x02 +#define LED_2_FLASH_THEN_ON 0x03 +#define LED_3_FLASH_THEN_ON 0x04 +#define LED_4_FLASH_THEN_ON 0x05 +#define LED_1_ON 0x06 +#define LED_2_ON 0x07 +#define LED_3_ON 0x08 +#define LED_4_ON 0x09 +#define LED_ROTATING 0x0A +#define LED_BLINKING 0x0B +#define LED_SLOW_BLINKING 0x0C +#define LED_ALTERNATING 0x0D + +typedef struct { + uint16_t idVendor; + uint16_t idProduct; + const char* name; +} XBOX360_DEVICE; + +typedef struct { + unsigned state; + unsigned mask; + unsigned count; + USBEH_SOF_COUNTER pressHold; +} XBOX360_BUTTON; + +typedef struct { + short x; + short y; + short x_previous; + short y_previous; +} XBOX360_STICK; + +/* API functions. */ +char xbox360gamepad_get_button(void); +char xbox360gamepad_get_button_preview(void); +unsigned char xbox360gamepad_get_trigger_left(void); +unsigned char xbox360gamepad_get_trigger_right(void); +void xbox360gamepad_led(int code); +XBOX360_STICK * xbox360gamepad_get_stick_left(void); +XBOX360_STICK * xbox360gamepad_get_stick_right(void); + +int xbox360gamepad_init(void); +void xbox360gamepad_process(void); + +/* Button press and hold callback function. */ +void xbox360gamepad_button_hold_callback(USBEH_SOF_COUNTER *q); + +/* Onload callback function. */ +int xbox360gamepad_onload_callback(int device, USBEH_deviceDescriptor *deviceDesc, USBEH_interfaceDescriptor **interfaceDesc); + +void xbox360_chatpad_init(void); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/user.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,214 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#include "rit.h" +#include "gpio.h" +#include "user.h" +#include "nexstar.h" +#include "xbox360gamepad.h" +#include "debug.h" + +#define STICK_DIVISOR 4096.0 + +void handle_stick_left(void); +void handle_stick_right(void); + +typedef void (PROCESS_FUNC)(); + +extern PROCESS_FUNC *process_callbacks[]; + +USER_INPUT user_input; + +/** user_get_button + * + * Used to get a "button press" from the user. This is basically + * a read of the XBox360 gamepad interface via the USBEH system. + * However, this function is provided to abstract that so that + * other systems can "inject" button presses into the system. + * The intention here is for a virtual console on a PC to + * control the SOWB system via the (to be done) pccomms.c module. + * This is just a conveinent way to get user IO into the SOWB. + * + * Note, this fnction calls all the module _process() functions + * in it's loop (ie while no user IO is occuring). That gives the + * SOWB modules a chance to get work done outside of time critical + * interrupts. _process() functions should NEVER block and should + * also be "fast" so as to avoid any user IO perseptive delay. + * + * Note, if arg peek is true, we return the next button press in + * the buffer without actually removing that event from the buffer. + * Allows us to look to see if an pending button press is within + * the buffer awaiting being handled. + * + * @param bool peek + * @return char The button pressed. + */ +char user_get_button(bool peek) { + char c; + + if (peek) { + /* Make a call to all _process()'s just in case we find + ourselves stuck in a tight loop waiting for an event. */ + for (c = 0; process_callbacks[c] != NULL; c++) (process_callbacks[c])(); + return xbox360gamepad_get_button_preview(); + } + + do { + /* Call all module _process functions. */ + for (c = 0; process_callbacks[c] != NULL; c++) { + KICK_WATCHDOG; + (process_callbacks[c])(); + } + + handle_stick_left(); + handle_stick_right(); + + /* Get a button press from the user or go round again. */ + c = xbox360gamepad_get_button(); + } + while (c == 0); + + return c; +} + +/* A flag to signify a timeout has occured. */ +volatile int user_wait_ms_flag; + +/** _user_wait_ms_cb + * + * Called by the RIT system to signal a timer timeout. + * + * @param int t_index The timer index value (handle). + */ +void _user_wait_ms_cb(int t_index) { + user_wait_ms_flag = 0; +} + +/** user_wait_ms + * + * Used to "wait" for a specified time interval. + * Note, while "waiting" for the timeout, it will + * call all the modules _process() functions to + * allow modules to perform non-time critical work + * outside of interrupts. + * + * @param uint32_t ms The delay amount. + */ +void user_wait_ms(uint32_t ms) { + rit_timer_set_counter(RIT_TIMER_CB_WAIT, ms); + user_wait_ms_flag = 1; + while (user_wait_ms_flag) + for (int c = 0; process_callbacks[c] != NULL; c++) { + KICK_WATCHDOG; + (process_callbacks[c])(); + } +} + +/** user_wait_ms + * + * Used to "wait" for a specified time interval. + * Note, unlike the function above, NO _process() + * functions are called. This really is a blocking + * delay and should be used with care! + * + * @param uint32_t ms The delay amount. + */ +void user_wait_ms_blocking(uint32_t ms) { + rit_timer_set_counter(RIT_TIMER_CB_WAIT, ms); + user_wait_ms_flag = 1; + while (user_wait_ms_flag) KICK_WATCHDOG; +} + +/** user_call_process + */ +void user_call_process(void) { + for (int c = 0; process_callbacks[c] != NULL; c++) { + KICK_WATCHDOG; + (process_callbacks[c])(); + } +} + +void handle_stick_left(void) { + static XBOX360_STICK stick_left_previous; + XBOX360_STICK *stick; + int x, y; + double rate; + + stick = xbox360gamepad_get_stick_left(); + if (stick->x/STICK_DIVISOR != stick_left_previous.x/STICK_DIVISOR || stick->y/STICK_DIVISOR != stick_left_previous.y/STICK_DIVISOR) { + stick_left_previous.x = stick->x; + stick_left_previous.y = stick->y; + x = stick->x/STICK_DIVISOR; + y = stick->y/STICK_DIVISOR; + + if (x > 2 || x < -2) { + rate = 6.0 * (double)((double)stick->x/STICK_DIVISOR / 16.0); + _nexstar_set_azmith_rate_coarse(rate); + } + else { + _nexstar_set_azmith_rate_coarse(0.0); + } + + if (y > 2 || y < -2) { + rate = 6.0 * (double)((double)stick->y/STICK_DIVISOR / 16.0); + _nexstar_set_elevation_rate_coarse(rate); + } + else { + _nexstar_set_elevation_rate_coarse(0.0); + } + } +} + +void handle_stick_right(void) { + static XBOX360_STICK stick_previous; + XBOX360_STICK *stick; + int x, y; + double rate; + + stick = xbox360gamepad_get_stick_right(); + if (stick->x/STICK_DIVISOR != stick_previous.x/STICK_DIVISOR || stick->y/STICK_DIVISOR != stick_previous.y/STICK_DIVISOR) { + stick_previous.x = stick->x; + stick_previous.y = stick->y; + x = stick->x/STICK_DIVISOR; + y = stick->y/STICK_DIVISOR; + + if (x > 2 || x < -2) { + //debug_printf("New RIGHT stick position x = %d y = %d\r\n", stick->x/STICK_DIVISOR, stick->y/STICK_DIVISOR); + rate = 0.4 * (double)((double)stick->x/STICK_DIVISOR / 16.0); + _nexstar_set_azmith_rate_fine(rate); + } + else { + _nexstar_set_azmith_rate_fine(0.0); + } + + if (y > 2 || y < -2) { + rate = 0.4 * (double)((double)stick->y/STICK_DIVISOR / 16.0); + _nexstar_set_elevation_rate_fine(rate); + } + else { + _nexstar_set_elevation_rate_fine(0.0); + } + } +} + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/user.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,46 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef USER_H +#define USER_H + +#include "xbox360gamepad.h" + +#define WHILE_WAITING_DO_PROCESS_FUNCTIONS user_call_process(); + +#define KICK_WATCHDOG { LPC_WDT->WDFEED = 0xAA; LPC_WDT->WDFEED = 0x55; } + +typedef struct _user_input { + char xbox_button; + unsigned char trigger_left; + unsigned char trigger_right; + XBOX360_STICK * stick_left; + XBOX360_STICK * stick_right; +} USER_INPUT; + + +char user_get_button(bool peek); +void user_wait_ms(uint32_t ms); +void user_wait_ms_blocking(uint32_t ms); +void user_call_process(void); + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utils/star.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,2358 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#include "sowb.h" +#include "debug.h" +#include "satapi.h" +#include "star.h" + + +basicStarData * star_closest(RaDec *radec, basicStarData *star) { + const basicStarData *bright_star; + float raHigh, raLow, decHigh, decLow; + char test_buffer[64]; + int i = 0, once = 0; + + raHigh = radec->ra + 5.0; + if (raHigh >= 360.0) raHigh -= 360.0; + raLow = radec->ra - 5.0; + if (raLow <= 0.0) raHigh += 360.0; + decHigh = radec->dec + 5.0; + if (decHigh >= 90.0) 90.0 - decHigh; + decLow = radec->dec - 5.0; + if (decLow <= -90.0) 90.0 + decLow; + + do { + bright_star = get_bright_star(i); + if (bright_star->ra < raHigh && bright_star->ra > raLow) { + if (bright_star->dec < decHigh && bright_star->dec > decLow) { + sprintf(test_buffer, "%d Candidate HR %d %f %f %f\r\n", once, bright_star->hr, bright_star->ra, bright_star->dec, bright_star->mag); + if (once == 0) { + once++; + memcpy(star, bright_star, sizeof(basicStarData)); + sprintf(test_buffer, "%d HR %d %f %f %f\r\n", once, star->hr, star->ra, star->dec, star->mag); + debug_printf(test_buffer); + } + else { + if (bright_star->mag < star->mag) { + once++; + memcpy(star, bright_star, sizeof(basicStarData)); + sprintf(test_buffer, "%d HR %d %f %f %f\r\n", once, star->hr, star->ra, star->dec, star->mag); + debug_printf(test_buffer); + } + } + } + } + i++; + } + while(bright_star->hr != 0); + + if (!once) return (basicStarData *)NULL; + return star; +} + + +const basicStarData brightstars[] = { + { 1, 1.2913, +45.2292, 6.70 }, { 2, 1.2658, +0.5031, 6.29 }, { 3, 1.3338, -4.2925, 4.61 }, { 4, 1.4250, +13.3961, 5.51 }, + { 5, 1.5667, +58.4367, 5.96 }, { 6, 1.5792, -48.9250, 5.70 }, { 7, 1.6104, +64.1961, 5.59 }, { 8, 1.6533, +29.0214, 6.13 }, + { 9, 1.7088, -22.8925, 6.18 }, { 10, 1.8258, -16.6136, 6.19 }, { 11, 1.9338, -1.4511, 6.43 }, { 12, 1.9450, -21.4911, 5.94 }, + { 13, 2.0146, -32.4706, 5.68 }, { 14, 2.0504, -1.5522, 6.07 }, { 15, 2.0971, +29.0906, 2.06 }, { 16, 2.0725, -7.1761, 5.99 }, + { 17, 2.1708, +36.6267, 6.19 }, { 18, 2.1392, -16.4225, 6.06 }, { 19, 2.2175, +25.4628, 6.23 }, { 20, 2.3342, +79.7147, 6.01 }, + { 21, 2.2946, +59.1497, 2.27 }, { 22, 2.2600, +18.2119, 5.53 }, { 23, 2.2600, -53.9981, 6.33 }, { 24, 2.3375, -26.0122, 5.42 }, + { 25, 2.3529, -44.2525, 3.88 }, { 26, 2.5096, +11.1456, 5.51 }, { 27, 2.5804, +46.0722, 5.03 }, { 28, 2.6237, +57.1656, 6.74 }, + { 29, 2.5783, -4.7514, 5.84 }, { 30, 2.5088, -81.7761, 5.28 }, { 31, 2.6783, -11.4200, 5.85 }, { 32, 2.6608, -72.7756, 6.64 }, + { 33, 2.8163, -14.5319, 4.89 }, { 34, 2.8933, -26.2003, 5.41 }, { 35, 2.9333, -34.8669, 5.25 }, { 36, 2.9962, +48.1525, 6.16 }, + { 37, 3.0417, -16.0617, 5.25 }, { 38, 3.2100, +37.6933, 6.73 }, { 39, 3.3092, +15.1836, 2.83 }, { 40, 3.3500, +26.9872, 6.30 }, + { 41, 3.3783, +41.0353, 5.72 }, { 42, 3.4254, -25.9781, 5.94 }, { 43, 3.4342, -25.7153, 6.31 }, { 44, 3.5096, +33.2061, 6.25 }, + { 45, 3.6508, +20.2067, 4.80 }, { 46, 3.6150, -6.2194, 5.12 }, { 47, 3.3308, -83.0058, 5.77 }, { 48, 3.6600, -17.0672, 4.44 }, + { 49, 3.7338, +22.2842, 6.24 }, { 50, 3.7450, +8.8208, 5.79 }, { 51, 3.7271, -8.4303, 5.75 }, { 52, 3.7792, +31.5358, 6.45 }, + { 53, 3.7942, +27.2831, 6.35 }, { 54, 3.7425, -33.0956, 6.17 }, { 55, 4.0583, +76.9508, 6.35 }, { 56, 4.0900, +43.5947, 6.15 }, + { 57, 4.0371, -30.5536, 5.67 }, { 58, 3.9800, -74.0886, 6.49 }, { 59, 4.1421, +8.2400, 6.11 }, { 60, 4.2379, +61.5333, 5.74 }, + { 61, 4.1771, -19.7894, 6.47 }, { 62, 4.2879, +47.9475, 5.89 }, { 63, 4.2729, +38.6817, 4.61 }, { 64, 4.2042, -77.2194, 6.77 }, + { 65, 4.4292, +51.4331, 6.14 }, { 66, 4.3858, -18.9489, 6.45 }, { 67, 4.4488, +1.6889, 6.17 }, { 68, 4.5821, +36.7853, 4.52 }, + { 69, 4.5717, +11.2058, 6.05 }, { 70, 4.6754, +43.7911, 6.11 }, { 71, 4.6596, +31.5172, 5.87 }, { 72, 4.6742, -7.9472, 6.46 }, + { 73, 4.6775, -42.7647, 6.33 }, { 74, 4.8571, -7.1761, 3.56 }, { 75, 4.9233, +40.7297, 6.33 }, { 76, 5.0217, +48.8653, 6.52 }, + { 77, 5.0179, -63.1253, 4.23 }, { 78, 5.1017, +30.9358, 5.90 }, { 79, 5.1896, +32.9114, 5.79 }, { 80, 5.1496, +8.1903, 5.37 }, + { 81, 5.2271, +10.9769, 6.56 }, { 82, 5.2804, +37.9686, 5.18 }, { 83, 5.1625, -68.3750, 5.51 }, { 84, 5.3800, -27.0183, 5.18 }, + { 85, 5.4429, -19.9422, 5.12 }, { 86, 5.6063, +13.4825, 6.23 }, { 87, 5.3692, -76.5731, 5.97 }, { 88, 5.7158, -11.7906, 6.39 }, + { 89, 5.8025, -30.9639, 6.55 }, { 90, 6.0083, +38.5772, 7.39 }, { 91, 6.0650, +52.0200, 5.57 }, { 92, 0.0000, +0.0000, 0.00 }, + { 93, 6.1979, +61.8311, 5.40 }, { 94, 6.1238, -1.7808, 6.07 }, { 95, 0.0000, +0.0000, 0.00 }, { 96, 6.2767, +53.0469, 5.74 }, + { 97, 6.3508, +1.9397, 5.77 }, { 98, 6.4379, -76.7458, 2.80 }, { 99, 6.5708, -41.6939, 2.39 }, { 100, 6.5508, -42.3200, 3.94 }, + { 101, 6.6558, +0.0497, 6.19 }, { 102, 6.8113, -24.4528, 5.98 }, { 103, 7.0121, +17.8931, 5.06 }, { 104, 7.0571, +44.3944, 5.17 }, + { 105, 6.9821, -32.9928, 4.81 }, { 106, 7.0529, +16.4450, 6.06 }, { 107, 7.0838, +10.1897, 6.04 }, { 108, 7.0879, -19.6650, 6.43 }, + { 109, 7.1100, -38.0850, 5.43 }, { 110, 7.2358, +36.9000, 6.26 }, { 111, 7.1796, -49.4672, 6.26 }, { 112, 7.7292, +77.0194, 6.21 }, + { 113, 7.5829, +59.9772, 5.94 }, { 114, 7.5304, +29.7517, 5.23 }, { 115, 7.4662, -13.1358, 6.14 }, { 116, 7.4538, -31.8833, 6.57 }, + { 117, 7.5100, -2.0428, 5.72 }, { 118, 7.5946, -22.2122, 5.19 }, { 119, 7.6158, -39.0606, 6.19 }, { 120, 7.6087, -47.7850, 5.69 }, + { 121, 7.8554, +66.5194, 6.18 }, { 122, 7.8567, +33.5817, 5.87 }, { 123, 7.9433, +54.5222, 4.73 }, { 124, 7.9217, +52.8394, 5.60 }, + { 125, 7.8542, -47.1964, 4.77 }, { 126, 7.8863, -61.0419, 4.37 }, { 127, 7.8900, -61.0342, 4.54 }, { 128, 8.1117, +43.4947, 6.70 }, + { 129, 8.3304, +70.9817, 6.42 }, { 130, 8.2500, +62.9317, 4.16 }, { 131, 8.1479, +20.2944, 5.38 }, { 132, 8.0992, +6.9556, 5.67 }, + { 133, 8.1438, +27.5806, 6.67 }, { 134, 8.2046, +28.2803, 6.30 }, { 135, 8.2933, +54.8950, 5.93 }, { 136, 8.1825, -62.9689, 5.09 }, + { 137, 8.6037, +66.7503, 6.48 }, { 138, 8.4213, -28.4417, 5.55 }, { 139, 8.3471, -70.7339, 6.13 }, { 140, 8.6158, -51.6269, 5.57 }, + { 141, 8.7304, +13.3711, 6.40 }, { 142, 8.8121, -2.4072, 5.20 }, { 143, 8.8867, +0.5056, 5.93 }, { 144, 9.0346, +54.1686, 5.08 }, + { 145, 8.9779, +13.2067, 6.41 }, { 146, 9.1137, +60.3261, 5.79 }, { 147, 8.9213, -47.9992, 5.51 }, { 148, 8.8892, -53.1781, 6.06 }, + { 149, 9.0833, +27.2547, 6.50 }, { 150, 9.0125, -13.0264, 6.45 }, { 151, 9.0288, -21.1575, 6.06 }, { 152, 9.1942, +44.4886, 5.13 }, + { 153, 9.2429, +53.8969, 3.66 }, { 154, 9.2204, +33.7194, 4.36 }, { 155, 9.1971, +15.2317, 5.89 }, { 156, 9.2800, +24.0142, 6.47 }, + { 157, 9.3379, +35.3994, 5.48 }, { 158, 9.9471, +82.4939, 6.40 }, { 159, 9.3362, -23.2328, 5.57 }, { 160, 9.1558, -64.8753, 6.42 }, + { 161, 9.3771, +3.1353, 6.39 }, { 162, 9.3254, -53.6058, 6.41 }, { 163, 9.6387, +29.3117, 4.37 }, { 164, 9.7912, +49.3544, 5.43 }, + { 165, 9.8321, +30.8608, 3.27 }, { 166, 9.8408, +21.2506, 5.87 }, { 167, 9.9817, +21.4383, 5.36 }, { 168, 10.1271, +56.5372, 2.23 }, + { 169, 9.6700, -72.8628, 6.85 }, { 170, 9.9913, -32.0383, 6.69 }, { 171, 9.9667, -43.2033, 6.01 }, { 172, 10.1192, -15.4831, 6.49 }, + { 173, 10.1371, -22.1956, 6.14 }, { 174, 10.1767, -3.6481, 5.91 }, { 175, 10.2800, +39.4586, 5.33 }, { 176, 10.1100, -58.5456, 5.89 }, + { 177, 10.5142, +66.1475, 5.83 }, { 178, 10.4000, +24.6292, 6.04 }, { 179, 10.5162, +50.5125, 4.80 }, { 180, 10.3317, -45.9150, 4.59 }, + { 181, 10.6296, +58.7533, 6.17 }, { 182, 0.0000, +0.0000, 0.00 }, { 183, 10.4433, -55.4983, 5.70 }, { 184, 10.8671, +47.0247, 4.94 }, + { 185, 10.6788, -37.5367, 6.06 }, { 186, 10.6742, -59.7375, 5.98 }, { 187, 10.6183, -64.5319, 5.39 }, { 188, 10.8975, -16.0133, 2.04 }, + { 189, 11.1100, +47.8642, 5.67 }, { 190, 10.9592, -11.9883, 6.02 }, { 191, 10.8383, -56.5369, 4.36 }, { 192, 11.4125, +74.9881, 5.66 }, + { 193, 11.1813, +48.2844, 4.54 }, { 194, 11.0475, -9.3906, 4.76 }, { 195, 11.0504, -37.5783, 5.90 }, { 196, 11.3217, +55.2217, 5.42 }, + { 197, 11.1850, -21.9939, 5.24 }, { 198, 11.2379, -41.3233, 5.94 }, { 199, 11.1346, -61.5022, 6.07 }, { 200, 11.6625, +69.3250, 6.33 }, + { 201, 11.3504, -3.3708, 6.15 }, { 202, 11.2500, -52.2850, 6.15 }, { 203, 11.3696, -11.1192, 6.15 }, { 204, 11.5629, +55.3053, 6.52 }, + { 205, 11.5454, +44.8614, 6.05 }, { 206, 11.4238, -15.5758, 6.47 }, { 207, 11.6767, +59.5744, 6.39 }, { 208, 11.9421, +74.8475, 5.41 }, + { 209, 11.4400, -46.4483, 5.80 }, { 210, 11.5492, -21.4781, 5.50 }, { 211, 11.6375, +15.4756, 5.38 }, { 212, 12.0379, +72.6750, 5.87 }, + { 213, 11.7563, +11.9739, 5.50 }, { 214, 11.8067, +19.5789, 6.13 }, { 215, 11.8346, +24.2672, 4.06 }, { 216, 11.8483, +6.7408, 5.99 }, + { 217, 11.9783, +20.9253, 6.54 }, { 218, 11.9304, -17.9386, 5.70 }, { 219, 12.2750, +57.8158, 3.44 }, { 220, 12.0046, -20.2775, 5.57 }, + { 221, 12.0725, +7.3000, 5.93 }, { 222, 12.0958, +5.2806, 5.75 }, { 223, 12.2088, +50.9683, 4.89 }, { 224, 12.1708, +7.5850, 4.43 }, + { 225, 12.2446, +16.9406, 5.07 }, { 226, 12.4533, +41.0789, 4.53 }, { 227, 12.3567, -12.4386, 5.59 }, { 228, 12.3079, -23.8636, 5.90 }, + { 229, 12.2363, -45.3022, 6.27 }, { 230, 12.4700, +27.7108, 7.00 }, { 231, 12.4717, +27.7103, 7.10 }, { 232, 12.3892, -22.6383, 6.28 }, + { 233, 12.6817, +64.2475, 5.39 }, { 234, 12.5763, +45.0022, 6.15 }, { 235, 12.5317, -9.3556, 5.19 }, { 236, 12.1475, -73.0767, 5.07 }, + { 237, 12.8183, +61.8058, 6.07 }, { 238, 12.7392, +51.5081, 6.39 }, { 239, 12.5154, -42.6053, 6.48 }, { 240, 13.7213, +83.7072, 5.62 }, + { 241, 12.8904, +51.5711, 6.21 }, { 242, 12.6717, -49.0131, 5.22 }, { 243, 12.8263, +3.3850, 6.37 }, { 244, 13.2671, +61.1242, 4.82 }, + { 245, 12.9671, -42.2908, 6.90 }, { 246, 13.2225, +38.5486, 6.69 }, { 247, 13.1692, -23.9942, 5.46 }, { 248, 13.2521, -0.8558, 4.77 }, + { 249, 13.3675, +37.4181, 6.06 }, { 250, 13.4483, +52.6892, 6.27 }, { 251, 13.3017, -23.2231, 6.46 }, { 252, 13.1013, -68.4956, 6.22 }, + { 253, 13.7504, +58.9728, 4.83 }, { 254, 13.6467, +19.1883, 5.74 }, { 255, 13.5733, -7.2592, 6.16 }, { 256, 13.7717, +48.6786, 6.27 }, + { 257, 13.4079, -61.1286, 5.70 }, { 258, 13.7417, +23.6283, 5.47 }, { 259, 13.8112, +24.5569, 6.20 }, { 260, 14.0538, +57.9967, 6.21 }, + { 261, 14.2317, +68.7761, 6.37 }, { 262, 13.9938, +27.2094, 6.09 }, { 263, 13.9267, -6.6528, 5.85 }, { 264, 14.1771, +60.7167, 2.47 }, + { 265, 14.1658, +59.1811, 4.63 }, { 266, 14.1962, +60.3628, 5.55 }, { 267, 14.0063, -10.7333, 5.31 }, { 268, 13.9812, -26.2244, 6.10 }, + { 269, 14.1883, +38.4994, 3.87 }, { 270, 13.7513, -68.4731, 5.45 }, { 271, 14.3017, +23.4175, 4.42 }, { 272, 14.4154, +45.8397, 6.12 }, + { 273, 14.6296, +66.3522, 5.97 }, { 274, 14.4592, +28.9922, 5.42 }, { 275, 14.5592, +33.9508, 5.98 }, { 276, 14.4771, +13.6958, 6.32 }, + { 277, 14.5787, +21.4044, 6.37 }, { 278, 15.1292, +70.9831, 6.39 }, { 279, 14.6829, -10.6200, 5.61 }, { 280, 14.6517, -28.6425, 4.31 }, + { 281, 14.5933, -59.3036, 6.23 }, { 282, 15.0142, +44.7111, 6.84 }, { 283, 15.0150, +44.7133, 6.04 }, { 284, 14.9571, +6.4831, 6.11 }, + { 285, 17.1863, +86.2569, 4.25 }, { 286, 23.4600, +89.0156, 6.46 }, { 287, 15.5767, +51.0350, 6.47 }, { 288, 15.3263, -37.0833, 5.59 }, + { 289, 15.7563, +47.3761, 6.45 }, { 290, 15.7263, +41.3450, 5.98 }, { 291, 15.7046, +31.8044, 5.50 }, { 292, 15.9042, +61.0750, 5.92 }, + { 293, 15.6100, -30.4481, 5.50 }, { 294, 15.7358, +7.8900, 4.28 }, { 295, 15.5075, -56.9975, 6.11 }, { 296, 15.7608, -3.1633, 5.43 }, + { 297, 16.0817, +61.5803, 5.84 }, { 298, 16.0100, +52.5022, 5.99 }, { 299, 15.7050, -45.6025, 5.36 }, { 300, 15.8233, -28.4742, 6.29 }, + { 301, 15.9542, +1.3667, 6.04 }, { 302, 16.1950, +51.0100, 6.54 }, { 303, 16.1150, +29.6586, 6.19 }, { 304, 15.6788, -64.5439, 6.21 }, + { 305, 16.1517, +39.9911, 6.72 }, { 306, 19.0562, +87.1453, 6.25 }, { 307, 16.2192, +5.6564, 6.00 }, { 308, 16.2725, +14.9461, 5.68 }, + { 309, 16.5950, +62.7617, 6.54 }, { 310, 16.4204, +21.4733, 5.34 }, { 311, 16.4237, +21.4653, 5.56 }, { 312, 17.3013, +80.0117, 6.29 }, + { 313, 16.4550, +4.9083, 6.35 }, { 314, 16.4642, +4.9094, 7.25 }, { 315, 16.4033, -8.0208, 6.12 }, { 316, 16.7508, +56.9350, 6.43 }, + { 317, 16.5212, -8.1606, 5.58 }, { 318, 16.7896, +53.4983, 6.38 }, { 319, 16.6400, +12.9561, 6.12 }, { 320, 16.5321, -22.0075, 6.14 }, + { 321, 17.0683, +54.9203, 5.17 }, { 322, 16.5208, -45.2814, 3.31 }, { 323, 16.6104, -34.3392, 6.61 }, { 324, 17.0038, +43.9419, 5.03 }, + { 325, 16.8046, -22.0036, 6.37 }, { 326, 17.1388, +58.2636, 5.79 }, { 327, 17.0054, +32.0122, 6.25 }, { 328, 16.9883, +20.7392, 5.55 }, + { 329, 16.9425, -8.2144, 5.82 }, { 330, 17.0925, +5.6497, 5.52 }, { 331, 16.9496, -40.5131, 5.21 }, { 332, 16.8279, -60.2247, 5.37 }, + { 333, 18.0696, +79.6739, 5.64 }, { 334, 17.1475, -9.8178, 3.45 }, { 335, 17.3758, +47.2419, 4.25 }, { 336, 17.6638, +68.7786, 5.29 }, + { 337, 17.4329, +35.6206, 2.06 }, { 338, 17.0963, -54.7542, 3.92 }, { 339, 17.4550, +19.6586, 5.55 }, { 340, 17.5783, +42.0814, 5.65 }, + { 341, 17.5808, +25.4578, 5.80 }, { 342, 17.8567, +64.2028, 5.55 }, { 343, 17.7758, +55.1497, 4.33 }, { 344, 17.5479, +15.6742, 6.06 }, + { 345, 17.9225, +65.0189, 5.57 }, { 346, 17.5500, -7.0939, 6.40 }, { 347, 17.6400, +2.4456, 5.95 }, { 348, 17.7929, +37.7242, 5.81 }, + { 349, 17.7783, +31.4247, 5.16 }, { 350, 17.5308, -56.3056, 6.41 }, { 351, 17.8633, +21.0347, 4.66 }, { 352, 17.9150, +30.0897, 4.51 }, + { 353, 17.9312, -1.7489, 5.94 }, { 354, 18.2913, +61.7058, 6.41 }, { 355, 18.1417, +45.3378, 6.11 }, { 356, 18.2479, +30.0642, 6.19 }, + { 357, 19.1279, +79.9100, 6.26 }, { 358, 18.0975, -29.1978, 6.52 }, { 359, 18.1892, -36.1436, 5.92 }, { 360, 18.4371, +24.5836, 4.65 }, + { 361, 18.4329, +7.5753, 5.24 }, { 362, 18.4387, +7.5783, 6.30 }, { 363, 18.5208, +28.5297, 6.43 }, { 364, 18.5317, +16.1336, 5.98 }, + { 365, 19.0504, +71.7439, 7.83 }, { 366, 18.6000, -6.0769, 5.13 }, { 367, 18.6767, +6.9953, 6.03 }, { 368, 18.7050, +0.9739, 5.70 }, + { 369, 19.1021, +48.0822, 6.61 }, { 370, 18.7963, -44.4686, 4.96 }, { 371, 19.0783, +33.1147, 6.02 }, { 372, 19.2712, +44.9019, 6.34 }, + { 373, 19.1513, -1.4997, 5.41 }, { 374, 19.3504, +31.7447, 6.73 }, { 375, 20.0813, +77.5706, 6.31 }, { 376, 19.5425, +47.4197, 6.25 }, + { 377, 18.9421, -67.1239, 4.86 }, { 378, 19.4500, +3.6144, 5.16 }, { 379, 19.6958, +37.3861, 6.46 }, { 380, 19.2650, -65.6019, 6.24 }, + { 381, 20.4963, +76.2389, 6.38 }, { 382, 20.0204, +58.2317, 4.98 }, { 383, 19.8667, +27.2642, 4.76 }, { 384, 20.2717, +64.6583, 6.34 }, + { 385, 19.9513, +0.5089, 5.87 }, { 386, 20.9450, +78.7258, 6.07 }, { 387, 20.1438, -2.7531, 6.23 }, { 388, 20.1158, -10.7611, 6.15 }, + { 389, 20.2808, +28.7381, 5.23 }, { 390, 20.5850, +45.5289, 4.88 }, { 391, 20.8400, +58.1431, 6.45 }, { 392, 20.6542, +1.7264, 6.20 }, + { 393, 20.6450, +0.4497, 6.49 }, { 394, 20.6271, -18.9186, 6.35 }, { 395, 20.9192, +37.7150, 5.58 }, { 396, 20.9063, +34.2458, 6.29 }, + { 397, 20.8538, +20.4689, 5.97 }, { 398, 21.4438, +70.9800, 6.49 }, { 399, 21.4833, +68.1300, 4.74 }, { 400, 20.8792, -29.0544, 5.84 }, + { 401, 21.0104, -7.9925, 6.21 }, { 402, 21.0058, -7.8167, 3.60 }, { 403, 21.4542, +60.2353, 2.68 }, { 404, 21.0858, -5.0853, 5.91 }, + { 405, 21.1658, -14.3397, 6.14 }, { 406, 21.2029, -1.1514, 6.15 }, { 407, 21.3988, +23.5117, 6.18 }, { 408, 21.1700, -40.5075, 5.42 }, + { 409, 21.5775, +43.4578, 5.96 }, { 410, 21.5362, +34.5797, 6.31 }, { 411, 21.1746, -43.4717, 6.26 }, { 412, 21.4050, -13.4011, 4.90 }, + { 413, 21.5637, +19.1722, 5.38 }, { 414, 21.6737, +19.2403, 5.50 }, { 415, 21.7758, +34.3775, 6.27 }, { 416, 21.6138, +0.3986, 6.41 }, + { 417, 21.9142, +45.4067, 4.83 }, { 418, 21.8608, +41.1006, 6.46 }, { 419, 21.7229, +3.5353, 6.58 }, { 420, 21.2721, -63.6306, 5.93 }, + { 421, 21.7150, -12.9433, 5.66 }, { 422, 21.9458, +40.3356, 6.60 }, { 423, 21.7421, -31.4569, 5.79 }, { 424, 37.9529, +89.2642, 2.02 }, + { 425, 21.9442, -9.0983, 6.13 }, { 426, 22.0954, +7.9614, 6.20 }, { 427, 22.8075, +70.2647, 5.81 }, { 428, 22.7179, +66.0981, 6.14 }, + { 429, 22.0912, -42.6817, 3.41 }, { 430, 22.5258, +47.0072, 5.27 }, { 431, 22.1804, -32.2364, 6.58 }, { 432, 22.4704, +18.3556, 6.02 }, + { 433, 22.4004, -20.3706, 5.12 }, { 434, 22.5463, +6.1439, 4.84 }, { 435, 22.3767, -45.2436, 6.31 }, { 436, 22.5954, -25.7922, 5.93 }, + { 437, 22.8708, +15.3458, 3.62 }, { 438, 23.0317, +34.8000, 6.39 }, { 439, 23.3575, +58.3275, 5.70 }, { 440, 22.8129, -48.9272, 3.95 }, + { 441, 22.9304, -29.7167, 5.82 }, { 442, 23.4829, +59.2319, 4.71 }, { 443, 22.9129, -44.4244, 6.17 }, { 444, 23.2646, -8.9853, 6.59 }, + { 445, 23.2333, -35.1347, 5.51 }, { 446, 23.5692, +37.2372, 5.88 }, { 447, 23.1513, -48.2722, 6.28 }, { 448, 23.4288, -6.9747, 5.76 }, + { 449, 24.3438, +74.3008, 6.58 }, { 450, 23.7046, +18.4606, 5.89 }, { 451, 23.6575, -14.3239, 5.63 }, { 452, 23.9688, +41.0764, 6.38 }, + { 453, 23.7113, -30.1078, 6.12 }, { 454, 24.1133, +48.7228, 5.92 }, { 455, 23.9433, +14.6614, 6.22 }, { 456, 24.6288, +73.0400, 5.28 }, + { 457, 23.9783, +17.4336, 5.80 }, { 458, 24.1992, +41.4056, 4.09 }, { 459, 23.9958, -14.5997, 5.42 }, { 460, 23.8133, -57.8606, 6.01 }, + { 461, 24.5317, +57.9775, 5.56 }, { 462, 24.0350, -28.0925, 5.69 }, { 463, 24.2746, +12.1417, 5.57 }, { 464, 24.4983, +48.6283, 3.57 }, + { 465, 24.6321, +45.4000, 6.36 }, { 466, 24.4071, -8.5961, 6.24 }, { 467, 23.4133, -77.4953, 6.11 }, { 468, 24.1867, -57.7292, 6.18 }, + { 469, 24.8375, +44.3861, 4.98 }, { 470, 25.0546, +53.8683, 6.39 }, { 471, 24.6142, -35.4717, 5.94 }, { 472, 24.4288, -56.7633, 0.46 }, + { 473, 24.7158, -20.7247, 5.58 }, { 474, 24.7083, -24.9781, 6.70 }, { 475, 24.9200, +16.4058, 5.97 }, { 476, 25.1658, +43.2978, 5.61 }, + { 477, 25.1450, +40.5769, 4.94 }, { 478, 25.5854, +68.0431, 5.59 }, { 479, 24.7008, -52.5611, 6.84 }, { 480, 25.7329, +70.6225, 5.18 }, + { 481, 25.5125, +61.0383, 6.71 }, { 482, 25.5742, +58.6278, 6.37 }, { 483, 25.4467, +42.6136, 4.95 }, { 484, 25.3267, +25.7458, 6.17 }, + { 485, 25.4133, +30.0472, 5.99 }, { 486, 24.9475, -55.8019, 5.87 }, { 487, 24.9492, -55.8053, 5.76 }, { 488, 25.7433, +61.4217, 6.34 }, + { 489, 25.3579, +5.4875, 4.44 }, { 490, 25.5146, +35.2456, 5.64 }, { 491, 25.8321, +60.5511, 5.78 }, { 492, 25.4363, -10.6753, 5.75 }, + { 493, 25.6242, +20.2686, 5.24 }, { 494, 25.3638, -37.8669, 6.17 }, { 495, 25.8188, +45.3222, 6.34 }, { 496, 25.9150, +50.6886, 4.07 }, + { 497, 25.5358, -31.6731, 5.25 }, { 498, 25.5125, -35.1675, 5.72 }, { 499, 26.0746, +57.5364, 6.21 }, { 500, 25.6812, -2.3097, 4.99 }, + { 501, 25.4213, -49.9611, 6.64 }, { 502, 26.1921, +57.0892, 6.25 }, { 503, 25.9583, +32.1917, 6.34 }, { 504, 26.1104, +46.1397, 6.35 }, + { 505, 25.4500, -59.2106, 5.71 }, { 506, 25.6221, -52.2594, 5.52 }, { 507, 25.9783, -3.2344, 6.19 }, { 508, 26.2325, +20.0831, 6.27 }, + { 509, 26.0171, -14.0625, 3.50 }, { 510, 26.3483, +9.1578, 4.26 }, { 511, 26.9367, +63.8522, 5.63 }, { 512, 24.4817, -81.0250, 5.87 }, + { 513, 26.4971, -4.2667, 5.34 }, { 514, 26.4117, -24.9475, 5.31 }, { 515, 26.6471, +17.4131, 6.55 }, { 516, 25.3388, -78.8517, 6.33 }, + { 517, 26.5042, -26.6508, 6.39 }, { 518, 26.9500, +46.2297, 6.32 }, { 519, 26.5242, -49.1836, 5.49 }, { 520, 26.5263, -52.4781, 5.04 }, + { 521, 27.1621, +37.9528, 5.94 }, { 522, 27.0454, +16.9556, 5.84 }, { 523, 27.1733, +32.6903, 5.79 }, { 524, 26.8200, -40.2400, 6.18 }, + { 525, 24.3667, -83.2303, 5.69 }, { 526, 27.3154, +47.8969, 5.82 }, { 527, 27.1083, +3.6856, 5.91 }, { 528, 26.9492, -36.8403, 6.32 }, + { 529, 27.7379, +51.9333, 5.90 }, { 530, 27.5354, +22.2753, 5.86 }, { 531, 27.3962, -9.3136, 4.67 }, { 532, 27.3313, -30.9272, 6.34 }, + { 533, 27.9971, +55.1475, 5.52 }, { 534, 27.7167, +11.0433, 5.94 }, { 535, 27.4533, -37.5961, 6.37 }, { 536, 28.0392, +50.7928, 5.79 }, + { 537, 27.5842, -46.1836, 6.14 }, { 538, 28.2117, +51.4747, 6.26 }, { 539, 27.8650, -9.6650, 3.73 }, { 540, 28.4521, +55.5981, 6.45 }, + { 541, 27.7271, -49.7939, 5.94 }, { 542, 28.5987, +63.6700, 3.38 }, { 543, 28.3221, +40.7297, 5.40 }, { 544, 28.2704, +29.5789, 3.41 }, + { 545, 28.3825, +19.2958, 4.83 }, { 546, 28.3825, +19.2936, 4.75 }, { 547, 28.2171, -15.0708, 5.80 }, { 548, 29.0000, +68.6853, 4.99 }, + { 549, 28.3888, +3.1875, 4.62 }, { 550, 26.9438, -79.8233, 6.06 }, { 551, 28.7242, +40.7019, 6.24 }, { 552, 28.7396, +37.1283, 6.26 }, + { 553, 28.6600, +20.8081, 2.64 }, { 554, 28.3467, -37.4053, 6.10 }, { 555, 28.4117, -45.6975, 4.41 }, { 556, 28.9767, +37.2778, 5.89 }, + { 557, 29.0388, +37.2517, 5.67 }, { 558, 28.5917, -41.5031, 5.11 }, { 559, 28.9625, +23.5772, 5.74 }, { 560, 28.9742, +1.8497, 6.01 }, + { 561, 29.6388, +61.6981, 6.02 }, { 562, 29.4850, +41.6944, 6.78 }, { 563, 29.3379, +17.8175, 5.10 }, { 564, 29.4325, +27.8044, 5.82 }, + { 565, 29.1675, -21.4731, 4.85 }, { 566, 28.9896, -50.3911, 3.70 }, { 567, 29.9083, +64.6214, 5.26 }, { 568, 29.6400, +49.2042, 5.69 }, + { 569, 29.4821, +23.5961, 4.79 }, { 570, 28.7338, -66.3528, 4.69 }, { 571, 28.9433, -59.1386, 6.06 }, { 572, 30.7383, +77.9164, 6.04 }, + { 573, 29.2504, -50.2339, 6.10 }, { 574, 29.2917, -46.6150, 4.83 }, { 575, 30.4892, +70.9069, 4.54 }, { 576, 29.6112, -32.9333, 6.35 }, + { 577, 29.8988, +21.0583, 5.87 }, { 578, 29.8579, +12.2947, 6.09 }, { 579, 30.7937, +73.8506, 6.23 }, { 580, 30.8588, +72.4214, 3.98 }, + { 581, 31.2808, +77.2814, 5.38 }, { 582, 30.0383, +3.0972, 5.88 }, { 583, 29.9421, -19.1756, 5.41 }, { 584, 29.4733, -64.5753, 6.37 }, + { 585, 30.0012, -20.9222, 4.00 }, { 586, 30.7196, +64.9014, 6.00 }, { 587, 30.1121, -7.4764, 5.51 }, { 588, 29.9117, -41.9694, 5.57 }, + { 589, 30.7512, +64.3900, 5.58 }, { 590, 30.5754, +54.4875, 5.04 }, { 591, 29.6925, -60.4303, 2.86 }, { 592, 31.3800, +76.1150, 5.22 }, + { 593, 28.9604, -77.6517, 6.16 }, { 594, 30.3113, -29.9983, 5.35 }, { 595, 30.5117, +2.7636, 5.23 }, { 596, 30.5117, +2.7636, 4.33 }, + { 597, 32.3554, +81.2958, 6.05 }, { 598, 31.1671, +65.1033, 6.52 }, { 599, 30.7417, +33.2839, 5.50 }, { 600, 29.9213, -65.9336, 6.10 }, + { 601, 30.6467, +13.4767, 5.94 }, { 602, 30.4267, -43.2864, 5.14 }, { 603, 30.9750, +42.3297, 2.26 }, { 604, 30.9779, +42.3308, 4.84 }, + { 605, 30.9138, +25.9356, 5.63 }, { 606, 30.6171, -28.3350, 6.42 }, { 607, 30.7987, +0.1283, 5.43 }, { 608, 30.7442, -14.6942, 5.86 }, + { 609, 30.9275, +18.2533, 6.21 }, { 610, 30.9508, +0.3403, 5.93 }, { 611, 30.9187, -3.8964, 5.62 }, { 612, 31.1225, -28.7031, 4.69 }, + { 613, 31.6412, +22.6483, 5.03 }, { 614, 31.5513, +8.2475, 6.31 }, { 615, 31.7050, +25.7047, 6.15 }, { 616, 31.6221, +0.0350, 6.28 }, + { 617, 31.7933, +23.4625, 2.00 }, { 618, 32.1688, +58.4236, 5.67 }, { 619, 32.1400, +44.4594, 6.42 }, { 620, 32.1221, +37.8592, 4.82 }, + { 621, 32.5325, +53.8431, 6.31 }, { 622, 32.3858, +34.9872, 3.00 }, { 623, 32.3554, +25.9397, 4.98 }, { 624, 32.3462, +17.2244, 6.43 }, + { 625, 32.1904, -16.2206, 6.10 }, { 626, 33.3383, +74.0278, 6.29 }, { 627, 32.8708, +57.6458, 6.36 }, { 628, 32.7200, +39.0394, 5.63 }, + { 629, 32.7238, +39.0431, 6.10 }, { 630, 32.3950, -23.6542, 6.48 }, { 631, 32.6567, +19.5003, 5.70 }, { 632, 32.2888, -42.4833, 5.85 }, + { 633, 32.8000, +25.9369, 6.02 }, { 634, 32.8542, +31.5264, 6.23 }, { 635, 32.8379, +8.5697, 5.63 }, { 636, 32.5204, -42.1844, 6.32 }, + { 637, 32.6067, -49.1756, 6.12 }, { 638, 32.8425, -9.9478, 6.01 }, { 639, 32.8992, -0.1747, 5.93 }, { 640, 33.6213, +66.5244, 6.07 }, + { 641, 33.4229, +58.5611, 6.44 }, { 642, 33.0929, +30.3031, 4.94 }, { 643, 33.3054, +44.2317, 4.83 }, { 644, 33.1563, +24.1678, 5.96 }, + { 645, 33.4012, +51.0658, 5.31 }, { 646, 33.2004, +21.2108, 5.27 }, { 647, 33.5108, +47.4842, 6.06 }, { 648, 33.2638, +15.2797, 5.71 }, + { 649, 33.2500, +8.8467, 4.37 }, { 650, 33.1979, -1.6064, 5.54 }, { 651, 33.2537, -20.9997, 5.86 }, { 652, 33.2271, -29.2761, 5.28 }, + { 653, 33.9913, +47.8114, 6.33 }, { 654, 34.2154, +57.0553, 6.48 }, { 655, 33.9842, +33.3589, 5.28 }, { 656, 33.9417, +25.7831, 5.79 }, + { 657, 33.9283, +25.0431, 5.58 }, { 658, 33.8679, -8.5344, 6.55 }, { 659, 33.6333, -40.8333, 5.91 }, { 660, 34.2633, +34.2242, 4.87 }, + { 661, 34.4996, +57.8997, 5.75 }, { 662, 34.5187, +57.5167, 5.98 }, { 663, 34.3892, +44.3069, 6.70 }, { 664, 34.3287, +33.8472, 4.01 }, + { 665, 34.2933, +23.7678, 6.55 }, { 666, 34.2458, -5.5778, 5.51 }, { 667, 33.5613, -66.1583, 5.55 }, { 668, 35.0538, +64.3372, 6.60 }, + { 669, 34.5313, +19.9011, 5.62 }, { 670, 34.8200, +47.3800, 5.30 }, { 671, 34.7954, +46.4725, 6.21 }, { 672, 34.5058, +1.7578, 5.58 }, + { 673, 34.8446, +48.9553, 6.37 }, { 674, 34.1275, -50.4878, 3.56 }, { 675, 34.7375, +28.6425, 5.03 }, { 676, 34.7417, +23.1678, 6.46 }, + { 677, 34.9054, +39.8350, 6.63 }, { 678, 33.8687, -66.2536, 5.69 }, { 679, 35.1725, +47.3108, 6.11 }, { 680, 35.0183, +30.1883, 6.47 }, + { 681, 34.8363, -1.0225, 3.04 }, { 682, 35.2425, +50.1514, 5.59 }, { 683, 34.7437, -24.0544, 6.34 }, { 684, 34.9200, -3.6544, 6.50 }, + { 685, 35.5892, +55.8456, 5.17 }, { 686, 34.8529, -40.1517, 6.37 }, { 687, 35.7096, +41.3964, 5.82 }, { 688, 34.9763, -54.0553, 5.81 }, + { 689, 35.4858, +0.3958, 5.28 }, { 690, 35.9658, +55.3644, 6.28 }, { 691, 35.5517, +0.8850, 5.42 }, { 692, 35.5058, -9.2222, 5.46 }, + { 693, 35.5208, -16.3378, 5.87 }, { 694, 36.1037, +50.0067, 5.19 }, { 695, 35.6358, -22.1836, 5.20 }, { 696, 36.3167, +56.6100, 6.25 }, + { 697, 35.7408, -17.6456, 6.22 }, { 698, 35.5492, -42.8000, 6.31 }, { 699, 36.4058, +50.2786, 4.71 }, { 700, 35.7771, -36.4236, 6.53 }, + { 701, 35.7275, -50.9078, 5.92 }, { 702, 36.2042, +10.6106, 5.47 }, { 703, 36.0838, -24.1525, 6.44 }, { 704, 36.2433, -1.2200, 6.33 }, + { 705, 35.4371, -67.3406, 4.09 }, { 706, 36.1408, -39.1594, 6.18 }, { 707, 37.2667, +67.4025, 4.52 }, { 708, 36.4875, -11.7094, 4.89 }, + { 709, 36.9658, +50.5697, 6.12 }, { 710, 36.5012, -14.6589, 5.83 }, { 711, 36.7792, +27.0133, 6.18 }, { 712, 36.8654, +31.8014, 5.54 }, + { 713, 36.6467, -19.9572, 5.88 }, { 714, 36.2246, -59.6881, 5.35 }, { 715, 35.7179, -72.3542, 5.01 }, { 716, 37.3542, +55.5364, 6.51 }, + { 717, 37.0417, +29.6694, 5.29 }, { 718, 37.0396, +8.4600, 4.28 }, { 719, 37.0000, +1.9608, 6.45 }, { 720, 37.2021, +29.9319, 5.89 }, + { 721, 36.7463, -46.2961, 4.25 }, { 722, 36.3596, -65.5053, 6.41 }, { 723, 37.3067, +23.4689, 6.19 }, { 724, 37.0071, -32.1889, 5.14 }, + { 725, 37.3971, +9.5658, 6.07 }, { 726, 37.5692, +33.8339, 6.25 }, { 727, 37.1475, -30.8975, 6.11 }, { 728, 37.6350, +25.2350, 5.92 }, + { 729, 37.6600, +19.8553, 6.15 }, { 730, 37.4808, -21.3172, 6.77 }, { 731, 37.7267, +17.7039, 6.23 }, { 732, 37.6883, +0.2553, 6.00 }, + { 733, 37.5575, -24.8136, 6.51 }, { 734, 37.0183, -63.7003, 6.37 }, { 735, 37.6367, -21.4544, 6.10 }, { 736, 38.0258, +36.1472, 5.15 }, + { 737, 37.8754, +2.2672, 5.25 }, { 738, 38.2188, +34.5425, 5.83 }, { 739, 38.0392, -0.9650, 5.35 }, { 740, 38.0217, -14.7553, 4.75 }, + { 741, 38.2254, +15.0347, 6.04 }, { 742, 38.0617, -35.5725, 6.30 }, { 743, 39.5083, +72.8183, 5.16 }, { 744, 38.2792, -33.3500, 5.90 }, + { 745, 38.4175, -19.9981, 6.21 }, { 746, 38.8663, +39.6644, 6.36 }, { 747, 39.4004, +65.7456, 5.78 }, { 748, 38.9117, +37.3122, 5.71 }, + { 749, 38.4613, -27.7675, 4.90 }, { 750, 38.9450, +34.6875, 5.35 }, { 751, 38.7671, +7.4714, 6.18 }, { 752, 38.6779, -6.1406, 5.75 }, + { 753, 39.0204, +6.8869, 5.82 }, { 754, 38.9688, +5.5933, 4.86 }, { 755, 38.4775, -50.9064, 6.24 }, { 756, 39.2383, +38.7328, 5.90 }, + { 757, 39.1788, +31.6075, 6.10 }, { 758, 39.2604, +34.2639, 5.30 }, { 759, 39.0000, -6.1683, 5.53 }, { 760, 39.3367, +39.8958, 6.54 }, + { 761, 39.2767, +32.8919, 6.25 }, { 762, 38.3900, -61.4131, 6.77 }, { 763, 39.1579, +12.4475, 5.68 }, { 764, 39.2404, +24.6483, 7.09 }, + { 765, 39.2521, +24.6475, 6.50 }, { 766, 39.1463, +7.7297, 5.81 }, { 767, 39.0388, -29.9553, 5.75 }, { 768, 39.5742, +37.7267, 6.18 }, + { 769, 39.6158, +38.0894, 6.30 }, { 770, 39.5033, +7.6953, 6.39 }, { 771, 39.4242, -2.6039, 5.65 }, { 772, 39.2442, -33.4217, 5.79 }, + { 773, 39.7042, +21.9614, 5.43 }, { 774, 41.9483, +81.4483, 5.78 }, { 775, 39.6538, +3.4431, 6.21 }, { 776, 37.9188, -78.8906, 5.28 }, + { 777, 39.5779, -29.8058, 5.83 }, { 778, 39.3517, -51.4569, 5.31 }, { 779, 39.8708, +0.3286, 4.07 }, { 780, 39.6033, -36.0094, 6.49 }, + { 781, 39.8908, -10.1278, 4.84 }, { 782, 40.1713, +27.0608, 5.30 }, { 783, 40.0654, +6.1119, 6.25 }, { 784, 40.0513, -8.5469, 5.78 }, + { 785, 40.7617, +55.1058, 5.77 }, { 786, 40.0104, -29.3661, 6.52 }, { 787, 40.7488, +53.5261, 5.84 }, { 788, 40.5621, +40.1939, 4.91 }, + { 789, 39.9500, -41.1083, 4.75 }, { 790, 40.3079, +0.6958, 5.71 }, { 791, 41.2071, +67.8247, 5.95 }, { 792, 40.7579, +48.2656, 6.48 }, + { 793, 40.5917, +20.0117, 5.69 }, { 794, 40.1667, -38.1444, 4.11 }, { 795, 40.4513, -2.7867, 6.05 }, { 796, 40.3917, -13.4506, 5.98 }, + { 797, 40.6204, +10.7417, 6.30 }, { 798, 39.8821, -63.7181, 6.55 }, { 799, 41.0500, +49.2283, 4.12 }, { 800, 41.0217, +44.2969, 5.43 }, + { 801, 40.8629, +27.7072, 4.66 }, { 802, 40.1650, -53.4500, 5.21 }, { 803, 40.9633, +25.6381, 6.35 }, { 804, 40.8250, +3.2358, 3.47 }, + { 805, 40.5275, -37.6161, 6.01 }, { 806, 39.8975, -67.7331, 4.11 }, { 807, 40.5354, -45.4756, 6.10 }, { 808, 41.0796, +17.7639, 6.46 }, + { 809, 41.1371, +15.3117, 5.77 }, { 810, 40.6396, -49.1997, 5.41 }, { 811, 41.0308, -12.1414, 4.25 }, { 812, 41.2400, +12.4458, 5.18 }, + { 813, 41.2354, +10.1142, 4.27 }, { 814, 40.8346, -39.4725, 6.36 }, { 815, 42.2313, +69.6342, 6.18 }, { 816, 41.3371, +4.7117, 6.03 }, + { 817, 41.0854, -31.4750, 6.22 }, { 818, 41.2758, -17.4275, 4.47 }, { 819, 41.7429, +35.9836, 6.25 }, { 820, 41.7646, +35.5550, 6.30 }, + { 821, 41.0446, -51.4294, 6.15 }, { 822, 41.3188, -45.7128, 6.85 }, { 823, 40.8608, -65.2856, 6.26 }, { 824, 41.9771, +29.2472, 4.51 }, + { 825, 42.3783, +57.0842, 6.25 }, { 826, 41.6883, -20.3603, 6.49 }, { 827, 41.7967, -21.5144, 6.47 }, { 828, 42.1337, +18.2836, 5.82 }, + { 829, 42.9946, +68.8886, 5.80 }, { 830, 42.1912, +25.1881, 5.86 }, { 831, 42.3629, +37.3261, 6.45 }, { 832, 41.9833, -11.5394, 6.90 }, + { 833, 41.3646, -62.2956, 5.74 }, { 834, 42.6742, +55.8956, 3.76 }, { 835, 41.8904, -34.4492, 6.51 }, { 836, 42.3229, +17.4642, 5.22 }, + { 837, 41.3858, -66.3833, 4.84 }, { 838, 42.4958, +27.2606, 3.63 }, { 839, 42.9396, +58.3147, 6.45 }, { 840, 42.6463, +38.3186, 4.23 }, + { 841, 42.2725, -31.5942, 4.46 }, { 842, 42.9237, +46.8419, 5.88 }, { 843, 42.8783, +35.0597, 4.53 }, { 844, 42.4625, -23.4397, 6.14 }, + { 845, 42.4758, -26.0583, 5.39 }, { 846, 43.2167, +52.9978, 6.36 }, { 847, 42.8733, +15.0819, 5.49 }, { 848, 42.5617, -34.1564, 5.92 }, + { 849, 43.3383, +48.5694, 6.26 }, { 850, 42.7596, -20.9958, 4.75 }, { 851, 42.6683, -34.3239, 5.47 }, { 852, 42.2563, -61.1933, 5.26 }, + { 853, 42.6996, -38.0683, 6.36 }, { 854, 43.5646, +52.7625, 3.95 }, { 855, 43.4275, +38.3375, 5.33 }, { 856, 43.2987, +16.4833, 6.31 }, + { 857, 43.1337, -11.2306, 6.04 }, { 858, 42.9804, -29.1856, 6.40 }, { 859, 43.2104, -8.5589, 6.32 }, { 860, 43.9871, +61.5211, 5.59 }, + { 861, 44.1033, +64.3325, 6.24 }, { 862, 43.3971, -21.6236, 5.95 }, { 863, 43.3933, -37.5631, 5.92 }, { 864, 44.2108, +51.2608, 6.22 }, + { 865, 44.1392, +47.1639, 6.02 }, { 866, 43.0800, -61.0903, 6.03 }, { 867, 43.9521, +18.3317, 5.91 }, { 868, 43.4704, -48.1097, 4.00 }, + { 869, 44.1088, +18.0231, 5.63 }, { 870, 44.0575, +8.3817, 5.97 }, { 871, 43.5271, -49.1286, 6.21 }, { 872, 42.6187, -74.9331, 4.75 }, + { 873, 44.3221, +31.9342, 5.11 }, { 874, 44.1071, -7.1019, 3.89 }, { 875, 44.1558, -2.2878, 5.17 }, { 876, 44.5096, +38.6150, 6.04 }, + { 877, 44.2692, +4.5011, 6.11 }, { 878, 44.5217, +20.6686, 5.80 }, { 879, 44.6904, +39.6628, 4.70 }, { 880, 43.5871, -63.5644, 6.56 }, + { 881, 46.5325, +79.4186, 5.49 }, { 882, 44.7654, +35.1831, 4.93 }, { 883, 44.3488, -22.1381, 5.45 }, { 884, 44.3046, -28.1447, 6.29 }, + { 885, 44.9579, +47.2208, 5.47 }, { 886, 44.9162, +41.0331, 5.89 }, { 887, 44.8029, +21.3403, 4.63 }, { 888, 44.8029, +21.3403, 4.63 }, + { 889, 44.5238, -22.3939, 5.84 }, { 890, 45.2175, +52.3517, 5.28 }, { 891, 45.2225, +52.3522, 6.74 }, { 892, 44.6750, -1.2175, 5.23 }, + { 893, 44.3862, -37.8089, 6.41 }, { 894, 45.0492, +38.1317, 6.11 }, { 895, 44.6975, -8.2236, 6.14 }, { 896, 44.9288, +8.9075, 4.70 }, + { 897, 44.5654, -39.6953, 3.24 }, { 898, 44.5679, -39.6956, 4.35 }, { 899, 44.9217, -1.5350, 5.56 }, { 900, 44.7775, -27.0931, 6.14 }, + { 901, 44.9004, -24.7258, 5.71 }, { 902, 45.1838, +10.8703, 5.95 }, { 903, 44.9096, -31.4928, 6.31 }, { 904, 45.2125, -1.1214, 6.11 }, + { 905, 45.4754, +26.4622, 5.90 }, { 906, 47.9283, +81.4706, 5.95 }, { 907, 45.2917, -6.3372, 5.75 }, { 908, 45.4679, +5.3361, 6.25 }, + { 909, 44.6992, -63.9286, 4.99 }, { 910, 45.5938, +4.3528, 5.61 }, { 911, 45.5700, +4.0897, 2.53 }, { 912, 45.4838, -8.0386, 5.83 }, + { 913, 45.5388, -5.5053, 6.19 }, { 914, 45.4071, -27.9083, 5.89 }, { 915, 46.1992, +53.5064, 2.93 }, { 916, 45.8762, +28.2697, 6.36 }, + { 917, 45.6763, -6.3147, 5.32 }, { 918, 46.3850, +56.7058, 4.76 }, { 919, 45.5979, -22.3756, 4.09 }, { 920, 46.4162, +56.0686, 6.11 }, + { 921, 46.2942, +38.8403, 3.39 }, { 922, 46.8292, +64.0578, 5.89 }, { 923, 46.3367, +40.5825, 6.05 }, { 924, 46.1696, +15.8561, 6.49 }, + { 925, 46.0683, -6.3992, 5.26 }, { 926, 46.1587, +1.8636, 6.05 }, { 927, 46.3612, +25.2553, 6.80 }, { 928, 46.3612, +25.2553, 7.00 }, + { 929, 45.7329, -45.0250, 5.82 }, { 930, 47.0162, +52.2133, 6.31 }, { 931, 46.5988, +13.1872, 5.62 }, { 932, 47.9846, +74.3936, 4.87 }, + { 933, 46.9475, +47.3083, 6.41 }, { 934, 45.9033, -58.2622, 5.11 }, { 935, 46.6396, -5.9114, 5.27 }, { 936, 47.0421, +40.9556, 2.12 }, + { 937, 47.2667, +49.6133, 4.05 }, { 938, 46.8571, +17.8800, 6.11 }, { 939, 45.5642, -70.0975, 5.53 }, { 940, 47.0883, +18.7950, 6.27 }, + { 941, 47.3742, +44.8572, 3.80 }, { 942, 47.1613, +8.4708, 6.28 }, { 943, 46.9621, -26.1689, 6.19 }, { 944, 47.4029, +29.0769, 5.72 }, + { 945, 47.5367, +27.8200, 6.42 }, { 946, 47.6125, +26.8964, 6.02 }, { 947, 47.8225, +39.6117, 4.63 }, { 948, 47.6621, +11.8725, 5.98 }, + { 949, 48.1100, +47.7258, 6.33 }, { 950, 48.0400, +42.3761, 6.15 }, { 951, 47.9075, +19.7267, 4.35 }, { 952, 47.8413, +13.0478, 6.12 }, + { 953, 47.6475, -22.2617, 6.38 }, { 954, 48.0592, +27.2569, 5.79 }, { 955, 47.8283, -2.1883, 6.05 }, { 956, 48.3500, +48.1769, 5.90 }, + { 957, 47.8200, -15.9747, 6.26 }, { 958, 48.1100, +6.6608, 5.56 }, { 959, 46.9550, -68.7344, 6.15 }, { 960, 47.6142, -47.2658, 6.12 }, + { 961, 50.0821, +77.7347, 5.45 }, { 962, 48.1933, -0.8039, 5.06 }, { 963, 48.0179, -27.0131, 3.87 }, { 964, 48.9500, +57.1408, 5.79 }, + { 965, 53.0838, +84.9111, 5.61 }, { 966, 48.7362, +42.5039, 6.07 }, { 967, 49.3817, +65.6586, 6.36 }, { 968, 48.1075, -43.5803, 5.93 }, + { 969, 49.0508, +50.9378, 5.03 }, { 970, 48.2563, -34.0561, 6.27 }, { 971, 48.8354, +30.5567, 5.52 }, { 972, 48.7254, +21.0444, 4.89 }, + { 973, 49.0196, +45.3458, 6.16 }, { 974, 48.4083, -28.1958, 6.16 }, { 975, 48.9458, +32.8564, 6.31 }, { 976, 49.0079, +34.6886, 6.25 }, + { 977, 48.1383, -56.6783, 5.74 }, { 978, 49.1463, +32.1836, 6.06 }, { 979, 49.2975, +40.4833, 6.45 }, { 980, 48.7508, -25.8997, 6.25 }, + { 981, 46.8833, -77.0106, 5.57 }, { 982, 49.4475, +44.0250, 5.47 }, { 983, 49.0037, -4.0814, 6.17 }, { 984, 48.9583, -7.1803, 4.80 }, + { 985, 49.9975, +65.6522, 4.84 }, { 986, 49.4408, +39.2833, 5.96 }, { 987, 49.6575, +50.2222, 5.15 }, { 988, 49.1488, -8.8456, 6.14 }, + { 989, 49.7817, +50.0950, 5.03 }, { 990, 49.0471, -29.1725, 6.65 }, { 991, 49.6825, +34.2228, 4.82 }, { 992, 49.5933, +0.9303, 5.38 }, + { 993, 49.5117, -27.2031, 5.91 }, { 994, 49.5921, -21.4886, 4.88 }, { 995, 49.9825, +27.0711, 5.90 }, { 996, 49.8404, +3.3703, 4.83 }, + { 997, 49.6717, -17.4403, 5.71 }, { 998, 49.3608, -46.2483, 5.85 }, { 999, 50.0850, +29.0483, 4.47 }, { 1000, 50.1067, +25.6628, 6.12 }, + { 1001, 50.4692, +49.0708, 5.93 }, { 1002, 50.3604, +43.3294, 4.95 }, { 1003, 49.8792, -20.2422, 3.69 }, { 1004, 49.8950, -23.8769, 5.61 }, + { 1005, 50.3067, +21.1469, 5.28 }, { 1006, 49.4425, -61.4247, 5.54 }, { 1007, 50.2783, +3.6756, 5.69 }, { 1008, 49.9821, -42.9303, 4.27 }, + { 1009, 51.1688, +64.5861, 5.23 }, { 1010, 49.5538, -61.4936, 5.24 }, { 1011, 50.8050, +49.2133, 5.29 }, { 1012, 50.5496, +27.6075, 5.52 }, + { 1013, 50.1883, -25.3936, 6.39 }, { 1014, 49.4958, -65.0731, 6.05 }, { 1015, 50.6883, +20.7419, 5.09 }, { 1016, 50.3500, -22.3647, 5.52 }, + { 1017, 51.0808, +49.8611, 1.79 }, { 1018, 50.5679, -24.4122, 6.35 }, { 1019, 51.1238, +33.5358, 5.61 }, { 1020, 51.4517, +53.9217, 6.51 }, + { 1021, 50.3888, -46.2231, 6.39 }, { 1022, 51.0771, +24.7242, 5.50 }, { 1023, 50.9129, +4.8819, 6.38 }, { 1024, 50.8242, -6.2058, 6.20 }, + { 1025, 48.9900, -76.6117, 5.52 }, { 1026, 51.2892, +41.2572, 6.51 }, { 1027, 51.1088, +20.8036, 6.08 }, { 1028, 51.0421, +12.6294, 6.04 }, + { 1029, 51.4892, +49.1208, 6.09 }, { 1030, 51.2033, +9.0289, 3.60 }, { 1031, 50.9358, -31.2928, 6.50 }, { 1032, 52.5812, +71.8639, 6.32 }, + { 1033, 52.0983, +60.2556, 6.49 }, { 1034, 52.0129, +49.0628, 4.98 }, { 1035, 52.2671, +59.9403, 4.21 }, { 1036, 51.7633, +18.7564, 6.57 }, + { 1037, 52.2183, +49.8483, 5.58 }, { 1038, 51.7925, +9.7328, 3.74 }, { 1039, 51.8279, +12.7350, 6.28 }, { 1040, 52.4787, +58.8786, 4.54 }, + { 1041, 52.0867, +33.8075, 5.61 }, { 1042, 51.4825, -34.0792, 6.39 }, { 1043, 52.5471, +59.3661, 6.13 }, { 1044, 52.3421, +49.5089, 4.67 }, + { 1045, 51.5938, -26.6825, 5.93 }, { 1046, 52.5008, +55.4519, 5.09 }, { 1047, 52.3592, +46.9378, 6.24 }, { 1048, 52.1108, +22.8042, 6.03 }, + { 1049, 51.5487, -40.3631, 6.32 }, { 1050, 52.0042, -10.7133, 5.73 }, { 1051, 52.6542, +48.1036, 5.82 }, { 1052, 52.6437, +47.9953, 4.36 }, + { 1053, 51.0104, -68.3753, 6.15 }, { 1054, 51.8892, -34.3186, 5.71 }, { 1055, 53.8017, +73.3469, 6.57 }, { 1056, 52.8725, +49.2097, 6.29 }, + { 1057, 0.0000, +0.0000, 0.00 }, { 1058, 52.0479, -34.1467, 6.50 }, { 1059, 52.9546, +49.4008, 6.39 }, { 1060, 52.4129, -5.1950, 5.99 }, + { 1061, 52.6021, +11.3364, 5.14 }, { 1062, 52.4000, -11.3253, 5.59 }, { 1063, 53.0358, +48.0236, 5.47 }, { 1064, 51.4008, -68.6636, 5.96 }, + { 1065, 52.8367, +27.5719, 5.96 }, { 1066, 52.7183, +12.9367, 4.11 }, { 1067, 52.6892, +6.1886, 5.94 }, { 1068, 53.3837, +58.7650, 6.40 }, + { 1069, 53.1096, +46.0569, 5.31 }, { 1070, 52.6546, -4.9247, 4.73 }, { 1071, 53.4217, +57.8689, 6.37 }, { 1072, 53.1629, +44.8556, 6.41 }, + { 1073, 53.4125, +54.9747, 5.98 }, { 1074, 53.1667, +35.4617, 5.90 }, { 1075, 52.4792, -41.3658, 5.78 }, { 1076, 52.5567, -40.6300, 6.12 }, + { 1077, 53.7533, +60.0411, 6.46 }, { 1078, 53.3963, +39.8994, 5.81 }, { 1079, 53.1500, +9.3736, 5.77 }, { 1080, 54.8533, +75.7397, 6.27 }, + { 1081, 52.6542, -46.6247, 5.99 }, { 1082, 52.9746, -24.3858, 6.38 }, { 1083, 52.3446, -61.0625, 4.72 }, { 1084, 53.2325, -8.5417, 3.73 }, + { 1085, 53.5346, +17.8328, 6.17 }, { 1086, 53.6108, +24.4644, 5.92 }, { 1087, 54.1225, +48.1928, 4.23 }, { 1088, 53.4471, -20.3672, 4.27 }, + { 1089, 53.7050, +6.4178, 6.49 }, { 1090, 53.1450, -49.6214, 5.68 }, { 1091, 53.6558, -8.1314, 6.25 }, { 1092, 52.7150, -65.5103, 5.83 }, + { 1093, 53.4867, -30.9197, 6.20 }, { 1094, 54.5821, +56.9328, 6.30 }, { 1095, 53.6396, -30.1253, 6.40 }, { 1096, 53.2150, -60.9831, 6.41 }, + { 1097, 54.5008, +42.5831, 6.42 }, { 1098, 53.9904, -10.8064, 5.57 }, { 1099, 54.1971, +0.5878, 5.71 }, { 1100, 54.0725, -16.5331, 5.23 }, + { 1101, 54.2183, +0.4017, 4.28 }, { 1102, 54.4492, +15.4308, 6.39 }, { 1103, 54.7504, +20.9158, 6.50 }, { 1104, 53.6029, -64.2356, 6.75 }, + { 1105, 55.5388, +63.2167, 5.10 }, { 1106, 54.2738, -39.7253, 4.58 }, { 1107, 62.5063, +86.6261, 5.86 }, { 1108, 54.6217, -6.6083, 5.85 }, + { 1109, 52.4950, -77.6481, 5.70 }, { 1110, 54.8571, +16.5367, 6.16 }, { 1111, 54.7546, -4.3739, 5.96 }, { 1112, 55.6779, +59.9694, 5.76 }, + { 1113, 55.2829, +37.5800, 5.57 }, { 1114, 54.6987, -26.0569, 6.01 }, { 1115, 54.9629, +3.0569, 5.57 }, { 1116, 54.9096, -2.6069, 6.23 }, + { 1117, 54.8558, -9.5628, 6.19 }, { 1118, 55.1929, +25.3294, 6.11 }, { 1119, 54.9979, -0.8794, 6.12 }, { 1120, 55.0475, -14.7733, 6.33 }, + { 1121, 55.1596, -4.7894, 5.53 }, { 1122, 55.7313, +47.7875, 3.01 }, { 1123, 55.5938, +33.9650, 4.97 }, { 1124, 56.5037, +67.2017, 5.80 }, + { 1125, 55.3075, -10.1969, 6.49 }, { 1126, 55.5787, +19.7003, 5.69 }, { 1127, 56.0267, +48.5236, 6.06 }, { 1128, 55.3433, -18.4153, 6.59 }, + { 1129, 56.5096, +63.3450, 4.80 }, { 1130, 56.1704, +46.0997, 6.11 }, { 1131, 56.0796, +32.2883, 3.83 }, { 1132, 55.9467, +19.6650, 6.14 }, + { 1133, 56.1308, +36.4600, 5.59 }, { 1134, 55.5621, -30.0617, 5.00 }, { 1135, 56.2983, +42.5786, 3.77 }, { 1136, 55.8121, -8.2367, 3.54 }, + { 1137, 56.1171, +20.9286, 6.10 }, { 1138, 57.3075, +70.8711, 5.44 }, { 1139, 55.8908, -9.5144, 5.60 }, { 1140, 56.2008, +24.2894, 5.46 }, + { 1141, 56.4971, +45.6819, 5.66 }, { 1142, 56.2188, +24.1133, 3.70 }, { 1143, 55.7088, -36.6864, 4.59 }, { 1144, 56.2904, +24.8392, 5.64 }, + { 1145, 56.3021, +24.4672, 4.30 }, { 1146, 56.1271, -0.8369, 5.25 }, { 1147, 56.8842, +55.9225, 6.10 }, { 1148, 57.5896, +71.3322, 4.63 }, + { 1149, 56.4567, +24.3678, 3.87 }, { 1150, 56.2354, +0.2967, 5.55 }, { 1151, 56.4767, +24.5547, 5.76 }, { 1152, 56.5121, +24.5281, 6.43 }, + { 1153, 56.4183, +6.0500, 5.35 }, { 1154, 54.1250, -77.6769, 6.29 }, { 1155, 57.3800, +65.5261, 4.47 }, { 1156, 56.5817, +23.9483, 4.18 }, + { 1157, 56.0258, -39.3397, 6.45 }, { 1158, 57.4029, +63.2972, 5.85 }, { 1159, 56.5396, +6.8031, 5.91 }, { 1160, 57.0763, +50.7367, 6.14 }, + { 1161, 57.3317, +57.1181, 6.46 }, { 1162, 56.5354, -11.8983, 4.42 }, { 1163, 56.9692, +33.6000, 6.57 }, { 1164, 56.9537, +32.1950, 6.25 }, + { 1165, 56.8713, +24.1050, 2.87 }, { 1166, 57.9242, +68.5075, 6.32 }, { 1167, 56.2108, -47.9386, 6.49 }, { 1168, 56.1408, -53.7261, 6.30 }, + { 1169, 56.3158, -46.6403, 5.73 }, { 1170, 57.2842, +43.9631, 6.02 }, { 1171, 56.6142, -28.6619, 5.90 }, { 1172, 57.0871, +23.4211, 5.45 }, + { 1173, 56.7121, -22.7503, 4.23 }, { 1174, 57.0679, +11.1433, 5.07 }, { 1175, 56.0500, -63.1931, 3.85 }, { 1176, 57.5187, +44.9678, 5.66 }, + { 1177, 57.3858, +33.0914, 5.11 }, { 1178, 57.2904, +24.0533, 3.63 }, { 1179, 56.8338, -28.0981, 6.55 }, { 1180, 57.2967, +24.1367, 5.09 }, + { 1181, 56.9150, -22.1253, 5.24 }, { 1182, 57.1621, +0.2278, 5.91 }, { 1183, 57.4312, +23.7117, 6.17 }, { 1184, 56.9833, -29.8322, 5.54 }, + { 1185, 57.4792, +22.2444, 6.07 }, { 1186, 56.9567, -35.8942, 6.21 }, { 1187, 57.1492, -19.0969, 5.81 }, { 1188, 57.5787, +25.5794, 5.26 }, + { 1189, 57.1475, -36.3778, 5.40 }, { 1190, 57.1496, -36.3794, 4.73 }, { 1191, 57.9738, +34.3592, 5.77 }, { 1192, 58.4304, +57.9750, 5.80 }, + { 1193, 57.9025, +22.0317, 6.83 }, { 1194, 57.8158, +13.0458, 6.30 }, { 1195, 57.3638, -35.7997, 4.17 }, { 1196, 59.1258, +71.8217, 6.34 }, + { 1197, 58.0179, +31.1683, 6.25 }, { 1198, 58.4113, +48.6506, 5.76 }, { 1199, 58.0008, +6.5347, 5.67 }, { 1200, 57.6567, -35.5747, 6.86 }, + { 1201, 58.2917, +17.3269, 5.97 }, { 1202, 58.1733, -4.6386, 5.48 }, { 1203, 58.5329, +31.8836, 2.85 }, { 1204, 59.3563, +63.0722, 5.03 }, + { 1205, 59.2846, +61.1089, 5.00 }, { 1206, 58.3042, -17.5656, 6.22 }, { 1207, 58.9925, +47.8714, 5.37 }, { 1208, 56.8096, -73.7611, 3.24 }, + { 1209, 58.8458, +31.0458, 6.10 }, { 1210, 59.1521, +50.6953, 5.28 }, { 1211, 58.5725, -1.0472, 6.14 }, { 1212, 58.5729, -1.0453, 4.79 }, + { 1213, 58.4275, -23.3875, 4.65 }, { 1214, 58.4121, -33.2678, 5.11 }, { 1215, 59.1196, +35.0811, 5.49 }, { 1216, 58.3888, -45.1064, 5.93 }, + { 1217, 58.8179, -11.9008, 6.00 }, { 1218, 59.2171, +22.4781, 5.63 }, { 1219, 58.5967, -39.6428, 5.71 }, { 1220, 59.4633, +40.0103, 2.89 }, + { 1221, 59.2658, +23.1756, 6.06 }, { 1222, 59.3600, +24.4619, 6.16 }, { 1223, 59.5129, +34.8144, 6.53 }, { 1224, 59.2571, +6.0400, 6.09 }, + { 1225, 59.1579, -8.2492, 6.19 }, { 1226, 59.6213, +38.8403, 6.30 }, { 1227, 58.6417, -51.3094, 6.46 }, { 1228, 59.7413, +35.7911, 4.04 }, + { 1229, 59.9167, +38.8206, 6.38 }, { 1230, 62.5117, +80.6986, 5.10 }, { 1231, 59.5075, -12.4914, 2.95 }, { 1232, 59.7179, -4.5300, 5.83 }, + { 1233, 59.9196, +10.3308, 6.37 }, { 1234, 60.3113, +36.9900, 6.41 }, { 1235, 59.8754, -11.4258, 5.60 }, { 1236, 59.0167, -62.5364, 6.14 }, + { 1237, 60.1538, +17.2967, 6.32 }, { 1238, 60.2033, +18.1939, 5.89 }, { 1239, 60.1700, +12.4903, 3.47 }, { 1240, 59.9813, -23.9836, 4.66 }, + { 1241, 61.5129, +68.6800, 5.87 }, { 1242, 61.1133, +59.1556, 5.06 }, { 1243, 60.4421, +9.9978, 5.67 }, { 1244, 60.3833, -0.4503, 5.28 }, + { 1245, 59.6788, -56.8975, 6.05 }, { 1246, 60.1696, -29.5092, 5.93 }, { 1247, 59.6863, -60.5997, 4.56 }, { 1248, 61.6625, +65.5208, 6.17 }, + { 1249, 60.6529, +0.2689, 5.38 }, { 1250, 60.0654, -50.4353, 6.51 }, { 1251, 60.7892, +5.9892, 3.91 }, { 1252, 61.0904, +24.1058, 5.47 }, + { 1253, 60.9358, +5.4356, 5.33 }, { 1254, 60.9858, +8.1972, 5.46 }, { 1255, 61.6525, +54.0086, 6.31 }, { 1256, 61.1737, +22.0819, 4.36 }, + { 1257, 61.0412, +2.8269, 5.36 }, { 1258, 60.8529, -19.8558, 6.46 }, { 1259, 60.9033, -19.8417, 7.01 }, { 1260, 61.9629, +62.3300, 6.99 }, + { 1261, 61.6458, +50.3514, 4.29 }, { 1262, 61.3342, +22.0089, 5.90 }, { 1263, 61.0363, -15.4111, 6.39 }, { 1264, 60.2242, -61.8406, 4.51 }, + { 1265, 61.0946, -11.2075, 5.61 }, { 1266, 60.3258, -60.9211, 4.97 }, { 1267, 61.1708, -19.6183, 6.13 }, { 1268, 61.6517, +27.6000, 5.20 }, + { 1269, 61.7521, +29.0014, 5.23 }, { 1270, 62.3650, +59.9081, 6.28 }, { 1271, 55.6337, -84.7378, 6.41 }, { 1272, 61.4854, -7.1439, 6.26 }, + { 1273, 62.1654, +47.7125, 4.04 }, { 1274, 61.4446, -19.4878, 6.34 }, { 1275, 61.4058, -26.3483, 5.59 }, { 1276, 62.3433, +54.8289, 6.18 }, + { 1277, 62.0637, +37.7278, 6.09 }, { 1278, 62.1525, +38.0397, 5.51 }, { 1279, 61.9250, +15.1628, 6.01 }, { 1280, 61.9975, +17.3397, 5.89 }, + { 1281, 63.4371, +72.1264, 6.03 }, { 1282, 63.2150, +68.5017, 6.32 }, { 1283, 62.2917, +19.6092, 5.50 }, { 1284, 62.2567, +13.3983, 5.95 }, + { 1285, 61.8546, -41.0831, 6.59 }, { 1286, 62.7458, +33.5867, 5.72 }, { 1287, 62.7079, +26.4808, 5.41 }, { 1288, 62.3242, -15.6142, 5.37 }, + { 1289, 67.0542, +83.8078, 5.57 }, { 1290, 62.5938, -5.0761, 5.44 }, { 1291, 62.1412, -44.1353, 6.59 }, { 1292, 62.8346, +5.5231, 5.72 }, + { 1293, 62.6987, -7.1803, 5.70 }, { 1294, 61.8400, -63.7775, 6.38 }, { 1295, 63.1308, +17.2775, 6.09 }, { 1296, 63.7575, +57.4603, 6.08 }, + { 1297, 63.2133, +22.4136, 6.12 }, { 1298, 62.9663, -5.1625, 4.04 }, { 1299, 62.6908, -34.7261, 6.44 }, { 1300, 62.9008, -19.6439, 5.79 }, + { 1301, 63.4983, +37.9669, 6.45 }, { 1302, 62.7108, -40.0064, 4.93 }, { 1303, 63.7246, +48.4094, 4.14 }, { 1304, 67.5004, +83.3406, 5.46 }, + { 1305, 64.2233, +61.8503, 5.70 }, { 1306, 63.7221, +40.4836, 4.71 }, { 1307, 63.3950, +10.2122, 6.23 }, { 1308, 63.3804, +8.8906, 6.51 }, + { 1309, 63.3879, +7.7161, 5.29 }, { 1310, 63.4579, +12.7533, 6.25 }, { 1311, 63.4850, +9.2636, 4.84 }, { 1312, 63.4092, -0.8503, 6.44 }, + { 1313, 64.2842, +57.8606, 5.71 }, { 1314, 64.1796, +53.6119, 5.19 }, { 1315, 63.6512, +10.0111, 5.22 }, { 1316, 63.1317, -43.6317, 6.71 }, + { 1317, 66.7617, +80.8242, 5.43 }, { 1318, 63.5988, -9.7436, 4.87 }, { 1319, 63.9429, +15.4006, 6.32 }, { 1320, 63.8837, +8.8922, 4.29 }, + { 1321, 63.8575, +6.1997, 6.93 }, { 1322, 63.8717, +6.1867, 6.31 }, { 1323, 63.3988, -39.6422, 6.37 }, { 1324, 64.5608, +50.2956, 4.61 }, + { 1325, 63.8179, -6.3472, 4.43 }, { 1326, 63.5004, -41.7056, 3.86 }, { 1327, 65.1679, +65.1406, 5.27 }, { 1328, 64.5342, +42.1411, 6.22 }, + { 1329, 64.3150, +20.5786, 4.94 }, { 1330, 64.8054, +50.0489, 5.45 }, { 1331, 64.5967, +21.5792, 5.65 }, { 1332, 64.3300, -5.5281, 5.94 }, + { 1333, 65.0479, +50.9208, 5.55 }, { 1334, 64.6021, +9.4867, 6.54 }, { 1335, 65.4483, +60.7356, 5.39 }, { 1336, 63.6063, -61.5261, 3.35 }, + { 1337, 65.0600, +41.8081, 5.92 }, { 1338, 64.0067, -50.5133, 4.25 }, { 1339, 64.8588, +21.1422, 5.35 }, { 1340, 63.7029, -61.8081, 5.45 }, + { 1341, 64.9029, +21.7736, 5.38 }, { 1342, 65.4658, +56.5067, 5.88 }, { 1343, 65.1025, +34.5667, 4.93 }, { 1344, 65.0417, +31.9533, 6.16 }, + { 1345, 64.5662, -19.2844, 6.00 }, { 1346, 64.9483, +15.6275, 3.65 }, { 1347, 64.4737, -32.2017, 3.56 }, { 1348, 65.0888, +27.3508, 4.95 }, + { 1349, 64.9063, +10.1214, 6.31 }, { 1350, 65.3883, +46.4989, 4.85 }, { 1351, 64.9904, +14.0353, 5.59 }, { 1352, 65.7412, +59.6164, 6.19 }, + { 1353, 64.6558, -21.0297, 6.07 }, { 1354, 65.1046, +18.7425, 6.12 }, { 1355, 64.1204, -58.6981, 4.44 }, { 1356, 65.1513, +15.0953, 5.26 }, + { 1357, 64.0879, -59.0514, 6.37 }, { 1358, 65.2200, +13.8642, 6.17 }, { 1359, 64.7625, -32.0950, 6.37 }, { 1360, 65.1717, +6.1308, 5.77 }, + { 1361, 65.2042, +9.2256, 6.53 }, { 1362, 65.1612, -5.7544, 6.27 }, { 1363, 65.1783, -6.4075, 5.85 }, { 1364, 64.8192, -43.7319, 5.34 }, + { 1365, 64.6667, -51.1400, 6.09 }, { 1366, 65.3629, +0.0981, 5.86 }, { 1367, 65.1625, -19.3603, 5.38 }, { 1368, 65.5146, +14.0772, 5.72 }, + { 1369, 65.6454, +25.6292, 5.37 }, { 1370, 65.5950, +20.8214, 5.91 }, { 1371, 65.8996, +42.4281, 6.23 }, { 1372, 64.4175, -62.7444, 5.87 }, + { 1373, 65.7338, +17.5425, 3.76 }, { 1374, 65.3804, -24.2717, 6.01 }, { 1375, 65.8850, +20.9822, 5.99 }, { 1376, 65.8542, +16.7772, 5.64 }, + { 1377, 66.1217, +34.1306, 5.73 }, { 1378, 65.9992, +24.3011, 6.36 }, { 1379, 66.1558, +33.9597, 5.76 }, { 1380, 66.0242, +17.4439, 4.80 }, + { 1381, 65.9663, +9.4608, 5.12 }, { 1382, 66.7537, +57.5853, 6.32 }, { 1383, 65.9200, -2.2544, 5.17 }, { 1384, 65.7738, -23.1078, 5.83 }, + { 1385, 66.2379, +19.0417, 5.98 }, { 1386, 65.7821, -34.4550, 6.39 }, { 1387, 66.3421, +22.2939, 4.22 }, { 1388, 66.3542, +22.1997, 5.28 }, + { 1389, 66.3725, +17.9281, 4.29 }, { 1390, 66.5263, +31.4389, 5.28 }, { 1391, 66.4054, +15.9408, 6.46 }, { 1392, 66.5771, +22.8136, 4.28 }, + { 1393, 66.0092, -33.9831, 3.96 }, { 1394, 66.5867, +15.6183, 4.49 }, { 1395, 65.4721, -62.6136, 5.24 }, { 1396, 66.6517, +14.7136, 4.69 }, + { 1397, 66.5879, +8.5903, 6.06 }, { 1398, 66.2350, -33.2422, 6.55 }, { 1399, 66.8229, +22.9964, 5.53 }, { 1400, 66.7529, +2.0794, 6.23 }, + { 1401, 68.3779, +72.5286, 5.94 }, { 1402, 66.8700, +11.2125, 5.88 }, { 1403, 67.0033, +21.6200, 5.72 }, { 1404, 66.3296, -43.8392, 6.39 }, + { 1405, 66.0508, -56.9286, 6.29 }, { 1406, 67.2163, +30.3614, 6.40 }, { 1407, 67.1100, +16.3597, 4.97 }, { 1408, 67.0975, +14.7408, 5.90 }, + { 1409, 67.1542, +19.1803, 3.53 }, { 1410, 66.7375, -23.9186, 6.11 }, { 1411, 67.1437, +15.9622, 3.84 }, { 1412, 67.1654, +15.8708, 3.40 }, + { 1413, 67.0150, +1.8586, 6.15 }, { 1414, 67.2092, +13.0475, 5.03 }, { 1415, 67.1338, +1.3808, 5.55 }, { 1416, 66.2721, -60.7617, 5.94 }, + { 1417, 68.0075, +53.9108, 5.77 }, { 1418, 66.7750, -45.0525, 6.10 }, { 1419, 67.6596, +32.4581, 6.21 }, { 1420, 67.4287, +10.5217, 6.79 }, + { 1421, 67.1625, -18.5417, 5.96 }, { 1422, 67.5358, +15.6381, 5.58 }, { 1423, 67.2788, -12.9517, 5.60 }, { 1424, 67.8500, +40.0103, 6.26 }, + { 1425, 67.5100, +10.2625, 6.48 }, { 1426, 64.4963, -79.7861, 5.69 }, { 1427, 67.6404, +16.1939, 4.78 }, { 1428, 67.6621, +15.6919, 5.48 }, + { 1429, 67.0392, -40.0400, 6.44 }, { 1430, 67.6554, +13.7244, 5.40 }, { 1431, 67.5404, -12.4078, 6.24 }, { 1432, 67.9658, +15.8517, 6.02 }, + { 1433, 67.3333, -45.4847, 6.16 }, { 1434, 68.3538, +43.0639, 6.09 }, { 1435, 66.9412, -61.4792, 5.75 }, { 1436, 68.0200, +5.4100, 6.39 }, + { 1437, 67.9696, +0.0439, 4.91 }, { 1438, 67.8579, -12.3550, 6.21 }, { 1439, 67.6679, -34.3464, 5.96 }, { 1440, 69.1008, +64.2617, 5.94 }, + { 1441, 68.1558, -2.7908, 5.81 }, { 1442, 68.3871, +18.0167, 6.25 }, { 1443, 67.7087, -43.0461, 5.07 }, { 1444, 68.4621, +14.8444, 4.65 }, + { 1445, 68.6583, +28.9611, 5.88 }, { 1446, 68.4504, +9.4131, 6.01 }, { 1447, 68.3417, -9.2142, 6.06 }, { 1448, 68.5346, +5.5686, 5.68 }, + { 1449, 68.4783, -5.2611, 5.72 }, { 1450, 68.5592, -5.1622, 6.09 }, { 1451, 68.5483, -7.7686, 5.11 }, { 1452, 68.5487, -7.0297, 5.26 }, + { 1453, 68.3775, -28.2333, 4.51 }, { 1454, 69.1725, +41.2647, 4.25 }, { 1455, 68.9279, +19.8817, 6.36 }, { 1456, 65.2412, -80.4200, 5.79 }, + { 1457, 68.9800, +16.5092, 0.85 }, { 1458, 68.9137, +10.1608, 4.25 }, { 1459, 69.1217, +23.3408, 6.02 }, { 1460, 68.8083, -8.2633, 6.37 }, + { 1461, 68.7521, -18.0794, 6.13 }, { 1462, 69.0067, -2.3881, 6.33 }, { 1463, 69.0796, -2.6475, 3.93 }, { 1464, 68.8875, -29.4378, 3.82 }, + { 1465, 68.4992, -54.9550, 3.27 }, { 1466, 69.9921, +53.4731, 5.35 }, { 1467, 69.9779, +53.0797, 5.05 }, { 1468, 71.5012, +76.6111, 6.49 }, + { 1469, 69.3071, +0.9983, 5.31 }, { 1470, 69.6233, +26.9400, 6.47 }, { 1471, 69.5658, +20.6847, 5.92 }, { 1472, 69.5392, +16.0333, 5.79 }, + { 1473, 69.5396, +12.5108, 4.27 }, { 1474, 69.4004, -1.5267, 5.23 }, { 1475, 68.3917, -61.1764, 5.79 }, { 1476, 69.2121, -29.2833, 6.30 }, + { 1477, 69.8462, +25.2183, 6.22 }, { 1478, 69.7883, +15.7997, 5.07 }, { 1479, 69.8187, +15.9181, 4.69 }, { 1480, 69.7758, +7.8708, 5.39 }, + { 1481, 69.5450, -13.6961, 3.87 }, { 1482, 70.3504, +48.3008, 5.67 }, { 1483, 69.7233, -11.8769, 5.01 }, { 1484, 70.0142, +12.1978, 5.46 }, + { 1485, 65.7121, -81.1008, 6.76 }, { 1486, 70.8254, +59.5208, 6.50 }, { 1487, 69.8321, -13.6408, 5.45 }, { 1488, 69.9467, -0.9472, 6.10 }, + { 1489, 70.4596, +38.2803, 5.99 }, { 1490, 70.3325, +28.6150, 5.78 }, { 1491, 72.2096, +75.9411, 6.06 }, { 1492, 69.1900, -61.9225, 5.40 }, + { 1493, 70.8400, +49.9739, 5.87 }, { 1494, 70.7262, +43.3650, 5.29 }, { 1495, 70.0283, -23.5175, 5.58 }, { 1496, 70.1104, -18.3283, 4.32 }, + { 1497, 70.5613, +22.9569, 4.28 }, { 1498, 69.7679, -50.3272, 6.44 }, { 1499, 70.8075, +24.0889, 6.13 }, { 1500, 71.0537, +40.7869, 6.08 }, + { 1501, 70.9513, +32.8653, 6.45 }, { 1502, 70.1404, -40.1361, 4.45 }, { 1503, 70.5146, -36.8556, 5.05 }, { 1504, 70.0763, -57.0564, 6.53 }, + { 1505, 70.8942, -7.2064, 6.82 }, { 1506, 70.8962, -7.2039, 6.70 }, { 1507, 71.1075, +11.1461, 5.40 }, { 1508, 71.0221, -7.4964, 5.90 }, + { 1509, 70.7887, -29.2344, 5.68 }, { 1510, 72.6517, +70.9417, 6.37 }, { 1511, 72.0012, +56.7572, 5.30 }, { 1512, 71.4271, +23.6281, 6.35 }, + { 1513, 71.0333, -17.3333, 5.53 }, { 1514, 71.6850, +40.3128, 5.97 }, { 1515, 72.0292, +55.6025, 6.26 }, { 1516, 70.6933, -49.5186, 5.31 }, + { 1517, 71.5700, +18.7350, 6.01 }, { 1518, 70.9342, -40.9353, 6.25 }, { 1519, 71.5071, +11.7056, 5.37 }, { 1520, 71.3754, -2.7453, 4.02 }, + { 1521, 71.2675, -20.7164, 5.72 }, { 1522, 71.6004, -1.0456, 6.33 }, { 1523, 75.0863, +81.1939, 5.07 }, { 1524, 71.4567, -33.9950, 6.86 }, + { 1525, 71.6075, -27.9125, 6.19 }, { 1526, 71.4808, -38.6433, 6.05 }, { 1527, 73.0217, +63.5053, 5.44 }, { 1528, 72.3292, +32.5883, 5.86 }, + { 1529, 72.3033, +31.4372, 5.58 }, { 1530, 71.0879, -58.2672, 5.27 }, { 1531, 69.5904, -76.3439, 6.05 }, { 1532, 71.9013, -15.0656, 5.51 }, + { 1533, 72.4775, +37.4883, 4.88 }, { 1534, 72.1858, +3.5883, 6.03 }, { 1535, 72.7887, +48.7408, 5.66 }, { 1536, 72.1513, -4.3261, 5.78 }, + { 1537, 72.4338, +15.9042, 6.08 }, { 1538, 72.1354, -15.6706, 5.77 }, { 1539, 71.9567, -29.9797, 6.37 }, { 1540, 71.2412, -62.7703, 6.46 }, + { 1541, 70.7662, -69.0689, 5.54 }, { 1542, 73.5125, +66.3428, 4.29 }, { 1543, 72.4600, +6.9614, 3.19 }, { 1544, 72.6529, +8.9003, 4.36 }, + { 1545, 72.4258, -12.2303, 6.26 }, { 1546, 73.2908, +52.8408, 6.41 }, { 1547, 72.8438, +18.8397, 5.10 }, { 1548, 72.1408, -42.0200, 6.72 }, + { 1549, 72.5483, -15.7828, 5.03 }, { 1550, 73.1992, +42.5867, 5.71 }, { 1551, 73.1583, +36.7031, 4.78 }, { 1552, 72.8017, +5.6050, 3.69 }, + { 1553, 72.9308, +9.9750, 6.11 }, { 1554, 73.1963, +27.8975, 5.97 }, { 1555, 73.7629, +55.2592, 5.52 }, { 1556, 73.1333, +14.2506, 4.74 }, + { 1557, 72.5675, -40.6792, 6.07 }, { 1558, 73.7138, +44.0608, 6.08 }, { 1559, 72.8675, -33.0936, 5.86 }, { 1560, 73.2237, -4.5472, 4.39 }, + { 1561, 74.0296, +52.8694, 5.75 }, { 1562, 73.3450, +2.5081, 5.33 }, { 1563, 72.7300, -52.5386, 5.61 }, { 1564, 72.7346, -52.5403, 6.42 }, + { 1565, 73.4825, +1.5694, 6.61 }, { 1566, 73.7429, +19.4853, 6.37 }, { 1567, 73.5629, +2.4406, 3.72 }, { 1568, 74.3217, +53.7522, 4.47 }, + { 1569, 73.6954, +11.4261, 5.19 }, { 1570, 73.7242, +10.1508, 4.65 }, { 1571, 73.6992, +7.7792, 5.33 }, { 1572, 75.5837, +74.2692, 6.06 }, + { 1573, 74.0829, +36.1689, 6.07 }, { 1574, 73.7113, +0.4675, 5.99 }, { 1575, 74.0650, +24.5922, 6.37 }, { 1576, 73.9596, +15.0400, 5.81 }, + { 1577, 74.2483, +33.1661, 2.69 }, { 1578, 73.9933, +5.3992, 6.50 }, { 1579, 73.7783, -15.2594, 5.70 }, { 1580, 74.0929, +13.5144, 4.07 }, + { 1581, 73.8275, -15.5822, 5.72 }, { 1582, 74.1008, -4.8286, 5.51 }, { 1583, 73.8758, -24.2722, 6.72 }, { 1584, 73.7283, -38.3714, 6.10 }, + { 1585, 74.3429, +17.1536, 5.48 }, { 1586, 74.4529, +23.9486, 5.79 }, { 1587, 76.0542, +73.7639, 6.66 }, { 1588, 74.9429, +53.1556, 6.08 }, + { 1589, 76.1658, +74.0669, 5.96 }, { 1590, 74.5392, +25.0503, 5.81 }, { 1591, 74.3217, -0.9328, 6.23 }, { 1592, 74.8142, +37.8903, 4.94 }, + { 1593, 75.3996, +61.0781, 6.03 }, { 1594, 75.7100, +66.8228, 6.19 }, { 1595, 74.4367, -13.7686, 6.15 }, { 1596, 74.5450, -1.7875, 6.35 }, + { 1597, 73.7208, -57.4528, 6.12 }, { 1598, 73.3771, -65.3244, 6.41 }, { 1599, 75.0763, +39.3947, 5.95 }, { 1600, 74.7475, +14.5428, 6.09 }, + { 1601, 74.6371, +1.7142, 4.47 }, { 1602, 75.0967, +39.6550, 6.58 }, { 1603, 75.8546, +60.4422, 4.03 }, { 1604, 74.7554, -15.6242, 5.66 }, + { 1605, 75.4921, +43.8233, 2.99 }, { 1606, 73.2729, -71.5925, 6.28 }, { 1607, 74.9021, -13.1942, 7.71 }, { 1608, 74.9600, -9.7367, 5.38 }, + { 1609, 75.1358, +3.6153, 7.03 }, { 1610, 75.1412, +3.6161, 6.66 }, { 1611, 74.9825, -11.4625, 4.79 }, { 1612, 75.6196, +41.0758, 3.75 }, + { 1613, 75.1658, -1.9344, 6.32 }, { 1614, 75.2042, -4.2467, 6.22 }, { 1615, 75.8275, +41.4417, 6.14 }, { 1616, 82.9500, +85.9386, 6.51 }, + { 1617, 75.3596, -6.8261, 4.81 }, { 1618, 75.4596, +0.7222, 5.92 }, { 1619, 75.5000, +1.6089, 6.24 }, { 1620, 75.7738, +21.5900, 4.64 }, + { 1621, 75.3567, -19.9481, 4.91 }, { 1622, 76.5354, +58.9725, 5.08 }, { 1623, 76.5508, +59.0211, 6.08 }, { 1624, 76.6238, +61.1700, 6.04 }, + { 1625, 75.6896, -3.7903, 5.85 }, { 1626, 76.0604, +30.4947, 6.14 }, { 1627, 76.1538, +32.3203, 6.62 }, { 1628, 75.5408, -25.7250, 5.02 }, + { 1629, 73.7967, -73.0631, 5.47 }, { 1630, 76.5917, +54.4058, 7.24 }, { 1631, 75.3937, -38.2819, 6.03 }, { 1632, 76.1579, +27.6961, 6.60 }, + { 1633, 76.0900, +21.2781, 6.19 }, { 1634, 75.6871, -21.2050, 5.75 }, { 1635, 75.5950, -30.2286, 5.94 }, { 1636, 77.4029, +69.6394, 6.41 }, + { 1637, 76.6692, +51.5978, 5.00 }, { 1638, 76.1421, +15.4042, 4.68 }, { 1639, 76.5037, +35.9364, 6.52 }, { 1640, 75.9667, -13.6306, 6.41 }, + { 1641, 76.6287, +41.2344, 3.17 }, { 1642, 76.3838, +19.8064, 6.44 }, { 1643, 78.0933, +73.9467, 5.43 }, { 1644, 76.7067, +43.1747, 6.20 }, + { 1645, 75.9721, -23.6122, 5.61 }, { 1646, 76.2271, -2.9603, 6.05 }, { 1647, 77.4354, +64.9194, 6.41 }, { 1648, 76.3487, +1.1775, 6.17 }, + { 1649, 75.7025, -48.8486, 5.38 }, { 1650, 78.6483, +76.4728, 6.37 }, { 1651, 75.9750, -40.2550, 6.31 }, { 1652, 76.1017, -34.5167, 4.55 }, + { 1653, 76.1088, -34.2947, 6.34 }, { 1654, 76.3654, -21.6289, 3.19 }, { 1655, 76.3175, -25.8475, 5.73 }, { 1656, 76.8625, +18.6450, 5.00 }, + { 1657, 76.6904, -3.3450, 5.12 }, { 1658, 76.9517, +20.4183, 5.30 }, { 1659, 77.0275, +24.2653, 5.50 }, { 1660, 76.9813, +21.7047, 5.89 }, + { 1661, 76.6529, -12.8781, 6.05 }, { 1662, 76.9096, +9.4719, 6.17 }, { 1663, 76.2417, -48.4222, 5.03 }, { 1664, 76.9704, +8.4983, 5.34 }, + { 1665, 76.8542, -11.5094, 5.97 }, { 1666, 76.9625, -4.9136, 2.79 }, { 1667, 76.2525, -53.5925, 6.27 }, { 1668, 77.6787, +46.9622, 5.68 }, + { 1669, 77.5787, +37.3019, 6.02 }, { 1670, 77.4379, +28.0306, 6.01 }, { 1671, 77.0842, -7.3350, 5.78 }, { 1672, 77.3317, +9.8294, 5.43 }, + { 1673, 77.1817, -3.5439, 5.12 }, { 1674, 76.3775, -56.5272, 4.72 }, { 1675, 78.2633, +61.8500, 6.17 }, { 1676, 77.4250, +15.5972, 4.82 }, + { 1677, 75.6792, -70.6856, 5.31 }, { 1678, 78.3804, +62.6914, 6.50 }, { 1679, 77.2867, -7.2458, 4.27 }, { 1680, 77.0617, -34.2817, 6.52 }, + { 1681, 77.5133, +0.5653, 6.10 }, { 1682, 75.0550, -77.6997, 6.29 }, { 1683, 79.5554, +73.2681, 5.74 }, { 1684, 77.9233, +16.0456, 5.18 }, + { 1685, 77.7417, -1.7461, 6.25 }, { 1686, 80.6396, +79.2311, 5.05 }, { 1687, 77.8300, -1.5092, 5.90 }, { 1688, 78.7971, +59.4056, 6.15 }, + { 1689, 78.3571, +38.4844, 4.86 }, { 1690, 77.9225, +0.5147, 6.67 }, { 1691, 77.9387, +1.0369, 5.89 }, { 1692, 78.6846, +53.2139, 6.20 }, + { 1693, 77.8450, -10.1508, 5.68 }, { 1694, 77.6854, -24.0906, 6.41 }, { 1695, 76.8917, -62.6003, 5.20 }, { 1696, 78.0746, -10.1308, 4.45 }, + { 1697, 78.2008, -5.9428, 5.91 }, { 1698, 78.3229, +2.8611, 4.46 }, { 1699, 77.8996, -36.6047, 6.57 }, { 1700, 76.5387, -72.9622, 6.27 }, + { 1701, 78.3817, +1.9681, 6.09 }, { 1702, 78.2329, -15.7944, 3.31 }, { 1703, 78.4467, +0.5603, 6.32 }, { 1704, 78.3888, -7.8522, 6.37 }, + { 1705, 78.3079, -11.0586, 4.36 }, { 1706, 78.8517, +32.6878, 5.02 }, { 1707, 79.3242, +53.5861, 6.50 }, { 1708, 79.1725, +45.9981, 0.08 }, + { 1709, 78.6838, +5.1561, 5.50 }, { 1710, 78.4996, -13.3933, 6.21 }, { 1711, 78.8654, +22.2847, 6.27 }, { 1712, 79.0758, +34.3119, 5.96 }, + { 1713, 78.6346, -7.7983, 0.12 }, { 1714, 85.9529, +85.6681, 6.60 }, { 1715, 78.4437, -34.1744, 6.98 }, { 1716, 74.7121, -81.5294, 5.85 }, + { 1717, 78.8267, -0.5908, 6.15 }, { 1718, 79.0171, +11.3414, 5.56 }, { 1719, 79.8658, +58.1172, 6.13 }, { 1720, 80.0942, +62.6536, 5.61 }, + { 1721, 78.6200, -34.0228, 5.76 }, { 1722, 79.5662, +42.7922, 5.48 }, { 1723, 78.8512, -25.0567, 5.07 }, { 1724, 79.1713, +1.9472, 6.42 }, + { 1725, 79.6683, +40.4650, 6.18 }, { 1726, 79.5446, +33.3717, 4.54 }, { 1727, 78.4721, -51.9689, 6.05 }, { 1728, 79.5787, +33.7672, 6.14 }, + { 1729, 79.7854, +40.0992, 4.71 }, { 1730, 78.9458, -33.0733, 6.66 }, { 1731, 79.2004, -16.8583, 6.56 }, { 1732, 79.7500, +33.7483, 5.41 }, + { 1733, 80.0096, +44.4256, 6.62 }, { 1734, 79.8483, +33.9856, 6.49 }, { 1735, 79.4017, -5.1556, 3.60 }, { 1736, 80.1637, +46.9639, 6.54 }, + { 1737, 79.4175, -12.4803, 5.50 }, { 1738, 80.0617, +41.0861, 5.52 }, { 1739, 79.8192, +22.0964, 4.94 }, { 1740, 80.0037, +33.9581, 5.03 }, + { 1741, 79.8113, +20.1347, 6.08 }, { 1742, 78.9121, -51.8181, 6.49 }, { 1743, 79.3713, -33.1047, 4.83 }, { 1744, 78.4392, -66.8147, 4.83 }, + { 1745, 82.3571, +77.9775, 6.56 }, { 1746, 79.7967, +2.5958, 5.34 }, { 1747, 79.7100, -17.8700, 5.96 }, { 1748, 79.8967, -0.5878, 6.34 }, + { 1749, 80.4517, +41.8044, 5.23 }, { 1750, 80.2471, +27.9572, 6.33 }, { 1751, 80.8658, +57.5444, 5.28 }, { 1752, 80.3029, +29.5700, 5.76 }, + { 1753, 79.8229, -17.4800, 6.36 }, { 1754, 79.8263, -17.4903, 6.54 }, { 1755, 80.2358, +19.8142, 6.18 }, { 1756, 79.8937, -12.8233, 4.29 }, + { 1757, 79.9963, -11.6844, 5.30 }, { 1758, 79.8487, -26.6311, 5.99 }, { 1759, 80.1100, -4.6333, 6.39 }, { 1760, 80.7096, +41.0294, 5.54 }, + { 1761, 80.3304, +4.0119, 6.57 }, { 1762, 80.1121, -20.7606, 4.71 }, { 1763, 80.4317, +8.4286, 5.80 }, { 1764, 80.3825, +0.4164, 5.68 }, + { 1765, 80.4404, +0.3825, 4.73 }, { 1766, 80.0858, -33.3011, 6.34 }, { 1767, 79.8421, -49.3939, 5.45 }, { 1768, 80.8454, +28.9367, 6.46 }, + { 1769, 80.4625, -12.2439, 6.56 }, { 1770, 80.7083, +3.5444, 5.00 }, { 1771, 80.4425, -23.2269, 5.06 }, { 1772, 80.3204, -33.6547, 6.09 }, + { 1773, 81.1633, +37.3856, 4.99 }, { 1774, 80.9071, +16.6994, 6.08 }, { 1775, 81.1596, +31.2239, 6.28 }, { 1776, 81.1604, +31.1431, 5.94 }, + { 1777, 80.8796, +5.3225, 6.35 }, { 1778, 80.8271, -7.5842, 5.90 }, { 1779, 81.3042, +34.8553, 6.55 }, { 1780, 81.1058, +17.3833, 4.99 }, + { 1781, 80.9262, +0.1597, 5.70 }, { 1782, 80.9642, +0.8672, 6.11 }, { 1783, 80.8758, -12.0728, 5.25 }, { 1784, 80.9867, -6.1919, 4.14 }, + { 1785, 80.8000, -25.2942, 6.49 }, { 1786, 81.1508, +2.3528, 6.32 }, { 1787, 81.1204, +0.8914, 5.08 }, { 1788, 81.1192, -1.6031, 3.36 }, + { 1789, 81.1867, +1.8464, 4.95 }, { 1790, 81.2829, +6.3497, 1.64 }, { 1791, 81.5729, +28.6075, 1.65 }, { 1792, 81.1183, -15.0239, 5.65 }, + { 1793, 80.8500, -38.3214, 5.71 }, { 1794, 81.7262, +35.4572, 6.15 }, { 1795, 81.7037, +34.3917, 5.94 }, { 1796, 81.7138, +33.2628, 6.15 }, + { 1797, 80.9125, -36.6633, 6.82 }, { 1798, 81.5238, +16.7003, 6.25 }, { 1799, 81.2567, -9.6708, 5.61 }, { 1800, 81.3800, +0.5442, 6.57 }, + { 1801, 80.5921, -55.8656, 6.11 }, { 1802, 82.5425, +63.0672, 5.42 }, { 1803, 81.4458, +0.5208, 6.16 }, { 1804, 81.7846, +30.2086, 5.74 }, + { 1805, 81.9121, +34.4758, 5.07 }, { 1806, 81.5100, -4.4817, 6.23 }, { 1807, 81.6617, +6.8692, 6.42 }, { 1808, 81.7921, +17.9622, 5.42 }, + { 1809, 81.8075, +15.2578, 6.16 }, { 1810, 81.9087, +21.9369, 4.88 }, { 1811, 81.7092, +3.0956, 4.59 }, { 1812, 81.4992, -18.3044, 5.89 }, + { 1813, 81.2317, -43.7742, 6.08 }, { 1814, 81.9400, +15.8742, 5.50 }, { 1815, 78.1071, -80.4583, 6.51 }, { 1816, 82.0067, +17.2389, 5.77 }, + { 1817, 81.7700, -10.0992, 6.35 }, { 1818, 81.1925, -51.6836, 6.27 }, { 1819, 82.1450, +13.6789, 6.35 }, { 1820, 82.0067, +1.2983, 6.41 }, + { 1821, 82.3187, +25.1506, 5.47 }, { 1822, 82.4192, +29.1864, 6.24 }, { 1823, 81.9021, -20.6244, 6.07 }, { 1824, 82.7025, +41.4619, 6.00 }, + { 1825, 82.6879, +39.8258, 6.37 }, { 1826, 82.2362, -2.6925, 6.39 }, { 1827, 81.7721, -39.0564, 5.87 }, { 1828, 83.1408, +57.2211, 6.48 }, + { 1829, 82.0613, -19.2406, 2.84 }, { 1830, 82.3483, -2.5536, 5.79 }, { 1831, 82.6808, +22.4625, 6.29 }, { 1832, 82.6088, +15.3603, 5.94 }, + { 1833, 82.4783, +1.7892, 5.78 }, { 1834, 82.4333, -0.9078, 4.71 }, { 1835, 82.0637, -36.7694, 5.57 }, { 1836, 81.5804, -57.0875, 5.14 }, + { 1837, 82.5825, +4.2042, 6.21 }, { 1838, 82.2779, -29.8833, 6.75 }, { 1839, 82.6963, +5.9481, 4.20 }, { 1840, 82.5863, -6.5653, 6.33 }, + { 1841, 0.0000, +0.0000, 0.00 }, { 1842, 82.8104, +3.2922, 5.46 }, { 1843, 83.1821, +32.1919, 4.76 }, { 1844, 84.9321, +75.0439, 6.17 }, + { 1845, 83.0533, +18.5944, 4.38 }, { 1846, 83.3696, +42.1089, 6.55 }, { 1847, 83.0592, +17.0581, 5.46 }, { 1848, 82.8371, -5.2917, 6.22 }, + { 1849, 82.7817, -19.1364, 5.55 }, { 1850, 83.3646, +32.8011, 6.48 }, { 1851, 83.0021, +0.2844, 6.85 }, { 1852, 83.0017, +0.2992, 2.23 }, + { 1853, 84.3175, +66.6961, 6.26 }, { 1854, 83.4083, +34.7258, 6.27 }, { 1855, 82.9825, -6.6986, 4.62 }, { 1856, 82.5396, -46.9222, 5.46 }, + { 1857, 84.3129, +64.1547, 6.15 }, { 1858, 83.3817, +18.5403, 5.69 }, { 1859, 81.7500, -67.3772, 6.03 }, { 1860, 83.4117, +20.4742, 6.18 }, + { 1861, 83.1721, -0.4081, 5.35 }, { 1862, 82.8029, -34.5294, 3.87 }, { 1863, 83.2800, -0.2817, 6.46 }, { 1864, 83.4762, +14.3056, 5.64 }, + { 1865, 83.1825, -16.1778, 2.58 }, { 1866, 84.1467, +54.4289, 5.73 }, { 1867, 82.3225, -61.6856, 6.59 }, { 1868, 83.3808, -0.8439, 5.34 }, + { 1869, 84.0662, +47.7153, 6.11 }, { 1870, 82.9004, -44.0747, 5.86 }, { 1871, 83.4900, +1.4078, 6.59 }, { 1872, 83.5696, +3.7669, 5.36 }, + { 1873, 83.5162, -0.9644, 6.22 }, { 1874, 83.5167, -0.5294, 5.93 }, { 1875, 83.8629, +24.0394, 5.38 }, { 1876, 83.7050, +9.4894, 4.41 }, + { 1877, 83.2138, -37.4869, 5.48 }, { 1878, 83.9813, +27.6622, 6.27 }, { 1879, 83.7846, +9.9342, 3.54 }, { 1880, 83.7854, +9.9350, 5.61 }, + { 1881, 83.2808, -34.8603, 5.78 }, { 1882, 82.5662, -62.0722, 6.19 }, { 1883, 83.8058, +10.2400, 5.60 }, { 1884, 84.2183, +40.1822, 6.09 }, + { 1885, 90.3342, +85.1822, 6.11 }, { 1886, 83.7537, -5.9908, 5.67 }, { 1887, 83.7613, -5.9981, 4.78 }, { 1888, 83.4671, -28.1511, 6.53 }, + { 1889, 84.1258, +25.9394, 6.49 }, { 1890, 83.8408, -3.5067, 6.56 }, { 1891, 83.8438, -3.5747, 6.24 }, { 1892, 83.8467, -3.1617, 4.59 }, + { 1893, 83.8162, -4.6128, 6.73 }, { 1894, 83.8171, -4.6147, 7.96 }, { 1895, 83.8187, -4.6103, 5.13 }, { 1896, 83.8221, -4.6122, 6.70 }, + { 1897, 83.8454, -4.5839, 5.08 }, { 1898, 83.8796, -3.6353, 6.38 }, { 1899, 83.8583, -4.0900, 2.77 }, { 1900, 83.8992, -2.7472, 6.40 }, + { 1901, 83.9146, -3.1442, 5.26 }, { 1902, 84.2867, +26.9242, 5.83 }, { 1903, 84.0533, -0.7981, 1.70 }, { 1904, 84.4404, +33.5592, 6.33 }, + { 1905, 84.2658, +17.0403, 5.54 }, { 1906, 84.0625, -4.3519, 6.54 }, { 1907, 84.2262, +9.2906, 4.09 }, { 1908, 84.2683, +11.0350, 5.94 }, + { 1909, 83.8142, -32.9200, 5.78 }, { 1910, 84.4112, +21.1425, 3.00 }, { 1911, 84.1488, -5.9350, 5.72 }, { 1912, 83.4350, -53.0978, 6.43 }, + { 1913, 84.3304, +8.9519, 6.12 }, { 1914, 84.6587, +30.4925, 5.40 }, { 1915, 84.0429, -27.2922, 6.26 }, { 1916, 85.6100, +65.6978, 5.60 }, + { 1917, 83.2483, -63.7725, 5.34 }, { 1918, 84.3642, -4.0617, 6.05 }, { 1919, 84.2867, -10.2244, 6.11 }, { 1920, 84.5046, +7.5414, 5.88 }, + { 1921, 84.7392, +26.6178, 6.37 }, { 1922, 83.4063, -61.5103, 3.76 }, { 1923, 84.4725, -3.1864, 6.19 }, { 1924, 84.8267, +29.2153, 5.96 }, + { 1925, 85.3346, +53.4811, 6.23 }, { 1926, 84.3187, -26.1286, 6.16 }, { 1927, 84.0113, -46.6861, 6.11 }, { 1928, 84.9342, +25.8969, 5.18 }, + { 1929, 84.8625, +21.7628, 6.34 }, { 1930, 83.7600, -57.1289, 6.75 }, { 1931, 84.6867, -1.4000, 3.81 }, { 1932, 84.6963, -1.4058, 6.65 }, + { 1933, 84.6575, -5.4261, 5.96 }, { 1934, 84.7963, +4.1214, 4.57 }, { 1935, 84.4358, -27.3106, 5.31 }, { 1936, 83.7400, -60.8242, 6.32 }, + { 1937, 84.7212, -6.7869, 4.80 }, { 1938, 85.1496, +31.3581, 6.04 }, { 1939, 85.1754, +31.9208, 6.11 }, { 1940, 84.8800, -2.4353, 6.00 }, + { 1941, 85.7567, +56.5817, 6.05 }, { 1942, 84.8783, -8.2933, 6.50 }, { 1943, 86.0358, +61.4767, 6.15 }, { 1944, 84.8179, -16.1506, 6.38 }, + { 1945, 85.3375, +29.4875, 6.43 }, { 1946, 85.3238, +16.5339, 4.86 }, { 1947, 84.6817, -39.2925, 5.82 }, { 1948, 85.1896, -0.0572, 2.05 }, + { 1949, 85.1900, -0.0572, 4.21 }, { 1950, 85.1554, -1.1750, 6.22 }, { 1951, 85.4775, +23.3264, 6.59 }, { 1952, 85.2108, -0.8711, 4.95 }, + { 1953, 82.9704, -75.6589, 5.19 }, { 1954, 85.5162, +22.6603, 6.36 }, { 1955, 85.2733, +0.3378, 5.93 }, { 1956, 84.9121, -33.9258, 2.64 }, + { 1957, 85.1917, -9.5906, 6.52 }, { 1958, 84.9575, -31.3708, 5.45 }, { 1959, 85.4179, -1.1039, 6.42 }, { 1960, 84.2279, -65.4397, 6.31 }, + { 1961, 85.8312, +23.2042, 6.21 }, { 1962, 85.4229, -15.2744, 6.21 }, { 1963, 85.6192, +1.4747, 4.91 }, { 1964, 83.6863, -72.2586, 5.78 }, + { 1965, 85.5596, -16.4697, 6.15 }, { 1966, 85.3625, -32.5994, 6.34 }, { 1967, 85.7242, -5.2039, 6.02 }, { 1968, 85.5579, -21.6264, 5.87 }, + { 1969, 86.6267, +56.1156, 5.94 }, { 1970, 85.7887, -0.3869, 6.31 }, { 1971, 86.4750, +49.8264, 5.47 }, { 1972, 85.5483, -29.4644, 6.19 }, + { 1973, 85.5629, -33.3322, 5.29 }, { 1974, 86.4562, +40.5072, 6.58 }, { 1975, 85.8400, -17.4425, 5.73 }, { 1976, 87.2704, +62.8081, 6.13 }, + { 1977, 86.4142, +20.6950, 6.95 }, { 1978, 86.2579, +4.0081, 6.09 }, { 1979, 86.8113, +42.5267, 6.29 }, { 1980, 86.1183, -19.8736, 6.34 }, + { 1981, 85.8758, -38.5931, 6.25 }, { 1982, 86.1104, -21.5783, 6.15 }, { 1983, 86.1158, -21.5517, 3.60 }, { 1984, 85.9213, -44.1669, 6.39 }, + { 1985, 86.6896, +15.8225, 6.00 }, { 1986, 86.5117, -3.7317, 6.34 }, { 1987, 86.7171, +9.5222, 5.79 }, { 1988, 86.6458, +1.1681, 5.95 }, + { 1989, 86.8050, +14.4883, 5.72 }, { 1990, 86.8592, +17.7292, 5.49 }, { 1991, 83.9013, -77.1792, 6.05 }, { 1992, 87.6417, +56.9189, 6.54 }, + { 1993, 86.9287, +13.8997, 5.29 }, { 1994, 88.2313, +68.4714, 6.20 }, { 1995, 87.2938, +39.1811, 4.52 }, { 1996, 86.4996, -31.6936, 5.17 }, + { 1997, 87.0933, +20.8694, 6.07 }, { 1998, 86.7387, -13.1781, 3.55 }, { 1999, 87.0008, +6.4542, 5.27 }, { 2000, 86.7817, -15.7622, 6.17 }, + { 2001, 86.8612, -9.4669, 6.03 }, { 2002, 87.2542, +24.5675, 4.86 }, { 2003, 87.7350, +51.5147, 6.29 }, { 2004, 86.9392, -8.3303, 2.06 }, + { 2005, 86.7696, -27.3608, 6.22 }, { 2006, 88.0725, +58.9642, 6.14 }, { 2007, 87.1454, -3.9053, 5.97 }, { 2008, 86.6142, -45.4028, 5.31 }, + { 2009, 86.8275, -34.3253, 6.32 }, { 2010, 87.3871, +12.6511, 4.91 }, { 2011, 87.7600, +37.3056, 4.74 }, { 2012, 87.8725, +39.1486, 3.97 }, + { 2013, 87.7421, +27.9678, 5.56 }, { 2014, 87.5108, +9.8711, 5.80 }, { 2015, 86.1933, -64.2644, 4.35 }, { 2016, 87.6204, +14.3056, 5.52 }, + { 2017, 86.9921, -39.3475, 6.61 }, { 2018, 87.8571, +32.1250, 6.25 }, { 2019, 87.5546, +4.4233, 5.97 }, { 2020, 86.8213, -50.9336, 3.85 }, + { 2021, 87.4021, -13.5164, 5.49 }, { 2022, 84.2908, -79.5308, 5.65 }, { 2023, 86.8042, -53.6392, 6.18 }, { 2024, 87.6250, +2.0244, 5.98 }, + { 2025, 88.1646, +39.5744, 6.45 }, { 2026, 87.4729, -21.0283, 5.87 }, { 2027, 88.7408, +59.8883, 5.20 }, { 2028, 88.1671, +33.9175, 5.98 }, + { 2029, 88.7117, +55.7069, 4.99 }, { 2030, 88.0975, +19.8681, 6.06 }, { 2031, 87.8417, -6.4819, 5.35 }, { 2032, 87.3921, -43.1247, 6.38 }, + { 2033, 88.0929, +14.1717, 5.59 }, { 2034, 88.3317, +27.6122, 4.58 }, { 2035, 87.8304, -19.1208, 3.81 }, { 2036, 87.8692, -21.0739, 6.17 }, + { 2037, 88.1100, +1.8550, 4.78 }, { 2038, 88.3296, +20.2992, 6.71 }, { 2039, 88.0317, -8.9586, 5.97 }, { 2040, 87.7400, -34.2317, 3.12 }, + { 2041, 89.3958, +66.0961, 6.25 }, { 2042, 87.4571, -55.8333, 4.51 }, { 2043, 87.9979, -28.5514, 6.45 }, { 2044, 87.6192, -51.2322, 6.35 }, + { 2045, 89.0600, +51.8039, 6.49 }, { 2046, 88.7458, +31.7017, 5.90 }, { 2047, 88.5954, +20.2761, 4.41 }, { 2048, 88.5558, +10.5869, 6.12 }, + { 2049, 87.7217, -51.8911, 5.17 }, { 2050, 88.6342, +11.7625, 6.59 }, { 2051, 88.5654, +3.2253, 6.31 }, { 2052, 88.7362, +19.7497, 5.92 }, + { 2053, 88.1383, -36.3689, 5.63 }, { 2054, 89.2704, +49.0294, 6.47 }, { 2055, 88.1988, -37.4742, 6.70 }, { 2056, 88.2788, -32.1986, 4.87 }, + { 2057, 88.6838, +0.9683, 6.00 }, { 2058, 88.6446, -3.9361, 6.57 }, { 2059, 82.5579, -83.2150, 6.20 }, { 2060, 88.4892, -18.3617, 6.69 }, + { 2061, 88.7929, +7.4069, 0.50 }, { 2062, 86.9504, -71.2978, 6.53 }, { 2063, 88.9554, +20.1750, 5.40 }, { 2064, 87.4733, -65.0989, 5.11 }, + { 2065, 88.6817, -10.2261, 5.66 }, { 2066, 89.1408, +28.9422, 6.32 }, { 2067, 89.0146, +13.9253, 6.60 }, { 2068, 88.5588, -28.8522, 6.36 }, + { 2069, 88.3454, -41.0786, 6.55 }, { 2070, 88.8762, -3.3836, 5.87 }, { 2071, 88.8975, -3.2117, 6.28 }, { 2072, 88.0846, -56.8439, 5.94 }, + { 2073, 87.8458, -63.9664, 6.36 }, { 2074, 89.2338, +24.2497, 6.02 }, { 2075, 89.1167, +9.5097, 5.99 }, { 2076, 89.2062, +11.5211, 5.87 }, + { 2077, 89.8817, +54.2847, 3.72 }, { 2078, 91.2887, +75.5858, 6.40 }, { 2079, 89.9404, +55.3208, 6.44 }, { 2080, 89.9504, +54.5472, 6.14 }, + { 2081, 89.8408, +49.9244, 5.89 }, { 2082, 88.7188, -38.0419, 5.57 }, { 2083, 88.5446, -49.6381, 6.52 }, { 2084, 89.4988, +25.9539, 4.82 }, + { 2085, 89.1012, -13.8322, 3.71 }, { 2086, 89.0596, -21.1597, 5.96 }, { 2087, 88.8746, -36.8792, 4.97 }, { 2088, 89.8821, +44.9475, 1.90 }, + { 2089, 88.6713, -48.3731, 6.10 }, { 2090, 89.1437, -22.7844, 6.36 }, { 2091, 89.9838, +45.9369, 4.26 }, { 2092, 89.0871, -30.6175, 5.50 }, + { 2093, 89.4758, +1.2244, 6.22 }, { 2094, 88.7092, -51.3647, 5.29 }, { 2095, 89.9304, +37.2125, 2.62 }, { 2096, 90.0792, +44.5919, 6.22 }, + { 2097, 89.5487, +0.9942, 6.22 }, { 2098, 89.2042, -30.0239, 6.44 }, { 2099, 89.7217, +12.8086, 5.70 }, { 2100, 89.6017, +1.8369, 5.90 }, + { 2101, 90.2442, +47.9019, 5.73 }, { 2102, 88.5254, -62.9100, 4.65 }, { 2103, 89.7067, +0.5531, 5.22 }, { 2104, 88.5496, -63.5178, 6.63 }, + { 2105, 90.4296, +48.9594, 5.96 }, { 2106, 89.3842, -34.7167, 4.36 }, { 2107, 89.7542, -8.6178, 6.12 }, { 2108, 89.7679, -8.4417, 5.03 }, + { 2109, 89.9071, -0.5556, 6.63 }, { 2110, 90.2925, +31.0347, 5.98 }, { 2111, 90.2517, +27.5722, 6.05 }, { 2112, 90.7029, +49.9056, 6.05 }, + { 2113, 90.0142, -2.9258, 4.53 }, { 2114, 89.3100, -52.5739, 6.45 }, { 2115, 90.7233, +43.3786, 6.42 }, { 2116, 90.4233, +22.4008, 6.37 }, + { 2117, 89.6567, -43.9656, 5.81 }, { 2118, 90.0738, -11.1003, 6.22 }, { 2119, 90.8250, +42.9117, 6.10 }, { 2120, 89.7867, -41.1847, 3.96 }, + { 2121, 91.2846, +59.3931, 6.34 }, { 2122, 90.7296, +32.6358, 6.24 }, { 2123, 91.1213, +51.5733, 6.45 }, { 2124, 90.5958, +9.6475, 4.12 }, + { 2125, 87.5696, -78.6386, 5.47 }, { 2126, 91.6633, +63.4536, 6.39 }, { 2127, 90.5713, +1.6944, 6.59 }, { 2128, 90.4600, -9.4019, 4.95 }, + { 2129, 90.3046, -24.5822, 6.05 }, { 2130, 90.8637, +19.6906, 5.14 }, { 2131, 90.3183, -32.0883, 5.55 }, { 2132, 91.2642, +42.9817, 5.87 }, + { 2133, 90.8529, +11.6808, 6.08 }, { 2134, 91.0300, +23.2633, 4.16 }, { 2135, 90.9800, +20.1383, 4.63 }, { 2136, 90.6408, -13.5028, 6.20 }, + { 2137, 91.2608, +37.9642, 6.34 }, { 2138, 90.2050, -50.7836, 5.67 }, { 2139, 91.3917, +33.5992, 6.23 }, { 2140, 90.8146, -25.7156, 5.04 }, + { 2141, 91.5354, +35.3875, 6.12 }, { 2142, 91.0563, -5.2908, 5.21 }, { 2143, 91.6462, +38.4828, 5.36 }, { 2144, 91.2425, +5.4200, 5.67 }, + { 2145, 91.2433, +4.1586, 5.63 }, { 2146, 91.5938, +29.5125, 6.08 }, { 2147, 91.8621, +41.8542, 6.12 }, { 2148, 91.2463, -15.5156, 4.93 }, + { 2149, 91.0846, -31.8275, 5.65 }, { 2150, 91.3625, -9.7572, 5.87 }, { 2151, 90.5383, -59.9031, 6.45 }, { 2152, 92.4963, +58.9358, 5.36 }, + { 2153, 92.0958, +41.0556, 6.36 }, { 2154, 91.6612, -3.8061, 5.38 }, { 2155, 91.5387, -13.0647, 4.67 }, { 2156, 91.4404, -23.8044, 6.95 }, + { 2157, 91.1183, -44.9633, 6.35 }, { 2158, 91.1675, -44.9211, 5.93 }, { 2159, 91.8929, +14.7683, 4.42 }, { 2160, 91.3629, -34.4864, 5.80 }, + { 2161, 91.7163, -10.8264, 6.66 }, { 2162, 91.1954, -47.5414, 6.58 }, { 2163, 91.6333, -22.8894, 5.47 }, { 2164, 91.5229, -28.2414, 5.81 }, + { 2165, 93.2129, +65.7183, 5.32 }, { 2166, 91.7400, -20.1872, 5.78 }, { 2167, 92.1967, +8.6700, 6.55 }, { 2168, 91.9233, -18.8342, 5.31 }, + { 2169, 92.3850, +22.1900, 5.93 }, { 2170, 91.7654, -33.6881, 5.83 }, { 2171, 91.6708, -41.7014, 6.12 }, { 2172, 92.9417, +52.6472, 6.30 }, + { 2173, 92.4333, +23.1133, 5.75 }, { 2174, 92.2412, +2.4994, 5.73 }, { 2175, 92.9021, +48.7131, 6.82 }, { 2176, 92.9025, +48.7111, 6.09 }, + { 2177, 91.8817, -36.7469, 5.02 }, { 2178, 91.7579, -44.9086, 6.51 }, { 2179, 92.4008, -4.2889, 6.17 }, { 2180, 92.2412, -21.5725, 5.50 }, + { 2181, 91.9704, -41.8461, 5.50 }, { 2182, 92.3346, -17.8739, 6.35 }, { 2183, 92.3929, -13.4158, 5.56 }, { 2184, 92.7575, +18.1294, 6.33 }, + { 2185, 92.8846, +24.4203, 5.80 }, { 2186, 92.4496, -21.2258, 5.71 }, { 2187, 92.1442, -43.6439, 6.27 }, { 2188, 93.4387, +51.1725, 6.04 }, + { 2189, 93.0837, +32.6933, 5.78 }, { 2190, 92.9642, +21.8686, 6.56 }, { 2191, 92.8662, +13.6386, 6.04 }, { 2192, 92.4467, -25.2992, 6.27 }, + { 2193, 93.0054, +19.7906, 5.75 }, { 2194, 91.5392, -65.9603, 5.71 }, { 2195, 92.7554, -5.2458, 6.15 }, { 2196, 91.7642, -61.8453, 5.05 }, + { 2197, 93.0796, +22.9083, 6.39 }, { 2198, 93.0138, +16.1306, 4.95 }, { 2199, 92.9850, +14.2089, 4.48 }, { 2200, 92.6442, -26.8458, 5.72 }, + { 2201, 93.9192, +59.9992, 5.35 }, { 2202, 92.9321, -3.3344, 6.18 }, { 2203, 92.5429, -39.6464, 5.58 }, { 2204, 92.3471, -48.4372, 6.49 }, + { 2205, 92.9658, -5.4497, 5.05 }, { 2206, 92.8063, -25.5178, 6.09 }, { 2207, 93.3892, +18.6803, 6.58 }, { 2208, 93.3025, +10.6275, 6.45 }, + { 2209, 94.7117, +69.3197, 4.80 }, { 2210, 93.1850, -1.4956, 6.62 }, { 2211, 92.6663, -44.7181, 6.31 }, { 2212, 92.5746, -53.0314, 4.81 }, + { 2213, 93.1929, -16.2369, 6.52 }, { 2214, 93.6192, +17.9064, 5.88 }, { 2215, 94.4783, +61.5153, 4.98 }, { 2216, 93.7192, +22.5067, 3.28 }, + { 2217, 93.9125, +36.1486, 6.92 }, { 2218, 93.4762, -2.2586, 5.83 }, { 2219, 93.8446, +29.4981, 4.35 }, { 2220, 93.7121, +19.1564, 5.20 }, + { 2221, 92.1842, -67.1567, 5.06 }, { 2222, 93.7854, +13.8511, 5.91 }, { 2223, 93.8546, +16.1431, 5.30 }, { 2224, 93.6529, -3.4317, 5.83 }, + { 2225, 93.4379, -22.1381, 6.39 }, { 2226, 93.3888, -28.6039, 6.54 }, { 2227, 93.7138, -5.7253, 3.98 }, { 2228, 94.3946, +46.4242, 6.52 }, + { 2229, 93.9375, +12.5511, 5.33 }, { 2230, 94.0792, +23.9700, 6.08 }, { 2231, 93.9171, +6.0661, 6.07 }, { 2232, 93.9458, +4.2836, 6.64 }, + { 2233, 93.8929, +0.5122, 5.65 }, { 2234, 93.8738, -3.0847, 5.99 }, { 2235, 94.0992, +17.1814, 6.39 }, { 2236, 93.9750, +1.1692, 6.37 }, + { 2237, 93.8583, -8.9647, 6.10 }, { 2238, 94.9058, +59.0108, 4.48 }, { 2239, 94.5704, +46.3606, 6.38 }, { 2240, 94.2446, +23.7408, 6.25 }, + { 2241, 94.1108, +12.2722, 5.04 }, { 2242, 93.7850, -19.7278, 5.91 }, { 2243, 93.8229, -17.5233, 5.99 }, { 2244, 93.9371, -12.2817, 5.01 }, + { 2245, 92.8125, -64.4106, 5.01 }, { 2246, 94.0883, +1.0803, 6.63 }, { 2247, 94.2775, +9.9425, 5.39 }, { 2248, 94.2433, +7.0531, 6.57 }, + { 2249, 94.0321, -15.3822, 5.92 }, { 2250, 94.3888, +14.0583, 6.59 }, { 2251, 94.3171, +5.1003, 5.71 }, { 2252, 93.9883, -28.2117, 6.67 }, + { 2253, 94.5233, +14.3828, 6.16 }, { 2254, 94.2646, -21.2850, 6.07 }, { 2255, 94.3967, -9.2747, 6.75 }, { 2256, 94.1379, -34.8594, 4.37 }, + { 2257, 95.5150, +59.3722, 5.94 }, { 2258, 94.7575, +17.3250, 6.32 }, { 2259, 94.6688, +9.0472, 6.24 }, { 2260, 94.4237, -15.1842, 5.14 }, + { 2261, 92.5600, -73.2469, 5.09 }, { 2262, 94.1483, -38.7356, 6.00 }, { 2263, 94.2550, -36.2625, 5.53 }, { 2264, 95.4421, +53.4522, 5.36 }, + { 2265, 94.2896, -36.7469, 5.87 }, { 2266, 94.5571, -18.0331, 5.52 }, { 2267, 94.7108, -8.6097, 5.36 }, { 2268, 94.7033, -14.9753, 6.06 }, + { 2269, 95.0175, +14.6511, 5.69 }, { 2270, 94.7829, -7.4136, 6.22 }, { 2271, 94.7458, -19.0739, 5.81 }, { 2272, 95.3004, +29.5411, 6.43 }, + { 2273, 94.9283, -6.1769, 5.27 }, { 2274, 94.0771, -58.7864, 6.43 }, { 2275, 94.9983, -1.0556, 4.90 }, { 2276, 95.2179, +11.7564, 6.54 }, + { 2277, 95.3579, +17.7636, 6.35 }, { 2278, 94.4654, -51.2669, 6.41 }, { 2279, 94.9208, -33.6033, 5.78 }, { 2280, 95.3575, +2.2686, 6.31 }, + { 2281, 94.6950, -49.6408, 7.04 }, { 2282, 95.0783, -29.9367, 3.02 }, { 2283, 93.7746, -70.2972, 6.64 }, { 2284, 95.3529, -10.2267, 5.64 }, + { 2285, 97.0608, +70.5356, 5.97 }, { 2286, 95.7400, +22.5136, 2.88 }, { 2287, 95.6521, +12.5700, 6.00 }, { 2288, 95.1513, -33.8561, 5.53 }, + { 2289, 96.2246, +49.2881, 4.91 }, { 2290, 95.0254, -47.2589, 6.60 }, { 2291, 96.6075, +56.2850, 5.64 }, { 2292, 95.8271, +3.7644, 6.40 }, + { 2293, 96.7037, +58.4172, 5.21 }, { 2294, 95.6750, -16.0442, 1.98 }, { 2295, 95.8446, -3.3128, 6.67 }, { 2296, 95.5283, -32.5636, 3.85 }, + { 2297, 96.2192, +29.7072, 6.71 }, { 2298, 95.9421, +4.5928, 4.44 }, { 2299, 95.9437, +4.5956, 6.72 }, { 2300, 96.0096, +8.8847, 6.26 }, + { 2301, 95.9000, -8.1256, 6.19 }, { 2302, 96.2204, +16.0569, 6.33 }, { 2303, 95.9417, -14.9283, 6.24 }, { 2304, 96.3871, +23.3269, 6.06 }, + { 2305, 96.0429, -10.4697, 5.22 }, { 2306, 95.9483, -18.2147, 6.60 }, { 2307, 95.8100, -30.2100, 6.34 }, { 2308, 96.3671, +14.7219, 6.24 }, + { 2309, 96.0854, -11.0375, 6.12 }, { 2310, 96.3046, +7.0858, 5.98 }, { 2311, 95.9829, -24.4222, 5.63 }, { 2312, 96.3267, +1.5011, 6.66 }, + { 2313, 96.3183, +0.9461, 5.87 }, { 2314, 96.9629, +47.4053, 6.56 }, { 2315, 96.4442, +2.2722, 6.51 }, { 2316, 96.0042, -35.2922, 5.62 }, + { 2317, 96.4463, -2.1108, 6.35 }, { 2318, 96.1829, -27.2200, 6.39 }, { 2319, 96.8979, +32.5631, 6.43 }, { 2320, 95.7325, -55.6300, 5.61 }, + { 2321, 96.4950, -6.1058, 6.40 }, { 2322, 95.9071, -51.8189, 5.98 }, { 2323, 96.1854, -39.7158, 6.31 }, { 2324, 96.6650, -0.4928, 5.87 }, + { 2325, 96.6437, -3.4028, 6.15 }, { 2326, 95.9879, -51.3042, -0.72 }, { 2327, 96.7446, +0.8408, 6.71 }, { 2328, 96.6871, -6.4886, 6.27 }, + { 2329, 96.3746, -34.9361, 6.25 }, { 2330, 96.9858, +20.4961, 6.22 }, { 2331, 97.6967, +58.1628, 5.88 }, { 2332, 97.1421, +30.4931, 5.55 }, + { 2333, 96.8350, +2.9081, 5.55 }, { 2334, 96.8075, +0.2992, 5.20 }, { 2335, 96.8150, +0.2761, 5.55 }, { 2336, 95.9454, -57.4561, 6.48 }, + { 2337, 95.7554, -62.3169, 6.27 }, { 2338, 97.5125, +46.6856, 5.90 }, { 2339, 97.2358, +26.9678, 6.47 }, { 2340, 97.1167, +16.2383, 6.23 }, + { 2341, 96.2008, -51.1936, 6.51 }, { 2342, 97.0783, +10.3039, 6.15 }, { 2343, 97.2408, +20.2122, 4.15 }, { 2344, 96.9900, -3.2378, 5.06 }, + { 2345, 96.0571, -59.7189, 5.80 }, { 2346, 100.0700, +79.5994, 6.54 }, { 2347, 97.0700, +1.9122, 6.48 }, { 2348, 96.4317, -47.8228, 5.76 }, + { 2349, 96.7967, -24.1433, 6.07 }, { 2350, 101.1258, +82.1153, 6.65 }, { 2351, 97.2500, +11.0194, 6.59 }, { 2352, 95.6592, -68.0158, 5.56 }, + { 2353, 96.7813, -36.1044, 6.48 }, { 2354, 96.1096, -62.5711, 6.46 }, { 2355, 97.3121, +2.6461, 6.16 }, { 2356, 97.2042, -6.9672, 4.60 }, + { 2357, 97.2062, -6.9656, 5.40 }, { 2358, 97.2062, -6.9656, 5.60 }, { 2359, 97.1554, -16.5339, 5.77 }, { 2360, 96.2317, -62.1722, 6.27 }, + { 2361, 97.0421, -31.4200, 4.48 }, { 2362, 97.5229, +9.0292, 6.57 }, { 2363, 100.1200, +77.9958, 5.73 }, { 2364, 97.1633, -31.6289, 5.74 }, + { 2365, 99.4788, +73.6956, 6.24 }, { 2366, 97.7921, +16.9386, 6.20 }, { 2367, 97.5471, -9.9186, 5.93 }, { 2368, 97.1762, -40.9256, 6.32 }, + { 2369, 96.7667, -57.9978, 5.82 }, { 2370, 97.7896, +11.2508, 6.14 }, { 2371, 97.9058, +15.9033, 6.40 }, { 2372, 98.1133, +32.4547, 5.87 }, + { 2373, 97.6446, -12.8519, 6.16 }, { 2374, 97.9133, +11.7922, 6.65 }, { 2375, 97.9513, +11.5444, 5.23 }, { 2376, 98.6367, +55.3531, 6.45 }, + { 2377, 96.3692, -68.3097, 5.38 }, { 2378, 98.0971, +11.6736, 6.03 }, { 2379, 97.8458, -11.6083, 5.15 }, { 2380, 97.6929, -26.2306, 5.93 }, + { 2381, 97.9587, -7.8419, 5.43 }, { 2382, 98.0800, +4.8558, 5.84 }, { 2383, 98.4279, +33.0242, 6.42 }, { 2384, 97.4546, -49.7608, 5.27 }, + { 2385, 98.2258, +7.3331, 4.50 }, { 2386, 98.0962, -4.1311, 5.60 }, { 2387, 97.9638, -22.5817, 4.33 }, { 2388, 97.8042, -34.7408, 5.84 }, + { 2389, 97.3688, -55.1472, 5.22 }, { 2390, 97.7492, -39.0836, 6.20 }, { 2391, 98.4004, +14.1553, 5.53 }, { 2392, 98.1954, -10.8336, 6.24 }, + { 2393, 97.8958, -35.0600, 6.34 }, { 2394, 99.4225, +61.4811, 5.94 }, { 2395, 98.4079, -0.7797, 5.10 }, { 2396, 100.1342, +71.7489, 5.92 }, + { 2397, 98.1625, -31.9694, 5.69 }, { 2398, 98.8004, +28.0222, 5.27 }, { 2399, 98.0888, -36.3033, 5.24 }, { 2400, 97.8263, -50.1739, 5.60 }, + { 2401, 101.5588, +79.5647, 5.45 }, { 2402, 99.4104, +56.8575, 5.85 }, { 2403, 98.3608, -19.0761, 6.40 }, { 2404, 98.6933, +7.5725, 6.45 }, + { 2405, 99.1371, +38.4453, 5.29 }, { 2406, 98.8233, +9.9883, 5.88 }, { 2407, 98.2929, -37.3747, 6.44 }, { 2408, 97.5125, -64.4317, 6.29 }, + { 2409, 98.8158, +0.8900, 5.80 }, { 2410, 97.7942, -60.1203, 6.15 }, { 2411, 98.4562, -35.7678, 5.42 }, { 2412, 97.9933, -57.2458, 5.70 }, + { 2413, 99.0000, +4.4975, 6.55 }, { 2414, 98.7642, -21.0353, 4.54 }, { 2415, 98.6471, -31.2836, 5.62 }, { 2416, 98.3588, -51.6711, 6.19 }, + { 2417, 99.3633, +24.5908, 6.44 }, { 2418, 99.1471, -4.7889, 5.52 }, { 2419, 99.6646, +39.3908, 5.69 }, { 2420, 99.7050, +39.9025, 5.20 }, + { 2421, 99.4279, +16.3992, 1.93 }, { 2422, 99.3504, +6.1353, 6.06 }, { 2423, 99.0950, -17.3400, 5.70 }, { 2424, 98.8504, -35.2200, 5.59 }, + { 2425, 99.5958, +28.9842, 5.79 }, { 2426, 99.4038, +10.8531, 6.38 }, { 2427, 99.8329, +42.4889, 4.79 }, { 2428, 99.1946, -12.6792, 5.97 }, + { 2429, 99.1708, -18.7442, 3.95 }, { 2430, 99.4179, +2.7042, 6.17 }, { 2431, 98.9750, -35.9111, 6.35 }, { 2432, 99.4696, +4.9572, 6.15 }, + { 2433, 99.1704, -21.3850, 6.35 }, { 2434, 99.9917, +44.0139, 6.41 }, { 2435, 98.7442, -51.0244, 4.39 }, { 2436, 99.7721, +22.0308, 6.04 }, + { 2437, 99.4204, -11.0150, 6.12 }, { 2438, 99.8879, +28.2631, 6.03 }, { 2439, 99.8808, +24.6000, 6.38 }, { 2440, 99.5854, -1.4564, 6.14 }, + { 2441, 99.7062, +4.7006, 6.57 }, { 2442, 99.6587, +1.6136, 6.21 }, { 2443, 99.4725, -17.7625, 4.43 }, { 2444, 99.2579, -37.8533, 6.04 }, + { 2445, 99.2138, -40.4431, 6.34 }, { 2446, 99.3075, -35.0094, 5.71 }, { 2447, 99.4483, -31.6603, 5.27 }, { 2448, 99.6475, -15.1264, 6.03 }, + { 2449, 99.9483, +12.9831, 5.97 }, { 2450, 99.8196, -13.8542, 4.82 }, { 2451, 99.4404, -42.8039, 3.17 }, { 2452, 100.4071, +35.9319, 6.46 }, + { 2453, 100.3375, +28.1964, 6.42 }, { 2454, 100.1325, +6.3717, 6.51 }, { 2455, 99.9013, -22.3044, 6.05 }, { 2456, 100.2446, +9.8956, 4.66 }, + { 2457, 100.3408, +16.3975, 6.28 }, { 2458, 100.3217, +11.0033, 6.11 }, { 2459, 100.7708, +44.5244, 5.02 }, { 2460, 99.9279, -29.5297, 5.71 }, + { 2461, 100.2725, +0.4953, 5.79 }, { 2462, 99.6567, -47.7797, 4.93 }, { 2463, 101.0483, +53.2964, 6.27 }, { 2464, 100.8075, +37.1469, 6.19 }, + { 2465, 99.9871, -37.8411, 6.58 }, { 2466, 100.6012, +17.6453, 5.21 }, { 2467, 100.4971, +6.3450, 6.37 }, { 2468, 99.5025, -60.4669, 6.18 }, + { 2469, 100.4850, -8.8328, 5.19 }, { 2470, 101.5588, +59.4417, 4.87 }, { 2471, 101.0525, +36.1097, 6.31 }, { 2472, 0.0000, +0.0000, 0.00 }, + { 2473, 100.9829, +25.1311, 2.98 }, { 2474, 100.7771, +3.0333, 6.19 }, { 2475, 100.3088, -39.6503, 6.12 }, { 2476, 100.2054, -46.3253, 6.65 }, + { 2477, 101.7063, +57.1692, 5.35 }, { 2478, 100.9971, +13.2278, 4.49 }, { 2479, 100.9113, +3.9322, 5.90 }, { 2480, 101.1896, +28.9708, 5.44 }, + { 2481, 100.6908, -21.5508, 6.13 }, { 2482, 100.5683, -37.6014, 6.29 }, { 2483, 101.6846, +43.5775, 5.25 }, { 2484, 101.3225, +12.8956, 3.36 }, + { 2485, 102.0537, +55.7044, 6.33 }, { 2486, 102.0513, +55.7044, 6.28 }, { 2487, 101.9150, +48.7894, 5.22 }, { 2488, 100.8471, -38.8067, 6.30 }, + { 2489, 101.4758, +12.6936, 6.46 }, { 2490, 102.7379, +67.5719, 5.14 }, { 2491, 101.2871, -15.2839, -1.46 }, { 2492, 101.1183, -30.9294, 5.20 }, + { 2493, 101.2163, -26.6586, 6.45 }, { 2494, 101.6350, +8.5872, 5.93 }, { 2495, 101.3471, -22.5381, 6.05 }, { 2496, 0.0000, +0.0000, 0.00 }, + { 2497, 101.2600, -29.4139, 6.54 }, { 2498, 101.4971, -13.2039, 5.32 }, { 2499, 101.8479, +18.1933, 6.20 }, { 2500, 101.3450, -30.2064, 5.92 }, + { 2501, 101.3804, -29.0511, 5.80 }, { 2502, 101.6625, -9.8928, 5.66 }, { 2503, 101.8325, +8.0372, 4.77 }, { 2504, 101.7129, -13.5742, 5.29 }, + { 2505, 100.2408, -70.2244, 6.51 }, { 2506, 101.9650, +2.4122, 4.47 }, { 2507, 101.5138, -38.4600, 6.62 }, { 2508, 101.9046, -7.0017, 5.07 }, + { 2509, 101.7562, -20.9844, 6.08 }, { 2510, 101.5504, -36.2244, 6.21 }, { 2511, 103.4258, +68.8883, 5.12 }, { 2512, 102.4221, +32.6067, 5.71 }, + { 2513, 101.3588, -51.7989, 6.57 }, { 2514, 102.0792, -0.6808, 5.75 }, { 2515, 101.4738, -51.5900, 5.80 }, { 2516, 102.6913, +41.7814, 5.02 }, + { 2517, 102.2654, +1.0019, 6.15 }, { 2518, 101.8392, -36.0703, 5.26 }, { 2519, 102.4575, +16.2028, 5.85 }, { 2520, 103.2712, +59.4486, 5.33 }, + { 2521, 102.3183, -1.7281, 5.74 }, { 2522, 102.2408, -14.8553, 5.39 }, { 2523, 101.7200, -50.7342, 5.40 }, { 2524, 101.6729, -53.3053, 6.46 }, + { 2525, 102.6063, +13.4133, 5.65 }, { 2526, 101.8279, -54.4600, 5.61 }, { 2527, 105.0167, +76.9775, 4.55 }, { 2528, 102.4333, -23.9242, 6.33 }, + { 2529, 102.8875, +21.7611, 5.27 }, { 2530, 102.7079, +0.5408, 5.77 }, { 2531, 100.9033, -72.8819, 6.37 }, { 2532, 103.2817, +44.8394, 6.26 }, + { 2533, 103.0000, +23.6017, 5.65 }, { 2534, 102.6763, -7.9589, 6.29 }, { 2535, 102.5913, -16.9161, 5.79 }, { 2536, 101.2338, -69.5661, 6.11 }, + { 2537, 102.5250, -26.6661, 7.04 }, { 2538, 102.4604, -31.4914, 3.96 }, { 2539, 103.2562, +38.8692, 6.12 }, { 2540, 103.1971, +33.9611, 3.60 }, + { 2541, 103.3058, +38.4381, 6.30 }, { 2542, 103.2642, +35.7886, 6.01 }, { 2543, 102.9137, +3.0417, 6.38 }, { 2544, 102.6538, -24.2219, 6.33 }, + { 2545, 102.5971, -30.2939, 5.70 }, { 2546, 102.4908, -44.5500, 6.55 }, { 2547, 103.4875, +38.5050, 6.48 }, { 2548, 102.4775, -45.3853, 5.14 }, + { 2549, 102.7183, -33.6328, 4.99 }, { 2550, 102.0475, -60.0586, 3.27 }, { 2551, 103.2058, +8.3803, 5.77 }, { 2552, 103.0954, -4.6839, 6.30 }, + { 2553, 102.4842, -49.3853, 2.93 }, { 2554, 102.4638, -52.3778, 4.40 }, { 2555, 103.3438, +10.9964, 6.24 }, { 2556, 103.8133, +45.8264, 6.34 }, + { 2557, 103.8113, +43.9100, 6.13 }, { 2558, 102.9263, -35.7697, 5.96 }, { 2559, 100.0113, -79.1864, 5.64 }, { 2560, 104.3187, +58.4225, 4.35 }, + { 2561, 104.3050, +57.5633, 6.05 }, { 2562, 102.5046, -59.7508, 6.11 }, { 2563, 102.8867, -47.7075, 6.42 }, { 2564, 103.6613, +13.1778, 4.65 }, + { 2565, 103.3283, -18.9672, 5.64 }, { 2566, 103.3404, -17.0667, 6.14 }, { 2567, 103.2504, -25.0425, 6.40 }, { 2568, 104.1346, +46.2742, 5.87 }, + { 2569, 103.8275, +25.3756, 5.73 }, { 2570, 103.5354, -4.1475, 6.41 }, { 2571, 103.3871, -19.7758, 4.83 }, { 2572, 103.6025, -0.8731, 5.45 }, + { 2573, 104.2333, +46.7050, 5.86 }, { 2574, 103.5475, -11.9614, 4.07 }, { 2575, 103.1654, -41.4956, 6.52 }, { 2576, 103.3913, -27.4603, 6.04 }, + { 2577, 103.6754, -0.2436, 6.21 }, { 2578, 103.4804, -23.4608, 6.21 }, { 2579, 103.1963, -42.0242, 6.46 }, { 2580, 103.5329, -23.8161, 3.87 }, + { 2581, 105.3396, +70.8081, 5.68 }, { 2582, 103.7450, -1.1964, 6.04 }, { 2583, 103.5542, -22.0717, 6.91 }, { 2584, 103.8942, +8.3247, 6.29 }, + { 2585, 104.4046, +45.0942, 4.90 }, { 2586, 104.2521, +33.6811, 5.89 }, { 2587, 103.1954, -53.9100, 6.57 }, { 2588, 103.7613, -19.5953, 5.74 }, + { 2589, 104.1075, +9.9564, 5.92 }, { 2590, 103.9058, -19.8636, 4.68 }, { 2591, 103.6113, -41.6344, 6.32 }, { 2592, 103.1892, -58.6589, 6.41 }, + { 2593, 104.0275, -13.9564, 5.00 }, { 2594, 103.5096, -49.3883, 6.26 }, { 2595, 103.9450, -21.0586, 5.30 }, { 2596, 104.0342, -16.9458, 4.37 }, + { 2597, 104.3571, +11.9075, 6.27 }, { 2598, 103.9783, -30.2100, 6.36 }, { 2599, 104.2504, -7.8211, 6.34 }, { 2600, 104.7617, +38.0522, 6.00 }, + { 2601, 104.6975, +26.0811, 6.10 }, { 2602, 102.8625, -69.0367, 5.40 }, { 2603, 104.3117, -21.7967, 6.61 }, { 2604, 104.1904, -34.6583, 6.29 }, + { 2605, 104.8662, +25.9142, 6.40 }, { 2606, 104.6625, +7.6219, 6.27 }, { 2607, 104.3913, -23.3694, 5.46 }, { 2608, 104.0667, -47.2789, 4.95 }, + { 2609, 115.1271, +87.0200, 5.07 }, { 2610, 104.7375, +3.6022, 5.97 }, { 2611, 104.4267, -26.4625, 6.23 }, { 2612, 104.3233, -34.4925, 6.23 }, + { 2613, 104.8337, +7.3169, 6.35 }, { 2614, 104.5317, -26.8353, 6.37 }, { 2615, 105.0658, +16.0789, 5.68 }, { 2616, 104.6496, -24.5861, 5.59 }, + { 2617, 106.4658, +70.7319, 6.50 }, { 2618, 104.6563, -27.0278, 1.50 }, { 2619, 104.6046, -33.8883, 5.06 }, { 2620, 105.3217, +32.4144, 6.59 }, + { 2621, 104.6825, -29.0022, 6.42 }, { 2622, 105.0750, -4.6331, 6.30 }, { 2623, 104.9137, -20.3967, 6.26 }, { 2624, 105.0988, -7.5931, 5.96 }, + { 2625, 105.0338, -19.8411, 6.31 }, { 2626, 104.6742, -44.2319, 6.22 }, { 2627, 105.1637, -8.7969, 6.49 }, { 2628, 105.0804, -21.8806, 6.53 }, + { 2629, 105.4225, +4.8181, 6.63 }, { 2630, 105.6033, +24.2153, 5.18 }, { 2631, 105.6063, +17.7556, 5.94 }, { 2632, 105.5725, +15.3361, 5.74 }, + { 2633, 105.4792, +5.5575, 6.59 }, { 2634, 104.6650, -54.2706, 6.27 }, { 2635, 105.6396, +16.6742, 5.82 }, { 2636, 105.4704, -0.6544, 6.17 }, + { 2637, 105.1775, -27.5106, 6.27 }, { 2638, 104.6508, -55.6053, 6.45 }, { 2639, 105.4850, -4.2778, 5.20 }, { 2640, 105.2746, -24.7847, 5.63 }, + { 2641, 105.2075, -32.5347, 6.40 }, { 2642, 106.5054, +59.8019, 6.44 }, { 2643, 105.8767, +29.3372, 5.93 }, { 2644, 106.4158, +52.7581, 6.12 }, + { 2645, 106.2875, +47.7750, 6.38 }, { 2646, 105.4296, -26.0653, 3.47 }, { 2647, 105.8246, +9.1383, 5.97 }, { 2648, 105.7283, -3.7608, 4.99 }, + { 2649, 105.9083, +10.9517, 5.13 }, { 2650, 106.0271, +20.5703, 3.79 }, { 2651, 105.9650, +12.5944, 5.98 }, { 2652, 105.2146, -50.5975, 5.14 }, + { 2653, 105.7562, -22.1667, 3.02 }, { 2654, 106.0842, +1.4883, 6.57 }, { 2655, 106.0217, -4.6764, 5.62 }, { 2656, 105.9888, -9.8758, 6.45 }, + { 2657, 105.9396, -14.3667, 4.12 }, { 2658, 105.5650, -42.5958, 6.43 }, { 2659, 106.3267, +22.6372, 6.02 }, { 2660, 106.5483, +34.4739, 5.55 }, + { 2661, 105.2712, -57.0600, 6.02 }, { 2662, 104.9604, -66.0839, 5.17 }, { 2663, 106.4129, +9.1858, 5.78 }, { 2664, 106.1963, -21.9678, 6.09 }, + { 2665, 106.8429, +34.0094, 5.91 }, { 2666, 106.0117, -41.6628, 5.20 }, { 2667, 105.9888, -42.3919, 5.54 }, { 2668, 105.9950, -42.3883, 6.79 }, + { 2669, 106.8542, +28.1772, 6.48 }, { 2670, 106.4571, -9.3389, 6.49 }, { 2671, 106.8392, +22.7036, 7.68 }, { 2672, 105.9738, -48.4161, 4.93 }, + { 2673, 107.0554, +33.8322, 6.28 }, { 2674, 105.8150, -58.8219, 5.50 }, { 2675, 107.1513, +37.4450, 6.16 }, { 2676, 106.7767, +4.9103, 6.11 }, + { 2677, 106.3833, -33.2222, 6.14 }, { 2678, 106.6696, -10.7058, 5.39 }, { 2679, 106.6496, -11.6061, 6.48 }, { 2680, 106.5025, -29.3444, 6.34 }, + { 2681, 108.4921, +71.8167, 6.35 }, { 2682, 106.9563, +7.4711, 5.75 }, { 2683, 106.0763, -55.2503, 5.17 }, { 2684, 107.0917, +15.9308, 5.44 }, + { 2685, 106.5096, -37.6172, 6.11 }, { 2686, 106.7179, -23.0394, 6.08 }, { 2687, 106.3187, -49.6397, 6.46 }, { 2688, 106.7504, -25.3422, 6.62 }, + { 2689, 104.1433, -78.5797, 5.45 }, { 2690, 106.8442, -22.1597, 5.71 }, { 2691, 106.7796, -39.1067, 5.79 }, { 2692, 107.5279, +21.2469, 6.43 }, + { 2693, 107.0979, -25.6067, 1.84 }, { 2694, 107.3346, -9.6528, 6.21 }, { 2695, 107.2054, -23.9558, 6.65 }, { 2696, 107.9137, +39.3206, 4.90 }, + { 2697, 107.7850, +30.2453, 4.41 }, { 2698, 106.8054, -50.0322, 5.96 }, { 2699, 107.3883, -15.7653, 6.03 }, { 2700, 107.8463, +26.8567, 5.78 }, + { 2701, 107.5571, -3.7628, 4.92 }, { 2702, 107.2129, -38.3442, 4.83 }, { 2703, 108.3475, +51.4289, 5.47 }, { 2704, 107.4287, -24.7689, 5.69 }, + { 2705, 107.5387, -17.3147, 6.23 }, { 2706, 108.1100, +24.1283, 5.85 }, { 2707, 107.8483, +0.3019, 5.45 }, { 2708, 107.5808, -26.5086, 5.46 }, + { 2709, 111.3413, +81.2575, 6.31 }, { 2710, 107.9638, +5.6547, 6.09 }, { 2711, 108.2042, +27.2247, 6.43 }, { 2712, 106.5588, -67.1628, 6.47 }, + { 2713, 108.0308, +5.4747, 6.16 }, { 2714, 107.9663, +0.4928, 4.15 }, { 2715, 108.9788, +59.6375, 5.20 }, { 2716, 107.9233, -19.1169, 5.84 }, + { 2717, 108.3429, +16.1589, 5.00 }, { 2718, 108.0508, -24.0575, 5.92 }, { 2719, 107.6979, -47.0678, 5.14 }, { 2720, 108.0171, -29.1783, 6.10 }, + { 2721, 108.9587, +47.2400, 5.58 }, { 2722, 108.6108, +24.7108, 6.89 }, { 2723, 108.2800, -10.7486, 5.78 }, { 2724, 108.1004, -26.5258, 6.59 }, + { 2725, 108.6746, +24.8850, 5.82 }, { 2726, 108.1071, -35.4556, 5.96 }, { 2727, 108.0658, -39.5011, 5.31 }, { 2728, 108.6358, +12.1158, 5.62 }, + { 2729, 108.5833, +3.1114, 5.35 }, { 2730, 108.3496, -21.3267, 6.01 }, { 2731, 108.5458, -2.0986, 5.75 }, { 2732, 108.5646, -8.0525, 5.90 }, + { 2733, 108.4513, -21.0936, 6.36 }, { 2734, 108.4013, -26.6436, 6.12 }, { 2735, 107.1758, -69.5028, 5.69 }, { 2736, 107.1871, -69.5011, 3.78 }, + { 2737, 109.3904, +52.1308, 5.92 }, { 2738, 108.9879, +27.8975, 5.71 }, { 2739, 108.6175, -9.6833, 6.03 }, { 2740, 108.1400, -45.2406, 4.49 }, + { 2741, 108.4463, -30.9161, 6.60 }, { 2742, 112.7683, +82.4114, 4.96 }, { 2743, 108.4883, -29.6600, 6.33 }, { 2744, 108.8304, +0.1614, 6.41 }, + { 2745, 108.5633, -25.6475, 4.66 }, { 2746, 108.3058, -44.8169, 4.89 }, { 2747, 108.9142, +7.9778, 5.82 }, { 2748, 108.3850, -43.3603, 5.10 }, + { 2749, 108.7029, -25.2272, 3.85 }, { 2750, 108.7129, -26.9619, 5.58 }, { 2751, 109.6329, +49.4650, 5.05 }, { 2752, 108.9296, -9.4161, 5.95 }, + { 2753, 109.5092, +40.8833, 5.78 }, { 2754, 108.0083, -62.8100, 6.02 }, { 2755, 108.9479, -22.2594, 6.32 }, { 2756, 108.8375, -29.3136, 5.36 }, + { 2757, 109.5171, +30.9558, 6.24 }, { 2758, 109.0604, -14.4142, 5.46 }, { 2759, 108.7379, -40.5742, 5.94 }, { 2760, 109.3242, +6.6806, 6.65 }, + { 2761, 108.6913, -45.1503, 5.72 }, { 2762, 108.6592, -47.7283, 4.76 }, { 2763, 109.5233, +16.5403, 3.58 }, { 2764, 109.1533, -22.6844, 4.79 }, + { 2765, 109.3821, -5.3200, 6.29 }, { 2766, 109.1458, -26.1189, 4.64 }, { 2767, 108.8375, -51.5003, 5.97 }, { 2768, 109.2383, -29.1033, 6.32 }, + { 2769, 109.1325, -37.6811, 5.80 }, { 2770, 109.2063, -35.4072, 5.03 }, { 2771, 109.0646, -45.2256, 5.66 }, { 2772, 110.5717, +59.9019, 6.35 }, + { 2773, 109.2858, -36.9025, 2.70 }, { 2774, 109.4496, -25.2025, 6.46 }, { 2775, 110.2629, +42.6556, 6.35 }, { 2776, 110.3229, +45.2281, 5.77 }, + { 2777, 110.0308, +21.9822, 3.53 }, { 2778, 109.8433, +2.7406, 5.89 }, { 2779, 109.9483, +7.1428, 5.91 }, { 2780, 110.0288, +15.1428, 6.45 }, + { 2781, 109.6679, -23.4411, 4.98 }, { 2782, 109.6767, -23.0458, 4.40 }, { 2783, 110.7121, +55.2844, 6.53 }, { 2784, 110.7171, +55.2814, 5.45 }, + { 2785, 109.7583, -18.7197, 6.09 }, { 2786, 109.7133, -25.4142, 5.28 }, { 2787, 109.5767, -35.2658, 4.66 }, { 2788, 109.8671, -15.6050, 5.70 }, + { 2789, 109.5175, -42.0133, 5.85 }, { 2790, 109.6592, -35.2572, 5.11 }, { 2791, 109.6400, -38.7897, 5.25 }, { 2792, 110.5558, +38.9961, 6.40 }, + { 2793, 110.5108, +36.7606, 5.13 }, { 2794, 109.8071, -32.2728, 6.30 }, { 2795, 110.4867, +20.4436, 5.10 }, { 2796, 110.2425, -13.6400, 5.45 }, + { 2797, 113.6654, +80.8967, 6.41 }, { 2798, 110.3204, -7.1217, 6.55 }, { 2799, 110.2217, -21.1483, 6.61 }, { 2800, 110.2292, -25.0364, 6.01 }, + { 2801, 110.5146, +0.1772, 5.99 }, { 2802, 110.2679, -24.1086, 5.87 }, { 2803, 109.2075, -66.0428, 3.98 }, { 2804, 111.2383, +51.8872, 5.80 }, + { 2805, 111.0354, +40.6722, 5.19 }, { 2806, 110.5083, -7.0208, 6.43 }, { 2807, 110.5771, -1.0211, 6.23 }, { 2808, 110.8688, +25.0506, 5.03 }, + { 2809, 111.8575, +66.3317, 6.47 }, { 2810, 110.8675, +22.9453, 6.02 }, { 2811, 110.6058, -4.0172, 5.82 }, { 2812, 110.5563, -18.9833, 4.96 }, + { 2813, 110.0892, -51.6883, 6.05 }, { 2814, 110.0904, -51.6903, 6.60 }, { 2815, 110.1613, -51.9139, 5.39 }, { 2816, 111.1392, +27.6381, 5.76 }, + { 2817, 111.1154, +15.5172, 6.41 }, { 2818, 111.6783, +49.2114, 4.64 }, { 2819, 110.7525, -30.0761, 5.43 }, { 2820, 111.2425, +11.6697, 5.30 }, + { 2821, 111.4317, +27.7981, 3.79 }, { 2822, 110.8713, -26.1658, 5.38 }, { 2823, 110.8829, -31.7978, 5.39 }, { 2824, 110.9762, -29.7831, 6.60 }, + { 2825, 111.1671, -15.7989, 5.33 }, { 2826, 111.0717, -21.0872, 6.19 }, { 2827, 111.0238, -28.6969, 2.45 }, { 2828, 111.4121, +9.2761, 4.99 }, + { 2829, 110.9929, -34.1622, 6.31 }, { 2830, 112.7196, +68.4656, 5.64 }, { 2831, 111.2113, -18.9878, 6.24 }, { 2832, 111.2846, -12.2481, 5.78 }, + { 2833, 111.4625, -4.2250, 5.97 }, { 2834, 111.1825, -30.1911, 5.35 }, { 2835, 111.7092, +21.5358, 6.54 }, { 2836, 111.6162, +10.6083, 6.37 }, + { 2837, 111.7346, +20.2572, 5.93 }, { 2838, 111.5146, -3.4625, 6.76 }, { 2839, 111.3329, -20.0172, 6.05 }, { 2840, 111.6721, +11.0092, 6.41 }, + { 2841, 111.3554, -24.7822, 5.78 }, { 2842, 111.1967, -36.7100, 6.97 }, { 2843, 111.1971, -36.7092, 6.84 }, { 2844, 112.2150, +48.1839, 5.72 }, + { 2845, 111.7875, +8.2894, 2.90 }, { 2846, 111.9350, +21.4450, 5.22 }, { 2847, 111.4292, -30.2614, 6.31 }, { 2848, 101.7446, -86.9750, 6.47 }, + { 2849, 112.4833, +49.6725, 5.36 }, { 2850, 111.6696, -22.2878, 6.56 }, { 2851, 112.0088, +6.9419, 5.25 }, { 2852, 112.2779, +31.7844, 4.18 }, + { 2853, 111.7833, -16.1356, 5.63 }, { 2854, 112.0408, +8.9256, 4.32 }, { 2855, 111.7475, -22.9139, 5.61 }, { 2856, 111.6763, -33.8592, 5.90 }, + { 2857, 112.3350, +28.1181, 5.05 }, { 2858, 112.1971, +15.1094, 6.22 }, { 2859, 111.9654, -10.4431, 5.79 }, { 2860, 111.9287, -21.1403, 5.95 }, + { 2861, 112.4529, +27.9161, 5.01 }, { 2862, 111.5913, -50.9817, 5.10 }, { 2863, 111.9967, -28.8442, 5.54 }, { 2864, 112.4492, +12.0067, 4.54 }, + { 2865, 112.3279, -0.0947, 5.59 }, { 2866, 112.3571, -6.4489, 5.86 }, { 2867, 112.3421, -9.6733, 5.75 }, { 2868, 112.3413, -13.0008, 6.05 }, + { 2869, 112.0950, -36.1897, 6.58 }, { 2870, 112.2138, -30.1517, 6.38 }, { 2871, 112.2146, -30.1531, 7.13 }, { 2872, 112.9821, +38.8964, 6.54 }, + { 2873, 112.2704, -30.5436, 5.77 }, { 2874, 112.4642, -22.9756, 4.85 }, { 2875, 112.2738, -37.1878, 5.43 }, { 2876, 112.7129, -4.7736, 6.24 }, + { 2877, 112.9517, +17.0861, 5.42 }, { 2878, 112.3075, -42.6986, 3.25 }, { 2879, 113.2108, +22.8878, 6.54 }, { 2880, 113.0246, +1.9144, 5.25 }, + { 2881, 112.6771, -29.0378, 4.65 }, { 2882, 112.6767, -36.6603, 6.65 }, { 2883, 113.0242, -7.1192, 5.90 }, { 2884, 112.4983, -51.3489, 5.87 }, + { 2885, 112.8575, -35.8472, 6.68 }, { 2886, 113.4021, +15.8267, 5.25 }, { 2887, 113.2983, +3.2903, 5.59 }, { 2888, 112.2138, -63.4900, 6.39 }, + { 2889, 112.9283, -34.1122, 6.61 }, { 2890, 113.6500, +31.8886, 2.88 }, { 2891, 113.6500, +31.8883, 1.98 }, { 2892, 112.6288, -53.6006, 5.96 }, + { 2893, 113.5212, +10.5683, 6.28 }, { 2894, 114.1958, +55.7553, 5.92 }, { 2895, 113.0929, -34.0386, 6.30 }, { 2896, 113.7863, +30.9611, 5.33 }, + { 2897, 113.3421, -13.6617, 6.21 }, { 2898, 113.9833, +43.0311, 6.30 }, { 2899, 113.3313, -18.5875, 5.66 }, { 2900, 113.2904, -23.2892, 5.85 }, + { 2901, 113.5658, +3.3714, 5.81 }, { 2902, 113.4496, -13.4761, 4.97 }, { 2903, 114.1317, +46.1803, 5.65 }, { 2904, 113.6917, +2.7250, 6.55 }, + { 2905, 113.9804, +26.8958, 4.06 }, { 2906, 113.5133, -21.7039, 4.45 }, { 2907, 113.3063, -39.9411, 6.26 }, { 2908, 113.3054, -42.9136, 6.52 }, + { 2909, 113.5775, -22.5264, 5.83 }, { 2910, 113.5796, -22.5253, 5.87 }, { 2911, 113.4625, -35.6617, 5.54 }, { 2912, 113.6200, -25.8833, 6.65 }, + { 2913, 113.5533, -32.5367, 6.11 }, { 2914, 114.4746, +48.7736, 5.92 }, { 2915, 114.3242, +40.0253, 6.38 }, { 2916, 113.6454, -26.9881, 5.77 }, + { 2917, 113.4938, -38.0942, 6.76 }, { 2918, 114.1446, +5.8617, 5.91 }, { 2919, 111.4083, -78.9058, 5.53 }, { 2920, 114.0692, -7.6886, 6.27 }, + { 2921, 114.0163, -13.5072, 5.70 }, { 2922, 113.8450, -27.6306, 4.64 }, { 2923, 114.0325, -21.8394, 6.34 }, { 2924, 114.6367, +35.0486, 5.56 }, + { 2925, 113.6646, -50.5253, 6.28 }, { 2926, 114.5604, +24.3603, 6.27 }, { 2927, 114.3196, -3.8889, 5.13 }, { 2928, 114.1708, -18.2978, 5.74 }, + { 2929, 115.2063, +57.0828, 6.06 }, { 2930, 114.7913, +34.5842, 4.90 }, { 2931, 114.7996, +24.2225, 6.17 }, { 2932, 114.4121, -13.5589, 6.53 }, + { 2933, 114.3200, -22.2250, 6.37 }, { 2934, 113.9154, -51.4661, 4.94 }, { 2935, 115.0608, +38.3444, 5.73 }, { 2936, 114.9754, +32.0097, 6.17 }, + { 2937, 114.3421, -33.0314, 4.53 }, { 2938, 114.8692, +17.6747, 5.05 }, { 2939, 115.3017, +48.1317, 5.56 }, { 2940, 114.1829, -47.1697, 5.72 }, + { 2941, 114.0071, -54.1125, 6.39 }, { 2942, 114.4367, -34.7228, 6.60 }, { 2943, 114.8254, +5.2250, 0.38 }, { 2944, 114.5750, -24.6353, 4.70 }, + { 2945, 114.4383, -37.9894, 6.38 }, { 2946, 115.7517, +58.7103, 4.99 }, { 2947, 114.7796, -17.3208, 6.72 }, { 2948, 114.7054, -25.1983, 4.50 }, + { 2949, 114.7075, -25.1964, 4.62 }, { 2950, 115.0292, +5.2308, 6.02 }, { 2951, 115.2438, +23.0186, 5.89 }, { 2952, 114.6008, -38.0086, 6.59 }, + { 2953, 115.1971, +13.7708, 6.24 }, { 2954, 114.6829, -35.5031, 5.80 }, { 2955, 114.6358, -37.2189, 6.19 }, { 2956, 114.8621, -25.1369, 6.50 }, + { 2957, 114.5758, -47.3989, 5.68 }, { 2958, 115.1479, -7.8142, 6.01 }, { 2959, 115.0967, -14.7364, 4.94 }, { 2960, 115.0567, -18.3392, 5.93 }, + { 2961, 114.8642, -37.6917, 4.84 }, { 2962, 115.6813, +34.0003, 6.02 }, { 2963, 114.9325, -37.8606, 5.73 }, { 2964, 114.9492, -37.7392, 5.76 }, + { 2965, 115.4658, +13.4806, 5.77 }, { 2966, 115.3967, +3.6247, 5.94 }, { 2967, 115.5133, +14.2083, 5.56 }, { 2968, 114.9917, -36.4206, 6.00 }, + { 2969, 116.0175, +50.4339, 5.27 }, { 2970, 115.3117, -8.4489, 3.93 }, { 2971, 114.7517, -52.7267, 6.06 }, { 2972, 115.1808, -26.0542, 6.76 }, + { 2973, 115.8279, +28.8836, 4.28 }, { 2974, 115.2196, -30.3392, 6.56 }, { 2975, 116.6671, +65.4558, 5.92 }, { 2976, 115.3483, -21.6628, 6.18 }, + { 2977, 116.6142, +62.8306, 6.49 }, { 2978, 115.8425, +22.3994, 6.21 }, { 2979, 113.8404, -73.7244, 7.16 }, { 2980, 113.8408, -73.7244, 7.26 }, + { 2981, 115.3158, -37.4664, 5.42 }, { 2982, 115.7725, +0.1894, 6.19 }, { 2983, 116.0288, +25.7842, 5.31 }, { 2984, 115.3408, -43.3678, 6.41 }, + { 2985, 116.1117, +24.3981, 3.57 }, { 2986, 115.4917, -37.4711, 6.54 }, { 2987, 116.0583, +12.8594, 6.43 }, { 2988, 115.7004, -25.6489, 5.64 }, + { 2989, 116.0308, +2.4050, 6.47 }, { 2990, 116.3288, +28.0261, 1.14 }, { 2991, 116.2887, +20.3164, 6.33 }, { 2992, 115.9129, -24.4961, 6.55 }, + { 2993, 115.8850, -27.5889, 4.59 }, { 2994, 115.8000, -35.9497, 5.60 }, { 2995, 115.7792, -37.1358, 6.89 }, { 2996, 115.9521, -27.0453, 3.96 }, + { 2997, 119.0721, +80.2656, 6.56 }, { 2998, 115.7383, -44.8267, 5.06 }, { 2999, 116.6637, +37.5175, 5.18 }, { 3000, 114.0175, -76.3658, 6.18 }, + { 3001, 115.9287, -37.7981, 6.40 }, { 3002, 115.9246, -39.0661, 5.17 }, { 3003, 116.5308, +18.5100, 4.88 }, { 3004, 116.1417, -23.3261, 5.62 }, + { 3005, 115.7788, -48.0072, 6.57 }, { 3006, 115.5425, -57.3692, 6.43 }, { 3007, 116.0400, -35.9372, 5.80 }, { 3008, 116.5675, +10.7683, 5.30 }, + { 3009, 116.3696, -13.3139, 6.89 }, { 3010, 116.3713, -13.3092, 6.07 }, { 3011, 116.1425, -36.0569, 5.88 }, { 3012, 115.7221, -57.7700, 6.21 }, + { 3013, 116.8763, +33.4156, 5.14 }, { 3014, 116.5092, -5.2275, 5.49 }, { 3015, 116.4871, -13.4361, 5.04 }, { 3016, 116.2692, -36.1122, 6.54 }, + { 3017, 116.3138, -36.0314, 3.61 }, { 3018, 116.3958, -33.8269, 5.37 }, { 3019, 116.6871, -11.3247, 6.39 }, { 3020, 116.3254, -42.2478, 6.03 }, + { 3021, 117.1400, +23.1411, 6.18 }, { 3022, 116.5433, -36.0661, 5.88 }, { 3023, 116.8021, -21.4803, 5.90 }, { 3024, 115.4550, -71.3939, 3.95 }, + { 3025, 116.6392, -39.9403, 6.57 }, { 3026, 116.9104, -14.0092, 6.34 }, { 3027, 116.9383, -15.9856, 6.43 }, { 3028, 117.7738, +54.1292, 6.02 }, + { 3029, 116.9863, -11.8069, 5.48 }, { 3030, 117.2583, +13.3708, 6.04 }, { 3031, 116.3983, -55.2775, 6.12 }, { 3032, 116.7742, -38.6686, 6.31 }, + { 3033, 117.2454, +4.3328, 6.53 }, { 3034, 117.0217, -24.0628, 4.50 }, { 3035, 116.8542, -37.4889, 5.08 }, { 3036, 116.1829, -65.9281, 6.38 }, + { 3037, 116.8812, -45.3914, 5.23 }, { 3038, 116.0542, -68.1786, 6.18 }, { 3039, 118.1525, +55.2094, 6.38 }, { 3040, 117.7596, +33.2336, 6.03 }, + { 3041, 117.0354, -39.3478, 6.14 }, { 3042, 117.3692, -12.6467, 6.23 }, { 3043, 117.2571, -23.0878, 5.33 }, { 3044, 117.4217, -16.7717, 5.18 }, + { 3045, 117.3238, -23.1403, 3.34 }, { 3046, 117.0846, -46.9222, 4.71 }, { 3047, 117.5442, -8.8167, 5.61 }, { 3048, 117.4383, -19.7931, 6.56 }, + { 3049, 117.3113, -34.7567, 5.93 }, { 3050, 117.6975, +3.2772, 6.18 }, { 3051, 117.5238, -18.4764, 6.12 }, { 3052, 117.3975, -32.7111, 5.60 }, + { 3053, 117.9863, +19.3253, 5.99 }, { 3054, 117.7300, -10.8714, 6.16 }, { 3055, 117.3096, -45.6267, 4.11 }, { 3056, 117.0800, -55.5289, 6.33 }, + { 3057, 117.3675, -43.2481, 6.32 }, { 3058, 117.3037, -45.1422, 5.84 }, { 3059, 117.9250, +1.7669, 5.14 }, { 3060, 117.7500, -23.4717, 6.45 }, + { 3061, 118.0300, +3.2772, 6.31 }, { 3062, 117.2779, -55.5894, 5.59 }, { 3063, 117.9204, -11.1806, 6.36 }, { 3064, 117.9429, -12.1019, 5.17 }, + { 3065, 118.6221, +47.3861, 6.25 }, { 3066, 118.6779, +47.5647, 5.45 }, { 3067, 118.3742, +26.7658, 4.97 }, { 3068, 117.9287, -20.8261, 5.63 }, + { 3069, 117.6767, -43.4203, 6.45 }, { 3070, 117.3037, -59.7164, 5.78 }, { 3071, 117.5996, -49.4903, 5.91 }, { 3072, 118.1996, -4.5719, 5.76 }, + { 3073, 118.0788, -13.1536, 5.69 }, { 3074, 117.8354, -42.9044, 6.32 }, { 3075, 120.0488, +73.9181, 5.41 }, { 3076, 117.4783, -59.9489, 6.72 }, + { 3077, 119.1117, +56.5044, 6.72 }, { 3078, 117.9179, -41.1117, 6.04 }, { 3079, 118.0654, -33.2947, 5.01 }, { 3080, 118.0542, -39.4242, 3.73 }, + { 3081, 117.4208, -65.8042, 5.79 }, { 3082, 121.1963, +79.4797, 5.42 }, { 3083, 118.9200, +35.4128, 6.23 }, { 3084, 118.1613, -37.1369, 4.49 }, + { 3085, 118.2646, -35.6361, 5.43 }, { 3086, 118.9163, +19.8839, 5.35 }, { 3087, 118.8808, +8.8628, 5.86 }, { 3088, 118.1238, -53.6328, 5.70 }, + { 3089, 118.2654, -48.3869, 4.63 }, { 3090, 118.3258, -47.8969, 4.24 }, { 3091, 118.5458, -34.1225, 5.49 }, { 3092, 118.6663, -33.1531, 6.15 }, + { 3093, 119.0996, +4.4858, 6.17 }, { 3094, 119.5692, +43.9775, 6.34 }, { 3095, 119.2475, +15.7903, 5.78 }, { 3096, 118.8071, -29.0825, 6.44 }, + { 3097, 119.3163, +8.6414, 6.05 }, { 3098, 119.3175, +1.1269, 6.35 }, { 3099, 119.0950, -29.7147, 6.33 }, { 3100, 118.7521, -51.4169, 6.38 }, + { 3101, 118.9437, -42.1550, 6.02 }, { 3102, 119.2146, -21.1200, 4.20 }, { 3103, 119.5242, +7.2136, 6.41 }, { 3104, 119.6312, +16.5186, 5.99 }, + { 3105, 118.7217, -56.6969, 5.63 }, { 3106, 120.3363, +59.0475, 5.77 }, { 3107, 119.1012, -39.2636, 6.78 }, { 3108, 124.2242, +84.0578, 6.49 }, + { 3109, 120.4267, +60.3244, 6.01 }, { 3110, 119.5858, +2.2247, 5.29 }, { 3111, 119.2412, -41.5939, 6.09 }, { 3112, 120.6283, +63.0903, 6.40 }, + { 3113, 119.4171, -29.6653, 4.79 }, { 3114, 119.2412, -42.4997, 5.35 }, { 3115, 119.8962, +13.2422, 6.02 }, { 3116, 119.3267, -43.8903, 5.09 }, + { 3117, 119.1946, -51.0178, 3.47 }, { 3118, 119.3333, -46.1097, 6.22 }, { 3119, 120.6492, +57.2736, 6.49 }, { 3120, 119.0775, -59.4736, 5.74 }, + { 3121, 119.4658, -44.4222, 5.17 }, { 3122, 119.9338, -2.3203, 4.93 }, { 3123, 119.7738, -22.6894, 5.11 }, { 3124, 120.2329, +25.3928, 5.83 }, + { 3125, 120.2000, +19.8161, 6.25 }, { 3126, 119.2113, -58.8736, 6.25 }, { 3127, 120.2529, +23.5831, 6.34 }, { 3128, 120.1971, +17.3086, 5.55 }, + { 3129, 119.5600, -48.7550, 4.41 }, { 3130, 120.4796, +35.4131, 6.34 }, { 3131, 119.9667, -17.6008, 4.61 }, { 3132, 120.4325, +25.0897, 6.31 }, + { 3133, 119.5892, -50.5514, 6.44 }, { 3134, 120.3763, +16.4553, 5.99 }, { 3135, 120.1838, -1.1183, 6.51 }, { 3136, 120.3075, +4.8797, 5.65 }, + { 3137, 119.7575, -44.7839, 5.99 }, { 3138, 119.4454, -59.6967, 5.60 }, { 3139, 119.3021, -62.7031, 6.14 }, { 3140, 119.8683, -38.7028, 5.24 }, + { 3141, 120.3054, -0.6075, 4.68 }, { 3142, 119.8013, -48.0233, 6.32 }, { 3143, 119.8058, -48.0264, 6.34 }, { 3144, 120.4613, +8.9139, 6.22 }, + { 3145, 120.5663, +2.3344, 4.39 }, { 3146, 120.0817, -44.5431, 6.61 }, { 3147, 119.7104, -59.1756, 5.81 }, { 3148, 120.0621, -47.0186, 6.02 }, + { 3149, 120.8796, +27.7942, 4.94 }, { 3150, 120.6083, -5.6628, 6.33 }, { 3151, 120.1204, -47.1286, 6.12 }, { 3152, 119.9175, -59.7925, 6.33 }, + { 3153, 119.9067, -59.4131, 5.17 }, { 3154, 120.4058, -36.7164, 5.95 }, { 3155, 120.5258, -36.9494, 6.34 }, { 3156, 120.2079, -53.8486, 5.87 }, + { 3157, 120.3454, -53.4850, 6.10 }, { 3158, 121.1883, +18.8422, 6.15 }, { 3159, 120.0833, -62.4325, 4.82 }, { 3160, 120.7671, -31.5361, 5.82 }, + { 3161, 120.3812, -54.5450, 6.28 }, { 3162, 120.6867, -40.6900, 5.52 }, { 3163, 121.2688, +13.1181, 5.12 }, { 3164, 121.4042, +27.5297, 6.21 }, + { 3165, 120.8962, -39.9967, 2.25 }, { 3166, 120.8729, -41.0514, 6.29 }, { 3167, 121.7913, +43.2603, 6.26 }, { 3168, 121.1729, -18.2719, 6.13 }, + { 3169, 121.5767, +22.6356, 5.99 }, { 3170, 121.0675, -31.3250, 5.31 }, { 3171, 119.8171, -72.7553, 6.34 }, { 3172, 121.4567, +0.5736, 6.41 }, + { 3173, 122.1142, +51.5067, 4.84 }, { 3174, 121.6146, -8.7550, 6.23 }, { 3175, 122.5158, +58.2481, 5.93 }, { 3176, 121.9408, +21.5817, 5.30 }, + { 3177, 121.4371, -32.4308, 6.14 }, { 3178, 121.1767, -49.4094, 5.95 }, { 3179, 121.3350, -45.0211, 6.19 }, { 3180, 121.2667, -52.8919, 5.53 }, + { 3181, 122.3463, +42.4306, 6.27 }, { 3182, 123.2033, +68.4742, 5.32 }, { 3183, 121.8250, -19.4453, 5.38 }, { 3184, 122.1767, +13.6408, 6.27 }, + { 3185, 121.8858, -23.6958, 2.81 }, { 3186, 121.1787, -61.1639, 6.30 }, { 3187, 121.6683, -44.7336, 5.05 }, { 3188, 122.1483, -1.0161, 4.34 }, + { 3189, 122.2371, -10.6603, 6.32 }, { 3190, 122.1813, -19.6369, 6.36 }, { 3191, 122.6133, +25.5072, 5.73 }, { 3192, 122.2567, -18.7550, 4.40 }, + { 3193, 122.8400, +38.7314, 6.58 }, { 3194, 122.3688, -15.7511, 5.68 }, { 3195, 122.1567, -36.3186, 6.37 }, { 3196, 122.2779, -29.6775, 6.65 }, + { 3197, 126.1371, +82.4308, 6.32 }, { 3198, 122.7450, +14.6294, 6.23 }, { 3199, 122.2925, -34.5450, 6.20 }, { 3200, 123.4592, +56.4522, 5.85 }, + { 3201, 122.8192, +9.8211, 6.07 }, { 3202, 122.6658, -12.2008, 5.54 }, { 3203, 122.2900, -47.3156, 5.70 }, { 3204, 122.3996, -43.8772, 5.21 }, + { 3205, 122.4488, -41.3594, 6.26 }, { 3206, 122.3721, -46.6542, 4.27 }, { 3207, 122.3833, -46.6633, 1.78 }, { 3208, 123.0529, +17.6478, 5.63 }, + { 3209, 123.0529, +17.6478, 6.02 }, { 3210, 123.0554, +17.6478, 6.20 }, { 3211, 122.8179, -11.0731, 4.72 }, { 3212, 122.8875, -6.2275, 5.36 }, + { 3213, 122.4300, -46.0625, 5.23 }, { 3214, 123.0921, +14.0039, 6.54 }, { 3215, 123.2871, +29.6567, 5.64 }, { 3216, 124.8842, +75.7569, 5.54 }, + { 3217, 122.1021, -62.1989, 6.28 }, { 3218, 122.3900, -55.9144, 5.66 }, { 3219, 122.7567, -36.7078, 6.44 }, { 3220, 122.2529, -60.6975, 4.76 }, + { 3221, 123.9604, +60.3806, 6.45 }, { 3222, 123.2492, +16.5142, 6.01 }, { 3223, 121.9825, -67.3828, 4.35 }, { 3224, 123.4238, +23.1378, 6.56 }, + { 3225, 122.8396, -38.3814, 4.45 }, { 3226, 122.8579, -41.0128, 4.75 }, { 3227, 122.7963, -47.5381, 5.82 }, { 3228, 123.5463, +17.6758, 6.47 }, + { 3229, 123.3333, -14.2117, 4.99 }, { 3230, 123.1917, -28.0892, 6.52 }, { 3231, 123.5875, +13.0483, 6.38 }, { 3232, 123.0000, -45.3558, 5.76 }, + { 3233, 123.2146, -36.0756, 6.43 }, { 3234, 123.1288, -45.7358, 6.03 }, { 3235, 124.4600, +59.5711, 5.64 }, { 3236, 125.1679, +72.4072, 5.98 }, + { 3237, 123.3733, -34.1003, 4.78 }, { 3238, 123.4213, -32.4308, 6.37 }, { 3239, 123.5458, -31.8592, 6.06 }, { 3240, 123.4933, -35.6775, 5.08 }, + { 3241, 123.4950, -35.6589, 6.11 }, { 3242, 123.5550, -34.5094, 5.78 }, { 3243, 123.5121, -39.6519, 4.44 }, { 3244, 123.4008, -45.0081, 5.13 }, + { 3245, 124.8221, +62.5072, 5.71 }, { 3246, 124.5658, +54.1436, 6.27 }, { 3247, 123.3921, -49.8039, 5.51 }, { 3248, 124.1413, +11.7264, 7.13 }, + { 3249, 124.1288, +9.1856, 3.52 }, { 3250, 123.5996, -44.1656, 5.83 }, { 3251, 123.9688, -29.0742, 6.21 }, { 3252, 124.3821, +8.8661, 6.29 }, + { 3253, 123.9954, -34.0972, 6.16 }, { 3254, 125.1088, +57.7433, 5.89 }, { 3255, 124.2258, -20.6797, 6.60 }, { 3256, 123.8471, -49.5506, 6.44 }, + { 3257, 124.3463, -15.7150, 6.16 }, { 3258, 125.1213, +53.5744, 6.49 }, { 3259, 124.5996, -11.3681, 5.98 }, { 3260, 123.8163, -61.0842, 5.16 }, + { 3261, 124.4929, -29.9967, 6.45 }, { 3262, 125.0163, +27.2178, 5.14 }, { 3263, 125.6838, +60.6311, 6.41 }, { 3264, 125.0875, +20.7478, 5.83 }, + { 3265, 124.8129, -9.8342, 6.32 }, { 3266, 124.5725, -34.5483, 5.58 }, { 3267, 124.5525, -36.6258, 6.70 }, { 3268, 125.1338, +24.0222, 5.98 }, + { 3269, 124.9579, +3.9478, 6.05 }, { 3270, 124.6388, -35.3406, 4.45 }, { 3271, 125.0546, +0.9094, 6.18 }, { 3272, 125.0713, -4.6708, 6.13 }, + { 3273, 124.8725, -33.4097, 6.43 }, { 3274, 124.4825, -58.8331, 6.42 }, { 3275, 125.7087, +43.1881, 4.25 }, { 3276, 125.1142, -21.0753, 6.13 }, + { 3277, 125.9521, +53.2197, 5.51 }, { 3278, 125.3342, -0.3978, 6.50 }, { 3279, 125.3383, -19.9208, 5.58 }, { 3280, 124.5788, -64.3867, 5.07 }, + { 3281, 125.4775, -16.4136, 5.75 }, { 3282, 125.3458, -32.9456, 4.83 }, { 3283, 125.3375, -35.5156, 5.20 }, { 3284, 125.8408, +18.3322, 5.95 }, + { 3285, 125.6258, -5.8208, 6.15 }, { 3286, 125.3508, -38.3792, 6.16 }, { 3287, 126.1783, +42.0050, 6.02 }, { 3288, 125.7250, -6.4567, 5.96 }, + { 3289, 125.6950, -12.9453, 6.11 }, { 3290, 125.9800, +10.6319, 6.08 }, { 3291, 125.7079, -25.6519, 5.90 }, { 3292, 126.2704, +35.0114, 6.06 }, + { 3293, 125.3000, -56.0269, 5.97 }, { 3294, 125.6317, -47.5097, 4.82 }, { 3295, 126.1517, -3.2831, 6.01 }, { 3296, 125.8217, -37.7142, 6.32 }, + { 3297, 126.1458, -2.2489, 5.61 }, { 3298, 125.2821, -63.8939, 6.12 }, { 3299, 126.4579, +17.0461, 6.14 }, { 3300, 125.7300, -51.8761, 5.85 }, + { 3301, 124.9542, -70.4850, 5.37 }, { 3302, 125.0029, -70.4947, 5.65 }, { 3303, 127.4425, +67.2975, 5.88 }, { 3304, 126.6154, +27.8936, 5.57 }, + { 3305, 126.3979, +2.1022, 5.73 }, { 3306, 126.4783, +7.5644, 5.13 }, { 3307, 125.6283, -58.4903, 1.86 }, { 3308, 126.2296, -22.8464, 5.68 }, + { 3309, 126.9033, +45.6531, 6.32 }, { 3310, 126.6950, +26.9344, 6.32 }, { 3311, 126.6958, +26.9353, 6.30 }, { 3312, 126.6658, +24.5342, 7.02 }, + { 3313, 126.6671, +24.5353, 7.81 }, { 3314, 126.4150, -2.0936, 3.90 }, { 3315, 126.2654, -23.9539, 5.28 }, { 3316, 126.3296, -20.9542, 6.01 }, + { 3317, 126.4142, -16.5606, 6.44 }, { 3318, 124.6317, -75.0803, 4.07 }, { 3319, 126.6829, +12.6544, 5.50 }, { 3320, 126.4817, -13.0703, 5.98 }, + { 3321, 126.6133, -2.0125, 5.59 }, { 3322, 126.2383, -41.2306, 5.98 }, { 3323, 127.5663, +60.7181, 3.36 }, { 3324, 126.6746, -11.4656, 5.54 }, + { 3325, 126.8217, -5.5903, 6.59 }, { 3326, 126.4663, -41.8467, 5.47 }, { 3327, 126.5733, -38.9406, 6.53 }, { 3328, 126.5758, -38.9397, 7.25 }, + { 3329, 127.1533, +24.1447, 6.10 }, { 3330, 126.3792, -50.2719, 5.17 }, { 3331, 126.7117, -28.7847, 6.73 }, { 3332, 128.2225, +69.3200, 6.31 }, + { 3333, 127.1554, +14.2108, 5.95 }, { 3334, 125.5183, -72.6000, 5.29 }, { 3335, 126.8888, -19.1561, 6.56 }, { 3336, 126.8183, -30.3269, 6.33 }, + { 3337, 127.1217, -1.4828, 6.39 }, { 3338, 127.0821, -7.1839, 6.43 }, { 3339, 126.9729, -25.8675, 6.62 }, { 3340, 125.1604, -76.5156, 4.35 }, + { 3341, 126.6050, -51.1925, 6.05 }, { 3342, 127.2121, -8.2517, 6.00 }, { 3343, 126.9971, -34.8861, 5.75 }, { 3344, 127.1496, -22.9283, 6.51 }, + { 3345, 127.2221, -19.0497, 6.67 }, { 3346, 126.4650, -63.3992, 5.97 }, { 3347, 126.4342, -65.8631, 3.77 }, { 3348, 127.8329, +37.2658, 6.18 }, + { 3349, 126.8642, -54.9883, 6.53 }, { 3350, 126.9021, -52.9114, 5.09 }, { 3351, 128.1396, +53.1147, 6.24 }, { 3352, 129.2029, +74.7236, 6.31 }, + { 3353, 127.3650, -26.6675, 6.70 }, { 3354, 128.6508, +65.1450, 5.47 }, { 3355, 127.8771, +24.0811, 5.75 }, { 3356, 127.2817, -43.8394, 5.79 }, + { 3357, 127.8988, +18.0944, 5.35 }, { 3358, 127.2696, -46.0708, 5.33 }, { 3359, 127.3650, -43.2750, 4.99 }, { 3360, 128.2292, +38.0164, 5.90 }, + { 3361, 127.9775, +9.8144, 6.83 }, { 3362, 127.6192, -31.8406, 5.65 }, { 3363, 127.4400, -45.6681, 5.99 }, { 3364, 127.6233, -35.2789, 6.69 }, + { 3365, 128.3408, +36.4364, 6.24 }, { 3366, 128.1771, +20.4411, 5.33 }, { 3367, 127.8788, -18.4225, 5.42 }, { 3368, 127.4013, -54.8089, 6.36 }, + { 3369, 128.2504, +24.0847, 6.36 }, { 3370, 126.8204, -69.9067, 5.53 }, { 3371, 127.6633, -43.2628, 6.30 }, { 3372, 128.1662, +10.0661, 6.46 }, + { 3373, 127.8525, -38.9358, 6.31 }, { 3374, 128.1387, -14.9706, 6.38 }, { 3375, 127.7950, -46.1333, 6.39 }, { 3376, 128.4379, +13.2572, 6.28 }, + { 3377, 128.6825, +36.4194, 5.78 }, { 3378, 128.4313, +4.7567, 5.87 }, { 3379, 129.9275, +73.6297, 6.15 }, { 3380, 128.5554, +8.4519, 6.03 }, + { 3381, 128.2700, -23.3936, 6.19 }, { 3382, 127.8733, -53.6058, 6.34 }, { 3383, 128.5067, -1.8483, 5.81 }, { 3384, 128.2146, -30.4992, 6.38 }, + { 3385, 128.2442, -33.3661, 6.36 }, { 3386, 128.0200, -52.7878, 5.69 }, { 3387, 128.8308, +19.5900, 6.58 }, { 3388, 128.3329, -37.6289, 6.49 }, + { 3389, 128.4096, -37.1511, 5.96 }, { 3390, 128.3767, -45.0289, 6.24 }, { 3391, 129.7988, +65.0208, 5.64 }, { 3392, 128.8537, +2.7436, 6.33 }, + { 3393, 126.0825, -79.0858, 5.69 }, { 3394, 129.0321, +15.3136, 6.32 }, { 3395, 128.9625, +6.6200, 5.99 }, { 3396, 128.9638, +6.6225, 7.25 }, + { 3397, 128.6321, -31.4014, 6.43 }, { 3398, 128.8675, -6.0178, 5.72 }, { 3399, 128.6221, -36.3886, 6.30 }, { 3400, 129.5925, +53.4014, 5.66 }, + { 3401, 129.7925, +59.9394, 6.48 }, { 3402, 128.8700, -25.1564, 5.96 }, { 3403, 130.0533, +64.3278, 4.60 }, { 3404, 128.8025, -38.0300, 6.47 }, + { 3405, 129.7500, +52.9250, 6.42 }, { 3406, 129.2742, +9.6556, 5.88 }, { 3407, 128.6817, -48.0558, 5.01 }, { 3408, 129.8233, +52.7117, 5.91 }, + { 3409, 129.5792, +32.8019, 5.94 }, { 3410, 129.4142, +5.7036, 4.16 }, { 3411, 129.3629, -3.0664, 6.19 }, { 3412, 129.5217, +9.5747, 6.53 }, + { 3413, 128.9671, -49.0300, 5.80 }, { 3414, 128.8317, -57.9908, 4.86 }, { 3415, 128.8142, -57.7750, 5.26 }, { 3416, 129.5846, -5.3375, 6.51 }, + { 3417, 128.1758, -72.6433, 6.12 }, { 3418, 129.6892, +3.3414, 4.44 }, { 3419, 129.3738, -32.2542, 6.48 }, { 3420, 129.4675, -25.7450, 5.27 }, + { 3421, 129.3329, -39.8525, 6.55 }, { 3422, 130.2546, +45.8339, 5.37 }, { 3423, 130.0762, +31.9419, 6.10 }, { 3424, 129.8525, +8.0172, 6.45 }, + { 3425, 129.6679, -18.2631, 6.33 }, { 3426, 129.4113, -41.0108, 4.14 }, { 3427, 130.0267, +20.0078, 6.39 }, { 3428, 130.0921, +19.6700, 6.44 }, + { 3429, 130.1125, +19.5450, 6.30 }, { 3430, 129.7833, -21.3381, 5.05 }, { 3431, 130.0062, -11.5247, 4.98 }, { 3432, 129.3283, -61.1464, 5.47 }, + { 3433, 129.9271, -28.4389, 4.89 }, { 3434, 129.8421, -35.3931, 6.13 }, { 3435, 129.6871, -52.9094, 6.47 }, { 3436, 130.7508, +46.9011, 6.22 }, + { 3437, 130.2567, -8.9481, 6.63 }, { 3438, 130.0258, -34.6917, 3.97 }, { 3439, 130.0804, -39.7358, 5.20 }, { 3440, 129.8492, -52.5603, 5.48 }, + { 3441, 130.4304, -14.0567, 4.88 }, { 3442, 129.9900, -52.9450, 5.19 }, { 3443, 129.8050, -59.6828, 6.36 }, { 3444, 130.1471, -44.8086, 5.71 }, + { 3445, 130.1567, -45.3511, 3.84 }, { 3446, 130.5408, -10.0339, 6.45 }, { 3447, 130.0733, -51.0781, 3.62 }, { 3448, 130.0725, -52.9847, 5.61 }, + { 3449, 130.8212, +21.4686, 4.66 }, { 3450, 130.8013, +12.6808, 5.64 }, { 3451, 131.0421, +36.9181, 6.33 }, { 3452, 130.3046, -46.6831, 4.77 }, + { 3453, 130.2721, -47.0775, 5.90 }, { 3454, 130.8063, +3.3986, 4.30 }, { 3455, 130.1817, -56.4547, 6.34 }, { 3456, 130.4871, -44.5892, 5.23 }, + { 3457, 130.1542, -58.2389, 4.33 }, { 3458, 130.9988, +4.3347, 6.37 }, { 3459, 130.9183, -6.7664, 4.62 }, { 3460, 129.7717, -69.6131, 5.20 }, + { 3461, 131.1712, +18.1542, 3.94 }, { 3462, 130.5667, -47.9008, 5.51 }, { 3463, 130.7375, -34.0567, 6.42 }, { 3464, 131.3392, +30.6978, 6.13 }, + { 3465, 131.1875, +10.0817, 5.66 }, { 3466, 130.5788, -52.9000, 5.52 }, { 3467, 130.6062, -52.8861, 4.86 }, { 3468, 130.8979, -32.8136, 3.68 }, + { 3469, 131.2554, +5.6806, 6.13 }, { 3470, 132.2058, +66.7081, 6.20 }, { 3471, 130.5871, -54.2258, 6.29 }, { 3472, 131.3367, -1.3992, 6.41 }, + { 3473, 131.2300, -20.8322, 6.11 }, { 3474, 131.6667, +28.7653, 6.57 }, { 3475, 131.6742, +28.7600, 4.02 }, { 3476, 130.9179, -48.1772, 5.16 }, + { 3477, 131.1000, -41.3508, 4.07 }, { 3478, 131.5104, -1.9511, 5.70 }, { 3479, 131.2163, -36.8528, 5.76 }, { 3480, 131.5288, -10.9936, 6.25 }, + { 3481, 131.7333, +12.1100, 5.87 }, { 3482, 131.6942, +6.4189, 3.38 }, { 3483, 131.4554, -24.6125, 6.10 }, { 3484, 131.5938, -12.4522, 4.32 }, + { 3485, 131.1758, -53.2917, 1.96 }, { 3486, 131.8125, -0.1028, 5.29 }, { 3487, 131.5071, -45.9583, 3.91 }, { 3488, 131.5992, -40.8744, 6.21 }, + { 3489, 131.2721, -57.2750, 6.21 }, { 3490, 131.7050, -33.3772, 6.37 }, { 3491, 130.9762, -67.7883, 6.32 }, { 3492, 132.1083, +5.8378, 4.36 }, + { 3493, 132.0204, -5.4414, 6.09 }, { 3494, 131.6275, -44.0872, 5.46 }, { 3495, 131.1250, -64.1744, 6.05 }, { 3496, 131.8288, -45.8444, 5.75 }, + { 3497, 131.9187, -40.2628, 6.36 }, { 3498, 131.6771, -55.2303, 4.49 }, { 3499, 132.6342, +33.2853, 6.25 }, { 3500, 132.3404, -2.5569, 5.31 }, + { 3501, 132.0367, -41.5361, 6.43 }, { 3502, 130.3313, -77.0367, 5.47 }, { 3503, 132.0008, -51.1494, 6.30 }, { 3504, 132.6879, +18.8322, 6.16 }, + { 3505, 133.3442, +61.9622, 5.73 }, { 3506, 133.2746, +59.0561, 6.25 }, { 3507, 132.4371, -20.9514, 6.47 }, { 3508, 132.9867, +43.7267, 5.15 }, + { 3509, 133.0483, +45.3125, 5.99 }, { 3510, 132.7562, +15.3506, 6.38 }, { 3511, 133.0417, +42.0025, 5.99 }, { 3512, 132.4646, -31.2194, 5.21 }, + { 3513, 132.5092, -28.5369, 5.87 }, { 3514, 132.4133, -39.6794, 5.48 }, { 3515, 0.0000, +0.0000, 0.00 }, { 3516, 132.5900, -27.3819, 6.17 }, + { 3517, 132.4683, -38.8583, 6.39 }, { 3518, 132.6329, -26.2900, 4.01 }, { 3519, 133.1442, +32.4742, 5.66 }, { 3520, 132.4487, -44.6919, 4.93 }, + { 3521, 133.1192, +28.2592, 6.23 }, { 3522, 133.1492, +28.3308, 5.95 }, { 3523, 132.8938, -6.8228, 5.54 }, { 3524, 130.8017, -78.9303, 6.05 }, + { 3525, 132.5875, -41.9100, 6.00 }, { 3526, 133.1008, +5.3400, 6.33 }, { 3527, 132.6396, -45.4708, 5.10 }, { 3528, 133.4821, +35.5383, 6.14 }, + { 3529, 133.1279, -12.7664, 6.13 }, { 3530, 132.8663, -41.4956, 6.55 }, { 3531, 134.1563, +64.6039, 5.58 }, { 3532, 133.5613, +30.5794, 5.39 }, + { 3533, 133.1087, -31.4908, 6.50 }, { 3534, 133.1608, -35.4544, 6.42 }, { 3535, 133.2000, -37.2758, 5.82 }, { 3536, 132.9025, -56.3664, 5.59 }, + { 3537, 132.6450, -65.2069, 5.35 }, { 3538, 133.5746, -4.5656, 6.00 }, { 3539, 133.1608, -47.6408, 5.91 }, { 3540, 133.9154, +27.9275, 5.22 }, + { 3541, 133.8454, +17.2314, 6.64 }, { 3542, 133.1700, -51.8708, 6.39 }, { 3543, 131.4800, -78.4956, 5.79 }, { 3544, 132.4596, -71.4492, 6.11 }, + { 3545, 134.2083, +45.6319, 5.74 }, { 3546, 134.1271, +40.2017, 5.89 }, { 3547, 133.8483, +5.9456, 3.11 }, { 3548, 133.4613, -39.5525, 6.47 }, + { 3549, 133.2658, -55.3506, 6.03 }, { 3550, 133.9817, +11.6261, 5.41 }, { 3551, 133.4613, -46.4792, 5.33 }, { 3552, 133.8729, -6.0297, 6.91 }, + { 3553, 133.8733, -6.0289, 6.67 }, { 3554, 133.8017, -17.7586, 5.75 }, { 3555, 134.2358, +32.9103, 5.45 }, { 3556, 133.8812, -26.3181, 4.89 }, + { 3557, 134.1538, +4.2367, 6.14 }, { 3558, 134.2842, +17.1439, 6.17 }, { 3559, 133.9829, -22.1817, 6.39 }, { 3560, 133.4529, -59.6458, 5.78 }, + { 3561, 134.3121, +15.3228, 5.20 }, { 3562, 133.8304, -44.9583, 6.26 }, { 3563, 134.4946, +30.2336, 6.29 }, { 3564, 134.1421, -15.2906, 5.96 }, + { 3565, 134.3967, +15.5814, 5.67 }, { 3566, 134.6146, +35.8025, 6.51 }, { 3567, 134.4250, +9.3878, 6.19 }, { 3568, 133.7250, -57.7600, 6.38 }, + { 3569, 134.8017, +48.0417, 3.14 }, { 3570, 133.7996, -53.0344, 5.71 }, { 3571, 133.7617, -59.3553, 3.84 }, { 3572, 134.6217, +11.8578, 4.25 }, + { 3573, 134.5342, +1.5417, 6.59 }, { 3574, 134.0808, -51.2764, 4.69 }, { 3575, 134.8858, +32.4186, 5.20 }, { 3576, 135.6362, +67.6297, 4.76 }, + { 3577, 134.7950, +18.1347, 6.38 }, { 3578, 134.6829, -15.8672, 5.86 }, { 3579, 135.1600, +41.7828, 3.97 }, { 3580, 135.1283, +37.6044, 6.44 }, + { 3581, 138.8383, +84.1811, 6.33 }, { 3582, 134.2433, -58.7706, 4.92 }, { 3583, 134.4825, -47.4267, 5.87 }, { 3584, 134.9162, -18.7919, 6.18 }, + { 3585, 134.8154, -27.1939, 6.25 }, { 3586, 135.4192, +39.7133, 6.36 }, { 3587, 135.3504, +32.2525, 5.82 }, { 3588, 134.7179, -46.7653, 5.18 }, + { 3589, 135.4538, +27.9028, 6.07 }, { 3590, 135.3808, +5.6408, 6.07 }, { 3591, 135.0225, -40.7461, 4.45 }, { 3592, 136.0017, +54.2839, 5.75 }, + { 3593, 135.0925, -42.8267, 6.07 }, { 3594, 135.9063, +47.1567, 3.60 }, { 3595, 135.6846, +24.4528, 5.45 }, { 3596, 135.4917, +0.4828, 5.67 }, + { 3597, 135.2975, -25.3361, 6.20 }, { 3598, 134.8504, -58.9164, 5.16 }, { 3599, 135.6867, +7.2981, 5.85 }, { 3600, 135.3367, -40.1356, 5.55 }, + { 3601, 136.0412, +27.8983, 6.38 }, { 3602, 135.5267, -38.5975, 6.27 }, { 3603, 136.3504, +48.5303, 5.95 }, { 3604, 135.1904, -59.0361, 5.79 }, + { 3605, 135.4358, -51.8117, 5.23 }, { 3606, 136.2300, +32.3769, 6.46 }, { 3607, 135.7867, -24.4956, 6.74 }, { 3608, 136.6796, +59.3444, 6.45 }, + { 3609, 137.0983, +66.8733, 5.14 }, { 3610, 135.2854, -67.3161, 5.88 }, { 3611, 135.7717, -52.4503, 6.40 }, { 3612, 136.6325, +38.4522, 4.56 }, + { 3613, 136.4933, +5.0922, 4.97 }, { 3614, 136.0387, -46.9022, 3.75 }, { 3615, 135.6117, -65.6039, 4.00 }, { 3616, 137.5967, +67.1347, 4.80 }, + { 3617, 136.8621, +22.9811, 6.40 }, { 3618, 136.7496, +1.4628, 6.17 }, { 3619, 137.2179, +51.6047, 4.48 }, { 3620, 137.0171, +32.5406, 6.50 }, + { 3621, 137.0004, +29.6542, 5.43 }, { 3622, 136.2000, -56.1475, 6.44 }, { 3623, 136.9367, +10.6681, 5.24 }, { 3624, 137.7296, +63.5136, 4.67 }, + { 3625, 137.2129, +33.8822, 5.93 }, { 3626, 137.1971, +26.6292, 5.98 }, { 3627, 137.3396, +22.0456, 5.14 }, { 3628, 137.0121, -24.1417, 4.58 }, + { 3629, 136.6417, -54.1967, 6.11 }, { 3630, 137.1758, -7.4106, 5.60 }, { 3631, 136.8113, -50.7881, 6.73 }, { 3632, 136.5317, -63.5003, 6.37 }, + { 3633, 138.5133, +71.6558, 6.55 }, { 3634, 136.9992, -42.5675, 2.21 }, { 3635, 137.4433, +11.5644, 6.48 }, { 3636, 137.2979, -11.6422, 5.77 }, + { 3637, 137.1813, -25.2322, 6.15 }, { 3638, 137.2679, -17.6714, 5.73 }, { 3639, 137.6613, +30.9631, 5.95 }, { 3640, 137.5871, +21.9964, 6.01 }, + { 3641, 137.3979, -7.2122, 5.46 }, { 3642, 136.4096, -69.4611, 4.71 }, { 3643, 136.2867, -71.3972, 4.48 }, { 3644, 137.4850, -29.6347, 5.59 }, + { 3645, 138.9692, +72.9461, 5.96 }, { 3646, 137.5958, -22.8233, 6.53 }, { 3647, 137.4379, -48.5753, 6.48 }, { 3648, 138.5858, +61.4233, 5.13 }, + { 3649, 137.9817, +5.4683, 6.35 }, { 3650, 138.0733, +14.9961, 6.51 }, { 3651, 138.0538, +3.8672, 6.14 }, { 3652, 138.4508, +43.2178, 5.32 }, + { 3653, 137.9946, -18.2522, 5.73 }, { 3654, 137.7683, -43.1319, 5.00 }, { 3655, 138.1083, -6.8903, 6.11 }, { 3656, 137.9208, -38.7411, 6.00 }, + { 3657, 138.4054, +21.2833, 6.48 }, { 3658, 137.8883, -45.4161, 5.79 }, { 3659, 137.7417, -57.0331, 3.44 }, { 3660, 138.9579, +56.7414, 5.27 }, + { 3661, 138.1275, -42.3864, 5.57 }, { 3662, 139.0471, +54.0219, 4.83 }, { 3663, 137.8192, -61.6828, 3.97 }, { 3664, 138.8096, +34.6336, 5.97 }, + { 3665, 138.5913, +2.3142, 3.88 }, { 3666, 139.9825, +74.0164, 6.50 }, { 3667, 138.3579, -37.3836, 6.31 }, { 3668, 138.3275, -41.7264, 6.29 }, + { 3669, 138.8075, +14.9414, 5.34 }, { 3670, 138.3938, -46.6614, 5.92 }, { 3671, 0.0000, +0.0000, 0.00 }, { 3672, 138.5342, -43.8542, 5.85 }, + { 3673, 138.2317, -58.5856, 5.54 }, { 3674, 138.6021, -42.7725, 5.25 }, { 3675, 138.8537, -14.9753, 6.35 }, { 3676, 139.3800, +46.8172, 5.97 }, + { 3677, 138.7383, -36.3975, 5.86 }, { 3678, 134.1712, -84.3369, 5.42 }, { 3679, 138.5750, -54.4303, 5.27 }, { 3680, 138.8108, -44.4444, 6.25 }, + { 3681, 139.1738, -5.6469, 5.24 }, { 3682, 138.9029, -37.4300, 4.94 }, { 3683, 139.1721, -7.2553, 5.47 }, { 3684, 138.9379, -36.5867, 4.62 }, + { 3685, 138.3000, -68.2828, 1.68 }, { 3686, 139.6083, +35.3642, 5.75 }, { 3687, 139.2813, -13.4264, 5.84 }, { 3688, 139.0175, -43.1014, 6.04 }, + { 3689, 139.4642, +11.5011, 6.41 }, { 3690, 139.7113, +36.8025, 3.82 }, { 3691, 138.8229, -57.6114, 6.02 }, { 3692, 139.0963, -43.7342, 5.12 }, + { 3693, 138.8958, -56.4219, 6.32 }, { 3694, 139.2383, -38.5986, 5.33 }, { 3695, 138.0513, -75.3369, 6.14 }, { 3696, 139.0508, -56.4586, 4.34 }, + { 3697, 140.1825, +51.2661, 6.13 }, { 3698, 140.4304, +56.6992, 5.47 }, { 3699, 139.2725, -58.7247, 2.25 }, { 3700, 139.4263, -53.5047, 6.33 }, + { 3701, 140.2471, +38.1883, 6.12 }, { 3702, 139.8904, -10.6858, 6.62 }, { 3703, 139.5242, -50.9489, 5.26 }, { 3704, 139.8883, -14.1656, 5.78 }, + { 3705, 140.2637, +34.3925, 3.13 }, { 3706, 139.9433, -10.0250, 4.79 }, { 3707, 140.3633, +32.9019, 6.16 }, { 3708, 139.6758, -50.4394, 5.87 }, + { 3709, 140.1208, -8.4442, 4.80 }, { 3710, 139.9496, -33.8967, 6.39 }, { 3711, 140.3142, +15.3711, 6.53 }, { 3712, 139.3217, -67.3106, 5.39 }, + { 3713, 139.4654, -66.9492, 6.11 }, { 3714, 140.2312, -14.3822, 6.33 }, { 3715, 140.1842, -30.2394, 6.82 }, { 3716, 140.1233, -36.4186, 6.05 }, + { 3717, 139.8858, -54.8133, 6.28 }, { 3718, 140.3733, -24.0344, 4.72 }, { 3719, 141.9650, +75.0983, 6.29 }, { 3720, 139.3558, -73.1056, 5.29 }, + { 3721, 139.3642, -73.2653, 5.86 }, { 3722, 141.4342, +63.9408, 6.28 }, { 3723, 140.8825, +25.1831, 6.41 }, { 3724, 140.7121, -8.1611, 6.53 }, + { 3725, 141.2321, +51.5739, 6.31 }, { 3726, 140.4621, -41.8050, 5.58 }, { 3727, 141.0938, +36.5869, 6.67 }, { 3728, 140.2367, -61.5953, 4.81 }, + { 3729, 140.6529, -38.2253, 6.54 }, { 3730, 140.6000, -45.9525, 5.75 }, { 3731, 141.1637, +26.1822, 4.46 }, { 3732, 140.4583, -54.4850, 5.63 }, + { 3733, 140.8013, -27.1661, 4.69 }, { 3734, 140.5283, -54.9892, 2.50 }, { 3735, 140.9367, -36.2428, 6.48 }, { 3736, 141.3854, +16.5856, 6.29 }, + { 3737, 141.0679, -38.5742, 6.06 }, { 3738, 141.3500, -4.8825, 5.59 }, { 3739, 140.9979, -50.2628, 6.08 }, { 3740, 140.8642, -59.6975, 6.30 }, + { 3741, 141.5929, -0.5361, 6.01 }, { 3742, 141.0238, -60.3511, 5.99 }, { 3743, 142.1667, +45.6014, 5.41 }, { 3744, 141.8108, -8.7764, 6.54 }, + { 3745, 141.6867, -27.2125, 6.10 }, { 3746, 141.6188, -39.4981, 6.20 }, { 3747, 142.4483, +55.7456, 6.45 }, { 3748, 141.8967, -7.3414, 1.98 }, + { 3749, 141.8267, -21.6561, 4.69 }, { 3750, 141.9450, -5.9289, 5.38 }, { 3751, 144.2717, +81.3264, 4.29 }, { 3752, 141.3629, -60.0497, 5.77 }, + { 3753, 141.5754, -52.6208, 5.11 }, { 3754, 142.1146, +9.0567, 5.41 }, { 3755, 142.1217, +8.1883, 5.71 }, { 3756, 141.9100, -34.9922, 6.65 }, + { 3757, 142.8821, +63.0619, 3.67 }, { 3758, 142.2592, -0.7431, 6.27 }, { 3759, 142.2871, -1.2311, 4.60 }, { 3760, 142.3521, -1.7947, 6.14 }, + { 3761, 141.6842, -63.0703, 6.05 }, { 3762, 142.3850, -3.7528, 6.26 }, { 3763, 142.3025, -19.2514, 5.66 }, { 3764, 142.6800, +33.6556, 5.85 }, + { 3765, 142.3113, -34.0486, 4.51 }, { 3766, 142.3179, -37.5961, 6.19 }, { 3767, 142.4579, -22.6547, 6.24 }, { 3768, 143.7233, +72.2056, 5.72 }, + { 3769, 142.8850, +35.1031, 5.37 }, { 3770, 142.4771, -25.4103, 5.48 }, { 3771, 143.6204, +69.8303, 4.56 }, { 3772, 142.5942, -14.4228, 5.85 }, + { 3773, 142.9300, +22.9681, 4.31 }, { 3774, 144.0283, +74.3178, 6.46 }, { 3775, 143.2142, +51.6772, 3.17 }, { 3776, 142.1958, -61.7269, 5.92 }, + { 3777, 141.7767, -70.3978, 5.47 }, { 3778, 143.2800, +49.4386, 6.76 }, { 3779, 142.9900, +9.7158, 5.07 }, { 3780, 142.6892, -30.1086, 7.00 }, + { 3781, 142.6921, -30.1106, 6.18 }, { 3782, 142.9863, +11.2997, 4.97 }, { 3783, 142.1275, -65.2981, 5.91 }, { 3784, 142.5217, -50.4828, 5.45 }, + { 3785, 142.9121, -9.4478, 6.14 }, { 3786, 142.6750, -39.5333, 3.60 }, { 3787, 142.9954, -0.8150, 4.57 }, { 3788, 142.9825, -9.6294, 6.13 }, + { 3789, 142.8842, -30.1281, 5.93 }, { 3790, 142.8871, -34.2850, 5.87 }, { 3791, 143.3763, +36.4869, 6.18 }, { 3792, 143.3262, +28.3681, 6.53 }, + { 3793, 142.5975, -57.6383, 5.88 }, { 3794, 143.1725, +1.8642, 6.11 }, { 3795, 141.0379, -79.2131, 5.36 }, { 3796, 143.0850, -18.5997, 5.74 }, + { 3797, 143.5817, +46.9022, 6.52 }, { 3798, 143.0771, -27.3719, 6.46 }, { 3799, 143.7063, +52.0514, 4.50 }, { 3800, 143.5558, +36.3975, 4.55 }, + { 3801, 143.2587, -7.4947, 6.12 }, { 3802, 143.2325, -12.4831, 5.94 }, { 3803, 142.8054, -56.9656, 3.13 }, { 3804, 143.4963, +23.4539, 6.25 }, + { 3805, 143.3338, -6.8100, 6.24 }, { 3806, 144.4842, +73.0806, 6.42 }, { 3807, 143.0804, -39.3506, 5.35 }, { 3808, 143.3021, -20.8842, 5.01 }, + { 3809, 143.7658, +39.6214, 4.81 }, { 3810, 143.3592, -21.1361, 5.91 }, { 3811, 143.8433, +39.9633, 6.76 }, { 3812, 143.2825, -38.8711, 6.43 }, + { 3813, 142.8871, -65.2806, 6.27 }, { 3814, 143.6362, -4.0850, 5.56 }, { 3815, 143.9150, +35.8103, 5.41 }, { 3816, 143.0608, -61.2111, 6.10 }, + { 3817, 143.4354, -48.9950, 5.12 }, { 3818, 143.9704, +14.3797, 6.36 }, { 3819, 143.5367, -50.7447, 5.01 }, { 3820, 144.1788, +31.1617, 5.56 }, + { 3821, 142.9013, -72.9192, 5.47 }, { 3822, 143.8904, -18.4164, 6.31 }, { 3823, 143.7992, -34.1761, 6.49 }, { 3824, 144.8663, +67.2722, 5.94 }, + { 3825, 143.6113, -58.7706, 4.08 }, { 3826, 144.2608, +16.4378, 5.69 }, { 3827, 144.3029, +6.8358, 5.00 }, { 3828, 144.1404, -23.2972, 6.53 }, + { 3829, 144.5904, +40.2397, 5.25 }, { 3830, 144.2508, -24.7033, 5.70 }, { 3831, 144.1054, -47.2486, 6.17 }, { 3832, 144.4646, -8.5756, 6.40 }, + { 3833, 144.2912, -31.8214, 5.63 }, { 3834, 144.6138, +4.6492, 4.68 }, { 3835, 144.3679, -35.9042, 5.98 }, { 3836, 144.2067, -48.6447, 4.35 }, + { 3837, 144.1929, -51.0558, 6.19 }, { 3838, 145.5617, +69.2375, 5.69 }, { 3839, 145.7383, +72.2525, 5.17 }, { 3840, 144.3013, -52.3314, 5.45 }, + { 3841, 144.0213, -63.0494, 6.56 }, { 3842, 144.5062, -42.8089, 5.50 }, { 3843, 146.3783, +78.1347, 6.23 }, { 3844, 144.6696, -38.3858, 6.70 }, + { 3845, 144.9642, -0.8572, 3.91 }, { 3846, 144.9475, -9.4297, 6.31 }, { 3847, 146.8250, +79.1367, 6.17 }, { 3848, 145.0838, -9.2308, 6.37 }, + { 3849, 145.0767, -13.6678, 5.06 }, { 3850, 145.3967, +31.2781, 5.89 }, { 3851, 145.5013, +39.7578, 5.62 }, { 3852, 145.2875, +9.8922, 3.52 }, + { 3853, 145.4104, +25.9128, 6.24 }, { 3854, 145.6796, +48.4311, 6.39 }, { 3855, 145.7792, +54.3636, 6.47 }, { 3856, 144.8375, -60.6719, 4.52 }, + { 3857, 145.6779, +35.0933, 6.14 }, { 3858, 145.3208, -22.4083, 4.77 }, { 3859, 146.1529, +64.9839, 6.17 }, { 3860, 143.4717, -79.0586, 5.11 }, + { 3861, 145.8887, +29.9744, 5.64 }, { 3862, 145.5600, -22.0844, 4.94 }, { 3863, 145.1771, -56.0164, 5.32 }, { 3864, 145.2592, -56.7403, 5.80 }, + { 3865, 146.4808, +63.6533, 6.34 }, { 3866, 145.9329, +14.0217, 5.35 }, { 3867, 145.6725, -34.4983, 6.41 }, { 3868, 145.4492, -54.7858, 6.00 }, + { 3869, 146.1250, +18.8636, 6.50 }, { 3870, 146.6321, +57.1281, 5.20 }, { 3871, 146.0504, -26.2306, 4.79 }, { 3872, 145.8646, -50.7717, 6.15 }, + { 3873, 146.4629, +23.7742, 2.98 }, { 3874, 146.0658, -38.4289, 6.82 }, { 3875, 145.9258, -52.1083, 5.56 }, { 3876, 146.5417, +6.7086, 5.79 }, + { 3877, 146.5971, +11.8100, 5.63 }, { 3878, 146.3408, -29.7972, 6.45 }, { 3879, 146.5983, +1.7856, 5.65 }, { 3880, 146.8579, +11.5683, 6.45 }, + { 3881, 147.1475, +46.0211, 5.09 }, { 3882, 146.8896, +11.4289, 6.02 }, { 3883, 146.4187, -56.8144, 6.46 }, { 3884, 146.3117, -61.4922, 3.69 }, + { 3885, 147.5988, +65.5933, 6.31 }, { 3886, 146.6267, -43.2450, 5.55 }, { 3887, 146.4808, -57.2058, 6.22 }, { 3888, 147.7475, +59.0386, 3.80 }, + { 3889, 147.4588, +21.1794, 6.09 }, { 3890, 146.7754, -64.9281, 3.01 }, { 3891, 146.7779, -64.9275, 6.26 }, { 3892, 147.3671, -36.8136, 5.97 }, + { 3893, 147.6254, +4.3436, 6.24 }, { 3894, 148.0267, +54.0644, 4.59 }, { 3895, 147.1667, -55.5881, 6.06 }, { 3896, 147.7583, +13.0661, 6.46 }, + { 3897, 147.4638, -35.7314, 6.37 }, { 3898, 147.4879, -44.2672, 5.08 }, { 3899, 147.8083, -3.7567, 6.01 }, { 3900, 147.9708, +24.3953, 5.32 }, + { 3901, 147.8400, -5.8183, 6.42 }, { 3902, 146.5858, -75.2239, 5.45 }, { 3903, 147.8696, -13.1533, 4.12 }, { 3904, 147.6750, -45.0656, 5.73 }, + { 3905, 148.1908, +26.0069, 3.88 }, { 3906, 148.0508, +2.4542, 6.02 }, { 3907, 148.0500, +0.0756, 6.35 }, { 3908, 147.9983, -15.4653, 6.08 }, + { 3909, 148.1267, -7.8950, 5.05 }, { 3910, 147.8325, -45.8061, 5.62 }, { 3911, 148.7642, +61.1161, 6.27 }, { 3912, 147.9200, -45.4522, 4.58 }, + { 3913, 147.8004, -58.5742, 5.79 }, { 3914, 147.7321, -61.2547, 5.57 }, { 3915, 148.4288, +5.9583, 5.95 }, { 3916, 148.2417, -26.6678, 6.30 }, + { 3917, 148.9292, +49.8200, 5.27 }, { 3918, 149.5950, +72.8794, 5.83 }, { 3919, 148.5513, -24.0675, 4.88 }, { 3920, 148.2500, -54.6267, 6.48 }, + { 3921, 148.6321, -21.5117, 6.24 }, { 3922, 149.3067, +57.4183, 5.93 }, { 3923, 148.7175, -18.9906, 4.94 }, { 3924, 148.4592, -50.8531, 5.93 }, + { 3925, 148.5733, -44.7161, 5.71 }, { 3926, 149.1083, +8.9331, 5.85 }, { 3927, 148.7138, -49.7561, 5.72 }, { 3928, 149.4212, +41.0556, 5.14 }, + { 3929, 149.4871, +45.4144, 6.30 }, { 3930, 149.0225, -39.1753, 6.41 }, { 3931, 149.1937, -25.4497, 6.28 }, { 3932, 149.1479, -32.5814, 5.84 }, + { 3933, 149.2250, -26.5250, 6.32 }, { 3934, 152.1429, +83.9183, 6.37 }, { 3935, 149.0913, -50.6639, 6.37 }, { 3936, 149.6087, +27.7589, 6.30 }, + { 3937, 149.5558, +12.4447, 5.26 }, { 3938, 149.5317, +8.3142, 6.04 }, { 3939, 149.9654, +56.8119, 5.48 }, { 3940, 149.2158, -53.4322, 3.54 }, + { 3941, 149.2954, -51.3611, 6.12 }, { 3942, 149.9008, +29.6453, 5.73 }, { 3943, 149.4271, -47.5856, 6.05 }, { 3944, 149.0404, -70.6106, 6.35 }, + { 3945, 149.9296, +3.3847, 6.70 }, { 3946, 149.7754, -22.0497, 6.21 }, { 3947, 149.7179, -34.1089, 5.23 }, { 3948, 149.3133, -63.5106, 6.58 }, + { 3949, 149.2488, -68.8981, 6.20 }, { 3950, 150.0533, +8.0442, 4.70 }, { 3951, 150.2529, +31.9236, 5.36 }, { 3952, 150.7038, +21.9492, 5.66 }, + { 3953, 150.1433, -55.0533, 6.52 }, { 3954, 151.1513, +53.8917, 5.74 }, { 3955, 150.4187, -52.6356, 6.20 }, { 3956, 150.7054, -29.4225, 6.54 }, + { 3957, 150.4917, -56.6503, 6.20 }, { 3958, 151.2937, +52.3708, 6.14 }, { 3959, 150.9208, -8.4261, 6.12 }, { 3960, 150.5000, -59.5792, 5.94 }, + { 3961, 151.0350, +3.2011, 6.45 }, { 3962, 150.9225, -24.6833, 6.70 }, { 3963, 151.0121, -17.8983, 5.86 }, { 3964, 150.8354, -45.3639, 6.12 }, + { 3965, 151.0875, -23.7144, 5.70 }, { 3966, 150.7496, -59.8214, 6.19 }, { 3967, 150.7058, -61.8436, 6.42 }, { 3968, 151.0975, -38.0242, 6.43 }, + { 3969, 151.4204, +15.7575, 6.37 }, { 3970, 151.2813, -12.9353, 4.60 }, { 3971, 150.8929, -60.1161, 6.14 }, { 3972, 151.3133, -35.6161, 6.27 }, + { 3973, 151.6975, +5.6114, 6.21 }, { 3974, 151.8575, +35.2447, 4.48 }, { 3975, 151.8333, +16.7628, 3.52 }, { 3976, 151.5471, -46.6300, 5.08 }, + { 3977, 151.7896, -16.8583, 5.60 }, { 3978, 151.5296, -51.8119, 6.52 }, { 3979, 152.0663, +31.6042, 6.24 }, { 3980, 151.9762, +9.9975, 4.37 }, + { 3981, 151.9846, +0.3717, 4.49 }, { 3982, 152.0929, +11.9672, 1.35 }, { 3983, 150.1821, -81.7853, 5.52 }, { 3984, 152.0071, -36.6664, 6.36 }, + { 3985, 152.1904, -9.1153, 6.53 }, { 3986, 152.1479, -14.3883, 6.27 }, { 3987, 152.7454, +40.6614, 6.32 }, { 3988, 152.4854, -11.9042, 6.24 }, + { 3989, 152.5313, -7.5917, 5.91 }, { 3990, 152.2346, -50.1889, 4.86 }, { 3991, 152.5246, -11.1839, 5.31 }, { 3992, 152.3825, -34.1433, 6.13 }, + { 3993, 152.8033, +37.4019, 5.85 }, { 3994, 152.6471, -11.6458, 3.61 }, { 3995, 152.1775, -64.1847, 5.28 }, { 3996, 152.7325, -7.5817, 5.65 }, + { 3997, 151.0317, -80.4342, 6.60 }, { 3998, 152.9092, +13.3550, 6.44 }, { 3999, 152.3413, -60.4508, 5.60 }, { 4000, 152.8242, -6.6833, 6.25 }, + { 4001, 152.6579, -40.2850, 5.98 }, { 4002, 152.3771, -67.3167, 5.81 }, { 4003, 153.0121, -27.3936, 6.28 }, { 4004, 153.2012, +4.6147, 5.77 }, + { 4005, 153.1575, -18.8464, 6.44 }, { 4006, 153.4575, +27.1358, 6.04 }, { 4007, 152.8967, -57.1719, 6.40 }, { 4008, 153.7821, +59.9856, 6.25 }, + { 4009, 152.9437, -57.9394, 5.72 }, { 4010, 153.0958, -51.8367, 6.16 }, { 4011, 153.3308, -26.9711, 6.25 }, { 4012, 153.6238, +21.1678, 6.02 }, + { 4013, 153.3533, -32.9681, 6.38 }, { 4014, 153.7763, +31.4681, 6.46 }, { 4015, 153.4413, -39.6542, 5.90 }, { 4016, 154.5046, +73.0733, 6.40 }, + { 4017, 153.3450, -50.7667, 5.28 }, { 4018, 153.2554, -58.0819, 6.10 }, { 4019, 153.4858, -39.6894, 6.35 }, { 4020, 153.3667, -50.2439, 5.78 }, + { 4021, 154.4608, +71.0606, 6.66 }, { 4022, 153.3383, -60.3411, 6.41 }, { 4023, 153.6842, -41.8781, 3.85 }, { 4024, 154.0600, +29.3106, 5.35 }, + { 4025, 153.3775, -65.6269, 5.16 }, { 4026, 154.5083, +65.1083, 5.82 }, { 4027, 154.1171, +28.6825, 6.49 }, { 4028, 154.0671, +17.7403, 6.55 }, + { 4029, 153.8371, -35.4819, 6.19 }, { 4030, 154.1346, +23.5031, 5.97 }, { 4031, 154.1725, +23.4172, 3.44 }, { 4032, 154.1746, +25.3714, 5.84 }, + { 4033, 154.2742, +42.9144, 3.45 }, { 4034, 154.0379, -10.7967, 6.08 }, { 4035, 154.1696, +13.7283, 5.41 }, { 4036, 153.8812, -42.8875, 5.60 }, + { 4037, 153.4342, -69.9619, 3.32 }, { 4038, 153.8192, -53.0258, 6.16 }, { 4039, 154.3108, +23.1061, 5.82 }, { 4040, 154.1900, -19.3294, 6.57 }, + { 4041, 154.5429, +27.4153, 6.52 }, { 4042, 154.4075, -7.9311, 5.24 }, { 4043, 154.0129, -58.0967, 6.22 }, { 4044, 154.7458, +46.7608, 6.43 }, + { 4045, 154.1675, -50.7950, 6.30 }, { 4046, 154.8617, +48.3969, 6.00 }, { 4047, 155.2642, +68.7475, 5.96 }, { 4048, 154.7529, +24.7117, 6.40 }, + { 4049, 154.5317, -27.0081, 5.34 }, { 4050, 154.2708, -60.6678, 3.40 }, { 4051, 155.0617, +53.7792, 6.45 }, { 4052, 155.1300, +54.2169, 6.00 }, + { 4053, 154.6575, -35.1953, 6.30 }, { 4054, 154.9338, +19.4708, 4.79 }, { 4055, 154.8200, -11.4719, 6.00 }, { 4056, 154.6175, -40.3317, 5.96 }, + { 4057, 154.9929, +19.8417, 2.61 }, { 4058, 154.9942, +19.8406, 3.80 }, { 4059, 154.8842, -4.8942, 6.37 }, { 4060, 154.9975, -8.9411, 6.32 }, + { 4061, 154.6567, -55.8900, 5.81 }, { 4062, 157.4229, +84.2522, 5.50 }, { 4063, 154.9033, -54.9706, 4.57 }, { 4064, 155.2583, +2.2897, 6.66 }, + { 4065, 154.7700, -63.3236, 5.67 }, { 4066, 155.0696, -46.3008, 5.65 }, { 4067, 155.5437, +41.2294, 5.76 }, { 4068, 155.2825, -16.0150, 6.51 }, + { 4069, 155.5821, +41.4994, 3.05 }, { 4070, 155.4596, +14.9756, 6.12 }, { 4071, 155.3696, -22.2892, 6.50 }, { 4072, 156.0329, +65.5664, 4.97 }, + { 4073, 155.4000, -21.4717, 6.51 }, { 4074, 155.2283, -55.9569, 4.50 }, { 4075, 155.7763, +33.9081, 5.90 }, { 4076, 155.5538, -18.1331, 6.13 }, + { 4077, 155.7517, +6.5425, 6.07 }, { 4078, 155.9242, +29.6158, 6.39 }, { 4079, 155.8108, +5.6942, 6.54 }, { 4080, 155.5817, -40.3500, 4.83 }, + { 4081, 156.0358, +33.7186, 5.50 }, { 4082, 155.8604, -3.9258, 5.97 }, { 4083, 155.8046, -29.8378, 6.27 }, { 4084, 157.7692, +82.5586, 5.26 }, + { 4085, 156.0546, +2.3681, 6.32 }, { 4086, 155.8721, -37.9900, 5.33 }, { 4087, 155.9183, -40.0467, 6.27 }, { 4088, 156.3133, +8.7847, 5.61 }, + { 4089, 155.7421, -65.0983, 4.99 }, { 4090, 156.4787, +33.7961, 4.74 }, { 4091, 155.9621, -56.0461, 6.35 }, { 4092, 156.4346, -6.9403, 5.57 }, + { 4093, 156.3217, -41.5319, 6.18 }, { 4094, 156.5225, -15.1636, 3.81 }, { 4095, 156.2475, -57.4236, 5.95 }, { 4096, 156.8667, +41.6008, 6.02 }, + { 4097, 156.7521, +19.3644, 6.15 }, { 4098, 157.0158, +48.7847, 6.44 }, { 4099, 156.5396, -41.2611, 6.13 }, { 4100, 156.9708, +36.7072, 4.21 }, + { 4101, 156.9125, +9.7625, 6.04 }, { 4102, 156.0988, -73.9683, 4.00 }, { 4103, 157.1521, +45.2122, 6.35 }, { 4104, 156.7879, -30.9322, 4.25 }, + { 4105, 156.1846, -72.0283, 6.19 }, { 4106, 157.4762, +65.6261, 6.32 }, { 4107, 156.7042, -53.1225, 5.58 }, { 4108, 157.6108, +64.2575, 6.12 }, + { 4109, 157.1833, -2.2575, 6.05 }, { 4110, 156.8517, -56.3611, 4.66 }, { 4111, 157.0079, -48.5944, 6.10 }, { 4112, 157.6567, +55.9806, 4.84 }, + { 4113, 157.5267, +38.9253, 5.77 }, { 4114, 156.9696, -57.2606, 3.82 }, { 4115, 156.8554, -64.2953, 6.01 }, { 4116, 157.3696, -1.2608, 5.21 }, + { 4117, 157.3708, -28.3364, 5.58 }, { 4118, 157.3975, -29.3928, 5.56 }, { 4119, 157.5729, +0.6369, 5.09 }, { 4120, 157.2192, -63.8278, 5.29 }, + { 4121, 159.0071, +80.4944, 6.52 }, { 4122, 157.7446, -6.3625, 6.20 }, { 4123, 157.7492, -12.4117, 5.58 }, { 4124, 157.9642, +32.3794, 5.90 }, + { 4125, 157.7142, -25.5161, 6.51 }, { 4126, 158.7729, +75.7131, 4.84 }, { 4127, 158.0492, +14.1372, 5.46 }, { 4128, 157.6633, -60.6439, 6.43 }, + { 4129, 157.5363, -65.0150, 6.19 }, { 4130, 157.9525, -27.7625, 6.05 }, { 4131, 158.4317, +53.4975, 6.45 }, { 4132, 158.3079, +40.4256, 4.75 }, + { 4133, 158.2029, +9.3067, 3.85 }, { 4134, 157.8408, -52.2844, 4.89 }, { 4135, 157.9896, -44.9333, 5.74 }, { 4136, 157.9858, -44.9306, 6.09 }, + { 4137, 158.3788, +34.9886, 5.58 }, { 4138, 157.5838, -70.0069, 4.74 }, { 4139, 158.1400, -43.3811, 5.91 }, { 4140, 158.0058, -60.3147, 3.32 }, + { 4141, 158.7904, +57.0828, 5.16 }, { 4142, 157.7583, -72.7783, 4.93 }, { 4143, 158.2371, -46.9967, 5.02 }, { 4144, 158.1983, -57.3331, 6.00 }, + { 4145, 158.5038, -22.2547, 5.08 }, { 4146, 158.7000, +6.9536, 5.08 }, { 4147, 158.3554, -57.8097, 6.14 }, { 4148, 158.7592, +8.6503, 5.67 }, + { 4149, 158.7404, -22.8239, 6.10 }, { 4150, 159.0892, +36.3269, 6.28 }, { 4151, 158.5538, -59.0122, 6.23 }, { 4152, 158.9121, -17.4308, 6.49 }, + { 4153, 158.8038, -38.4372, 5.38 }, { 4154, 158.7937, -42.3353, 6.08 }, { 4155, 159.0725, -9.4167, 6.57 }, { 4156, 159.0696, -15.6556, 6.03 }, + { 4157, 159.0192, -25.3250, 6.29 }, { 4158, 159.1350, -11.7697, 5.70 }, { 4159, 158.8971, -56.4422, 4.45 }, { 4160, 159.2983, -10.2514, 6.52 }, + { 4161, 157.9625, -80.0789, 7.07 }, { 4162, 159.3071, -26.5875, 4.89 }, { 4163, 159.3883, -12.6156, 4.82 }, { 4164, 159.0846, -58.4353, 5.08 }, + { 4165, 159.7738, +53.6683, 5.52 }, { 4166, 159.6800, +31.9761, 4.71 }, { 4167, 159.3254, -47.7742, 3.84 }, { 4168, 159.7817, +37.9100, 5.85 }, + { 4169, 159.3617, -57.2667, 5.45 }, { 4170, 158.8533, -75.6908, 6.30 }, { 4171, 159.6458, -15.1233, 4.91 }, { 4172, 159.7100, -11.5564, 6.04 }, + { 4173, 159.5104, -56.7436, 5.91 }, { 4174, 158.8671, -77.3922, 4.11 }, { 4175, 159.7096, -41.2464, 6.11 }, { 4176, 160.4512, +68.4433, 5.75 }, + { 4177, 159.6879, -58.8169, 4.66 }, { 4178, 160.4858, +65.7164, 5.12 }, { 4179, 159.7475, -57.1831, 5.92 }, { 4180, 159.8267, -54.3967, 4.28 }, + { 4181, 160.7671, +69.0761, 5.00 }, { 4182, 160.3508, -0.2583, 6.26 }, { 4183, 160.2150, -34.2583, 6.37 }, { 4184, 160.5471, +31.6969, 6.02 }, + { 4185, 160.0471, -64.8994, 5.52 }, { 4186, 159.8192, -73.5064, 6.07 }, { 4187, 160.9304, +57.1992, 5.80 }, { 4188, 160.3233, -58.3231, 6.42 }, + { 4189, 160.7575, +26.3256, 5.51 }, { 4190, 160.6304, -12.0250, 6.24 }, { 4191, 160.8871, +46.2039, 5.18 }, { 4192, 160.8542, +23.1883, 5.08 }, + { 4193, 160.8371, +4.7478, 5.79 }, { 4194, 160.6800, -31.2842, 5.64 }, { 4195, 161.2667, +67.4114, 6.00 }, { 4196, 160.5583, -63.5336, 4.82 }, + { 4197, 161.0604, +19.7586, 6.27 }, { 4198, 160.6692, -58.7842, 5.38 }, { 4199, 160.7392, -63.6056, 2.76 }, { 4200, 160.8837, -59.4333, 4.57 }, + { 4201, 161.2892, +2.4881, 6.28 }, { 4202, 161.5938, +57.3658, 6.34 }, { 4203, 161.4663, +30.6822, 5.24 }, { 4204, 160.9633, -63.7511, 5.77 }, + { 4205, 161.0288, -62.0389, 4.82 }, { 4206, 160.4638, -78.2167, 5.97 }, { 4207, 161.5238, +6.3731, 6.37 }, { 4208, 161.6021, +18.8914, 5.49 }, + { 4209, 161.6054, +14.1947, 5.48 }, { 4210, 161.2650, -58.3158, 6.21 }, { 4211, 161.0808, -69.1400, 6.26 }, { 4212, 161.1337, -69.1450, 6.46 }, + { 4213, 161.1104, -71.5561, 6.27 }, { 4214, 161.7167, -16.7033, 5.42 }, { 4215, 162.2083, +65.1322, 6.39 }, { 4216, 161.6925, -48.5800, 2.69 }, + { 4217, 161.5700, -59.3967, 6.25 }, { 4218, 161.9083, -14.7381, 6.67 }, { 4219, 161.5687, -63.4850, 5.34 }, { 4220, 161.6238, -63.7367, 5.23 }, + { 4221, 161.7396, -55.2428, 5.23 }, { 4222, 161.7133, -63.6167, 4.85 }, { 4223, 162.2383, +29.4158, 6.15 }, { 4224, 162.1692, -0.0411, 5.93 }, + { 4225, 162.0592, -30.3117, 5.88 }, { 4226, 161.9113, -56.5322, 6.36 }, { 4227, 162.3142, +10.5453, 5.34 }, { 4228, 162.0225, -58.0808, 6.00 }, + { 4229, 162.3221, -3.9758, 6.61 }, { 4230, 162.4738, +27.9739, 6.04 }, { 4231, 161.3154, -79.5303, 5.47 }, { 4232, 162.4063, -15.8064, 3.11 }, + { 4233, 162.4313, -8.1472, 5.86 }, { 4234, 161.4450, -79.4597, 4.45 }, { 4235, 162.7962, +56.5822, 5.67 }, { 4236, 162.8488, +59.3200, 5.58 }, + { 4237, 162.5754, -7.1022, 5.79 }, { 4238, 162.4875, -33.9419, 5.61 }, { 4239, 162.3504, -58.6764, 5.91 }, { 4240, 162.7725, -2.9075, 5.95 }, + { 4241, 163.1283, +52.5653, 6.65 }, { 4242, 163.1329, +52.5036, 6.44 }, { 4243, 163.3779, +69.8539, 5.93 }, { 4244, 163.0571, +1.0253, 6.38 }, + { 4245, 163.1504, +0.2014, 6.31 }, { 4246, 163.3938, +54.5850, 5.10 }, { 4247, 163.3279, +34.2150, 3.83 }, { 4248, 163.4946, +43.1900, 4.71 }, + { 4249, 163.3537, -1.7447, 6.12 }, { 4250, 163.1288, -56.7594, 5.25 }, { 4251, 163.3729, -19.8611, 5.24 }, { 4252, 163.3871, -14.5544, 6.38 }, + { 4253, 163.4321, -1.8708, 5.45 }, { 4254, 163.6758, +25.4908, 6.20 }, { 4255, 163.5742, -12.2419, 5.66 }, { 4256, 163.7425, +34.0347, 5.72 }, + { 4257, 163.3733, -57.1467, 3.78 }, { 4258, 163.9350, +33.5069, 5.03 }, { 4259, 163.9033, +24.7497, 4.50 }, { 4260, 163.9054, +24.7489, 6.30 }, + { 4261, 163.7983, -19.3350, 6.44 }, { 4262, 163.4250, -69.2797, 5.99 }, { 4263, 163.7542, -41.7489, 6.11 }, { 4264, 164.0604, +42.0083, 6.03 }, + { 4265, 163.9267, +0.7369, 5.91 }, { 4266, 163.6233, -60.1733, 5.93 }, { 4267, 164.0062, +6.1853, 5.81 }, { 4268, 163.1146, -78.4406, 6.33 }, + { 4269, 164.0704, +22.3517, 6.14 }, { 4270, 164.1433, +25.5000, 6.35 }, { 4271, 163.8217, -59.4831, 5.92 }, { 4272, 164.9867, +77.7700, 6.20 }, + { 4273, 164.1796, -36.8622, 4.60 }, { 4274, 164.2829, -49.2350, 5.91 }, { 4275, 164.8246, +51.8822, 6.17 }, { 4276, 164.4517, -58.2681, 6.11 }, + { 4277, 164.8667, +40.4303, 5.05 }, { 4278, 164.8867, +36.0931, 6.00 }, { 4279, 164.3154, -74.9003, 6.13 }, { 4280, 165.0613, +45.5261, 5.47 }, + { 4281, 164.9212, +11.7058, 6.55 }, { 4282, 164.8079, -32.2628, 5.71 }, { 4283, 165.1067, +51.5019, 6.43 }, { 4284, 164.8788, -15.6461, 5.89 }, + { 4285, 165.0858, +42.9114, 6.02 }, { 4286, 165.2742, +63.4211, 6.39 }, { 4287, 164.9437, -17.7011, 4.08 }, { 4288, 165.2100, +39.2122, 5.08 }, + { 4289, 165.0483, -13.9167, 5.88 }, { 4290, 164.8083, -60.6797, 6.16 }, { 4291, 165.1400, +3.6175, 4.84 }, { 4292, 164.9975, -42.1928, 5.81 }, + { 4293, 165.0387, -41.7742, 4.39 }, { 4294, 165.1867, +6.1014, 4.99 }, { 4295, 165.4604, +56.3825, 2.37 }, { 4296, 165.0358, -50.1822, 6.15 }, + { 4297, 165.2383, -14.2072, 6.34 }, { 4298, 165.1700, -30.1606, 6.07 }, { 4299, 165.4571, -1.5153, 4.74 }, { 4300, 165.5825, +20.1797, 4.42 }, + { 4301, 165.9321, +61.7508, 1.79 }, { 4302, 165.6017, -25.1686, 6.23 }, { 4303, 165.8108, +0.7525, 6.14 }, { 4304, 164.8038, -80.4439, 6.71 }, + { 4305, 165.8121, -10.6964, 5.50 }, { 4306, 165.9025, +0.0008, 5.95 }, { 4307, 165.8171, -30.0392, 6.46 }, { 4308, 165.9021, -12.5656, 6.34 }, + { 4309, 166.1300, +38.2414, 6.00 }, { 4310, 166.2542, +7.3361, 4.63 }, { 4311, 166.1300, -46.3208, 5.67 }, { 4312, 164.8075, -83.4061, 6.19 }, + { 4313, 166.2258, -34.1953, 5.43 }, { 4314, 166.3329, -26.7064, 4.94 }, { 4315, 166.3917, -10.9111, 6.09 }, { 4316, 166.2675, -48.6075, 6.13 }, + { 4317, 166.4900, -26.7122, 5.71 }, { 4318, 166.5242, -50.7875, 6.30 }, { 4319, 166.7258, +1.9556, 5.52 }, { 4320, 166.6613, -27.2722, 6.77 }, + { 4321, 166.6142, -49.0433, 6.32 }, { 4322, 166.9154, +23.3236, 6.46 }, { 4323, 166.6221, -57.3247, 6.02 }, { 4324, 166.7850, -31.4128, 6.59 }, + { 4325, 166.6350, -61.5758, 4.61 }, { 4326, 166.6008, -63.1603, 6.41 }, { 4327, 166.8192, -41.3614, 5.15 }, { 4328, 166.9767, -29.8253, 6.54 }, + { 4329, 166.7079, -69.1219, 5.57 }, { 4330, 167.4162, +67.2103, 6.06 }, { 4331, 167.0658, -28.0272, 6.49 }, { 4332, 167.2046, +24.6583, 5.68 }, + { 4333, 167.3296, +36.3094, 5.74 }, { 4334, 167.1829, -27.9194, 5.44 }, { 4335, 167.4158, +44.4986, 3.01 }, { 4336, 167.4104, +43.2075, 5.89 }, + { 4337, 167.1475, -57.0250, 3.91 }, { 4338, 167.1417, -60.0528, 5.13 }, { 4339, 167.4725, -31.6325, 5.81 }, { 4340, 168.0458, +68.2719, 6.40 }, + { 4341, 167.9321, +14.4003, 6.30 }, { 4342, 167.7279, -57.5447, 6.88 }, { 4343, 167.9146, -21.1742, 4.48 }, { 4344, 168.1854, +54.8942, 6.63 }, + { 4345, 168.1342, +35.8136, 6.41 }, { 4346, 168.0617, -31.5661, 6.38 }, { 4347, 168.1267, -17.5000, 6.13 }, { 4348, 168.1442, -20.2508, 6.40 }, + { 4349, 167.8729, -70.5636, 6.35 }, { 4350, 168.1379, -48.8989, 5.36 }, { 4351, 168.4175, +41.0886, 6.33 }, { 4352, 168.1500, -59.6825, 4.60 }, + { 4353, 168.2371, -48.2636, 6.11 }, { 4354, 168.3113, -43.6278, 5.80 }, { 4355, 168.1883, -63.8303, 5.23 }, { 4356, 168.4400, +0.0697, 5.42 }, + { 4357, 168.5271, +20.5236, 2.56 }, { 4358, 168.5075, +8.0606, 5.79 }, { 4359, 168.5600, +15.4294, 3.34 }, { 4360, 168.4137, -52.7683, 5.76 }, + { 4361, 168.3783, -58.3806, 5.74 }, { 4362, 168.8008, +23.0956, 4.63 }, { 4363, 169.0167, +52.7731, 6.50 }, { 4364, 168.7250, -42.2658, 6.21 }, + { 4365, 168.9663, +13.3075, 5.32 }, { 4366, 168.9908, +12.8447, 6.67 }, { 4367, 169.1746, +49.4764, 5.88 }, { 4368, 169.1654, -2.3483, 4.47 }, + { 4369, 169.2425, -6.8653, 6.14 }, { 4370, 169.1154, -44.1200, 6.31 }, { 4371, 169.3225, +2.0106, 5.18 }, { 4372, 169.2992, -37.9856, 6.27 }, + { 4373, 169.4133, -33.2628, 6.45 }, { 4374, 169.5454, +31.5292, 4.87 }, { 4375, 169.5458, +31.5292, 4.41 }, { 4376, 169.4292, -35.4656, 6.68 }, + { 4377, 169.6196, +33.0942, 3.48 }, { 4378, 169.5875, +11.9847, 6.66 }, { 4379, 169.3292, -66.1764, 6.06 }, { 4380, 169.7829, +38.1856, 4.78 }, + { 4381, 169.7292, +1.6506, 5.91 }, { 4382, 169.8354, -13.2214, 3.56 }, { 4383, 170.2242, +67.1006, 6.21 }, { 4384, 169.8187, -63.4175, 5.99 }, + { 4385, 169.6429, -78.3314, 6.35 }, { 4386, 170.2842, +6.0294, 4.05 }, { 4387, 169.9013, -74.8575, 6.27 }, { 4388, 170.4554, +57.0750, 6.43 }, + { 4389, 170.0163, -70.0056, 6.41 }, { 4390, 170.2517, -53.5089, 3.89 }, { 4391, 170.7138, +64.3306, 6.02 }, { 4392, 170.7067, +43.4828, 4.99 }, + { 4393, 170.5963, -43.3542, 6.12 }, { 4394, 170.8250, +0.1317, 6.05 }, { 4395, 170.8413, -17.2200, 5.09 }, { 4396, 170.8029, -35.8353, 5.00 }, + { 4397, 170.4879, -76.3917, 6.43 }, { 4398, 170.7838, -55.2206, 5.79 }, { 4399, 170.9812, +10.5292, 3.94 }, { 4400, 171.0096, +1.4078, 5.39 }, + { 4401, 170.8408, -63.0450, 5.11 }, { 4402, 171.1525, -9.1406, 4.83 }, { 4403, 171.0921, -41.3308, 6.12 }, { 4404, 171.2454, +11.4303, 5.80 }, + { 4405, 171.2204, -16.3161, 4.08 }, { 4406, 171.0462, -71.7433, 5.59 }, { 4407, 171.4879, +55.8506, 5.75 }, { 4408, 171.4017, +16.4564, 5.57 }, + { 4409, 171.3725, -35.9369, 5.22 }, { 4410, 171.4583, +3.8600, 6.37 }, { 4411, 171.3879, -36.2522, 5.89 }, { 4412, 171.6062, +33.4506, 6.32 }, + { 4413, 171.4300, -62.0272, 5.17 }, { 4414, 171.6888, +3.0131, 6.50 }, { 4415, 171.6471, -60.8847, 5.30 }, { 4416, 171.7896, -11.6433, 5.94 }, + { 4417, 171.6971, -52.8400, 5.81 }, { 4418, 171.9842, +2.8561, 4.95 }, { 4419, 171.9738, -0.3000, 6.25 }, { 4420, 171.9938, -34.6714, 6.45 }, + { 4421, 172.2692, +61.7783, 5.83 }, { 4422, 172.2675, +39.3369, 5.31 }, { 4423, 172.1463, -41.3258, 5.08 }, { 4424, 172.4313, +56.7375, 6.28 }, + { 4425, 172.0758, -71.5256, 6.09 }, { 4426, 172.4246, +15.4133, 5.74 }, { 4427, 172.5538, +54.3617, 6.41 }, { 4428, 172.4108, -23.5367, 5.76 }, + { 4429, 172.9600, +81.1272, 6.15 }, { 4430, 172.6042, +46.6575, 6.35 }, { 4431, 172.6296, +43.1733, 5.94 }, { 4432, 172.5788, -2.9964, 4.77 }, + { 4433, 172.6208, +18.4097, 5.52 }, { 4434, 172.8508, +69.3311, 3.84 }, { 4435, 172.7204, +47.9292, 6.42 }, { 4436, 172.7925, +48.7892, 6.56 }, + { 4437, 172.9371, +14.3644, 6.20 }, { 4438, 172.8125, -60.7217, 6.38 }, { 4439, 173.0867, +61.0825, 5.48 }, { 4440, 172.9483, -19.2233, 6.24 }, + { 4441, 172.9421, -58.5578, 5.13 }, { 4442, 172.9533, -58.4842, 5.15 }, { 4443, 173.0671, -28.7367, 5.81 }, { 4444, 173.0679, -28.7389, 5.64 }, + { 4445, 173.0971, -25.2533, 6.16 }, { 4446, 173.1979, -6.1725, 5.95 }, { 4447, 173.2004, -39.5636, 5.64 }, { 4448, 173.0829, -65.0378, 5.90 }, + { 4449, 173.2254, -30.9128, 5.04 }, { 4450, 173.2504, -30.1422, 3.54 }, { 4451, 173.3108, -15.7194, 6.05 }, { 4452, 173.4846, +36.8156, 6.40 }, + { 4453, 173.4054, -39.4131, 5.39 }, { 4454, 173.5417, +11.0236, 6.55 }, { 4455, 173.5917, +3.0600, 5.77 }, { 4456, 173.6771, +16.7969, 5.95 }, + { 4457, 173.7704, +54.7853, 5.63 }, { 4458, 173.6229, -31.1686, 5.98 }, { 4459, 173.7658, +20.4414, 6.45 }, { 4460, 173.6904, -53.7358, 4.62 }, + { 4461, 174.0117, +69.3228, 5.20 }, { 4462, 173.7367, -48.8633, 5.50 }, { 4463, 173.8050, -46.6275, 5.71 }, { 4464, 173.9308, +10.9111, 6.56 }, + { 4465, 174.0746, +27.7811, 5.80 }, { 4466, 173.9817, -46.3583, 5.25 }, { 4467, 173.9450, -62.9803, 3.13 }, { 4468, 174.1704, -8.1978, 4.70 }, + { 4469, 174.1458, -32.4300, 5.74 }, { 4470, 174.1700, -36.7622, 6.31 }, { 4471, 174.2371, +0.8239, 4.30 }, { 4472, 174.0929, -60.9478, 5.83 }, + { 4473, 174.2550, -31.0119, 6.29 }, { 4474, 174.4708, +50.6183, 6.14 }, { 4475, 174.2525, -60.7167, 5.15 }, { 4476, 174.3913, -46.2528, 5.44 }, + { 4477, 174.5858, +43.6256, 5.59 }, { 4478, 174.5408, +8.8842, 6.17 }, { 4479, 174.3150, -74.1033, 5.65 }, { 4480, 174.6396, +46.8342, 6.10 }, + { 4481, 174.7050, +64.3469, 6.46 }, { 4482, 174.6342, +33.6256, 6.27 }, { 4483, 174.6150, +8.1342, 5.36 }, { 4484, 174.6004, -1.5639, 6.22 }, + { 4485, 174.4517, -66.3797, 5.96 }, { 4486, 174.6871, +45.1086, 6.44 }, { 4487, 174.5304, -60.1736, 5.15 }, { 4488, 174.6671, -12.7981, 5.48 }, + { 4489, 174.7517, -23.2789, 6.42 }, { 4490, 174.9629, -13.5314, 6.21 }, { 4491, 174.9600, -15.3797, 6.19 }, { 4492, 174.8725, -64.6022, 5.17 }, + { 4493, 175.1142, +57.9706, 6.37 }, { 4494, 175.0533, -33.2553, 4.70 }, { 4495, 175.1962, +21.3528, 5.26 }, { 4496, 175.2625, +34.2017, 5.33 }, + { 4497, 175.1775, -52.0314, 5.96 }, { 4498, 175.2850, -28.8036, 6.44 }, { 4499, 175.2233, -61.9100, 4.94 }, { 4500, 175.4317, +55.1725, 6.27 }, + { 4501, 175.3929, +31.7461, 5.73 }, { 4502, 175.3325, -42.9042, 5.55 }, { 4503, 175.4333, -31.5003, 5.22 }, { 4504, 175.6183, +66.7450, 5.30 }, + { 4505, 175.5217, +22.2108, 6.59 }, { 4506, 175.5146, -19.7061, 6.22 }, { 4507, 175.2550, -82.9000, 6.33 }, { 4508, 175.8633, -36.8097, 5.98 }, + { 4509, 175.7308, -78.6936, 6.39 }, { 4510, 175.9796, -5.3228, 6.07 }, { 4511, 175.8800, -61.5106, 5.03 }, { 4512, 176.0550, +25.2183, 6.02 }, + { 4513, 175.9704, -61.1217, 6.10 }, { 4514, 176.1908, -17.6492, 4.73 }, { 4515, 176.3212, +8.2583, 4.85 }, { 4516, 176.3025, -48.9303, 6.26 }, + { 4517, 176.4650, +6.5294, 4.03 }, { 4518, 176.5125, +47.7794, 3.71 }, { 4519, 176.4329, -44.3100, 5.29 }, { 4520, 176.4017, -65.2714, 3.64 }, + { 4521, 176.7317, +55.6283, 5.27 }, { 4522, 176.6283, -60.8217, 4.11 }, { 4523, 176.6296, -39.4994, 4.91 }, { 4524, 176.7792, -34.0931, 6.17 }, + { 4525, 176.8154, -29.7131, 6.48 }, { 4526, 176.8296, -56.3036, 5.41 }, { 4527, 176.9963, +20.2189, 4.53 }, { 4528, 176.9787, +8.2458, 5.32 }, + { 4529, 177.0979, -9.6867, 6.26 }, { 4530, 177.0596, -65.1853, 4.72 }, { 4531, 177.1613, +14.2842, 5.88 }, { 4532, 177.1879, -25.2503, 5.11 }, + { 4533, 177.2550, +0.3186, 6.15 }, { 4534, 177.2650, +14.5719, 2.14 }, { 4535, 177.3121, +16.2428, 6.04 }, { 4536, 177.4238, +34.9317, 5.70 }, + { 4537, 177.4212, -62.2117, 4.32 }, { 4538, 177.4858, -69.7742, 4.97 }, { 4539, 177.5813, -14.1361, 6.13 }, { 4540, 177.6738, +1.7647, 3.61 }, + { 4541, 177.6133, -61.3506, 5.70 }, { 4542, 177.6546, -26.7222, 6.48 }, { 4543, 177.7304, +12.2789, 6.35 }, { 4544, 177.7592, -4.6667, 5.64 }, + { 4545, 177.7892, +33.3750, 6.27 }, { 4546, 177.7863, -44.8264, 4.46 }, { 4547, 177.8413, -11.8122, 6.35 }, { 4548, 177.9233, -29.1650, 5.85 }, + { 4549, 177.9633, -64.7939, 4.90 }, { 4550, 178.2450, +37.7186, 6.45 }, { 4551, 178.0421, -55.0122, 5.57 }, { 4552, 178.2275, -32.0919, 4.28 }, + { 4553, 178.3617, -34.9333, 6.17 }, { 4554, 178.4575, +53.6947, 2.44 }, { 4555, 178.4596, +0.5519, 6.30 }, { 4556, 178.5479, -56.5900, 6.06 }, + { 4557, 178.6075, -36.2511, 6.46 }, { 4558, 178.6771, -24.2861, 5.30 }, { 4559, 178.7629, +8.4439, 5.58 }, { 4560, 178.7738, +46.4769, 6.54 }, + { 4561, 178.7967, +46.4697, 7.03 }, { 4562, 178.8088, +36.7564, 6.49 }, { 4563, 178.7492, -62.7211, 5.91 }, { 4564, 178.9187, +15.6467, 5.53 }, + { 4565, 178.9171, -27.5231, 5.93 }, { 4566, 178.9933, +56.5986, 5.84 }, { 4567, 179.0038, -16.8492, 5.18 }, { 4568, 178.9779, -38.3108, 6.13 }, + { 4569, 179.2217, +61.5492, 6.22 }, { 4570, 179.1829, -46.9275, 6.26 }, { 4571, 179.2654, -32.6847, 6.21 }, { 4572, 179.3108, +40.3436, 6.62 }, + { 4573, 179.4171, -61.5511, 5.57 }, { 4574, 179.5300, +32.2739, 6.42 }, { 4575, 179.5858, +61.4647, 6.76 }, { 4576, 179.5633, -55.6828, 5.44 }, + { 4577, 179.5846, -39.0528, 6.79 }, { 4578, 179.6987, -63.6608, 5.61 }, { 4579, 179.7267, -24.0911, 6.43 }, { 4580, 179.7642, +0.5306, 6.17 }, + { 4581, 179.8233, +33.1675, 5.96 }, { 4582, 179.7954, -50.3033, 6.05 }, { 4583, 179.9054, -77.7781, 4.91 }, { 4584, 179.9883, +34.0350, 6.50 }, + { 4585, 179.9871, +3.6553, 5.37 }, { 4586, 180.0775, +80.8531, 6.17 }, { 4587, 180.1854, -9.5539, 5.55 }, { 4588, 180.1771, -20.1628, 6.28 }, + { 4589, 180.2183, +6.6142, 4.66 }, { 4590, 180.2133, -18.3411, 5.26 }, { 4591, 180.2575, -0.2319, 6.31 }, { 4592, 180.3708, -56.4964, 6.16 }, + { 4593, 180.4146, +36.0419, 5.59 }, { 4594, 180.5283, +43.0456, 5.21 }, { 4595, 180.5838, -84.3683, 6.05 }, { 4596, 180.6192, -70.5111, 6.42 }, + { 4597, 180.6571, -68.8078, 5.89 }, { 4598, 180.7150, -6.3164, 6.22 }, { 4599, 180.7562, -62.6872, 4.33 }, { 4600, 180.9150, -41.5658, 5.15 }, + { 4601, 180.9346, -73.7861, 6.44 }, { 4602, 181.0692, +21.4592, 5.87 }, { 4603, 181.0800, -62.8344, 4.72 }, { 4604, 181.1613, -67.6708, 5.35 }, + { 4605, 181.1937, -75.4808, 5.04 }, { 4606, 181.1171, +85.5872, 6.27 }, { 4607, 181.2379, -59.0308, 5.96 }, { 4608, 181.3021, +8.7331, 4.12 }, + { 4609, 181.3129, +76.9058, 5.80 }, { 4610, 181.4154, +62.9331, 6.13 }, { 4611, 181.4717, -64.4528, 6.33 }, { 4612, 181.4863, -34.3061, 6.23 }, + { 4613, 181.4992, -2.8683, 6.37 }, { 4614, 181.5825, -67.3492, 6.23 }, { 4615, 181.5963, -64.2908, 6.06 }, { 4616, 181.7204, -63.3864, 4.15 }, + { 4617, 181.9575, -74.6331, 5.18 }, { 4618, 182.0217, -49.3386, 4.47 }, { 4619, 182.0200, -49.2367, 6.37 }, { 4620, 182.0613, -47.3072, 5.34 }, + { 4621, 182.0896, -49.2775, 2.60 }, { 4622, 182.1025, -59.1528, 6.22 }, { 4623, 182.1033, -23.2711, 4.02 }, { 4624, 182.2242, -43.6739, 5.75 }, + { 4625, 182.2271, -40.7686, 5.48 }, { 4626, 182.4221, +1.8978, 5.95 }, { 4627, 182.4471, +74.6614, 6.35 }, { 4628, 182.5104, -33.2950, 6.17 }, + { 4629, 182.5142, +5.8069, 5.72 }, { 4630, 182.5313, -21.3803, 3.00 }, { 4631, 182.6408, -36.1297, 6.06 }, { 4632, 182.6317, +16.8092, 6.39 }, + { 4633, 182.6921, +27.2814, 6.01 }, { 4634, 182.7704, -60.7225, 6.08 }, { 4635, 182.7663, -22.3975, 5.46 }, { 4636, 182.7621, -44.5772, 6.61 }, + { 4637, 182.8808, -50.6406, 6.23 }, { 4638, 182.9129, -51.6314, 3.96 }, { 4639, 182.7500, +81.7100, 6.00 }, { 4640, 182.9633, +25.8703, 5.66 }, + { 4641, 182.9371, +57.0544, 6.43 }, { 4642, 183.0050, +28.5361, 6.49 }, { 4643, 183.0387, +20.5419, 5.57 }, { 4644, 183.0917, -61.0492, 5.92 }, + { 4645, 183.1950, -69.8481, 6.17 }, { 4646, 183.0496, +77.6164, 5.14 }, { 4647, 183.3042, -33.8744, 6.50 }, { 4648, 183.3554, -37.0708, 5.76 }, + { 4649, 183.4821, -77.4264, 6.35 }, { 4650, 183.3579, +10.2622, 5.85 }, { 4651, 183.4029, -32.2072, 6.33 }, { 4652, 183.5108, -44.2761, 5.31 }, + { 4653, 183.5700, -63.5914, 6.22 }, { 4654, 183.6808, +53.4347, 6.16 }, { 4655, 183.7483, -19.1558, 5.83 }, { 4656, 183.7863, -57.2511, 2.80 }, + { 4657, 183.7942, -9.6875, 6.11 }, { 4658, 183.8771, -40.0869, 6.26 }, { 4659, 183.7854, +70.2000, 5.71 }, { 4660, 183.8567, +57.0325, 3.31 }, + { 4661, 183.9458, -22.6464, 6.54 }, { 4662, 183.9517, -16.4581, 2.59 }, { 4663, 184.0008, +14.8989, 5.10 }, { 4664, 184.0979, -71.3853, 6.22 }, + { 4665, 183.9225, +72.5508, 6.29 }, { 4666, 184.0317, +40.6603, 5.66 }, { 4667, 184.0854, +23.9453, 4.95 }, { 4668, 184.1254, +33.0614, 5.00 }, + { 4669, 184.2750, -64.3072, 6.06 }, { 4670, 184.2637, -15.3064, 6.05 }, { 4671, 184.3921, -66.0392, 4.11 }, { 4672, 184.3729, +53.1911, 5.81 }, + { 4673, 184.3771, +28.9372, 5.70 }, { 4674, 184.5863, -78.6878, 4.26 }, { 4675, 184.4471, -35.9061, 6.15 }, { 4676, 184.4346, +15.1442, 6.34 }, + { 4677, 184.5379, -2.0456, 6.99 }, { 4678, 184.5400, -2.0514, 6.54 }, { 4679, 184.6087, -63.9969, 4.04 }, { 4680, 184.6317, +30.2492, 6.23 }, + { 4681, 184.6679, +0.7872, 5.90 }, { 4682, 184.7488, -54.8569, 5.00 }, { 4683, 184.2142, +86.4361, 6.33 }, { 4684, 184.7587, +26.0078, 6.48 }, + { 4685, 184.8296, +23.0347, 6.27 }, { 4686, 183.8346, +87.7000, 6.28 }, { 4687, 184.7079, +75.1606, 5.38 }, { 4688, 184.8733, +28.1569, 6.33 }, + { 4689, 184.9767, +0.6669, 3.89 }, { 4690, 184.9529, +48.9842, 5.29 }, { 4691, 185.0446, -21.8244, 5.97 }, { 4692, 185.1167, -64.1572, 6.21 }, + { 4693, 185.0821, +26.6194, 5.54 }, { 4694, 185.0737, +26.0019, 6.15 }, { 4695, 185.0875, +3.3125, 4.96 }, { 4696, 185.1404, -21.7842, 5.21 }, + { 4697, 185.1792, +17.7928, 4.74 }, { 4698, 185.1721, +27.0547, 7.13 }, { 4699, 185.2321, -12.4344, 5.14 }, { 4700, 185.3400, -59.5989, 3.59 }, + { 4701, 185.2117, +57.8639, 5.55 }, { 4702, 185.4896, -55.6253, 5.92 }, { 4703, 185.5304, -66.4781, 5.15 }, { 4704, 185.5496, -67.6925, 5.74 }, + { 4705, 185.5450, +24.7739, 6.19 }, { 4706, 185.7054, -56.3239, 5.39 }, { 4707, 185.6263, +25.8461, 4.81 }, { 4708, 185.6333, +5.3056, 6.40 }, + { 4709, 186.4063, -85.8494, 6.33 }, { 4710, 185.8075, -66.3683, 6.36 }, { 4711, 185.8400, -23.1594, 5.68 }, { 4712, 185.8975, -34.5872, 5.32 }, + { 4713, 185.9038, -38.6969, 6.40 }, { 4714, 185.9371, -37.0889, 5.79 }, { 4715, 185.9458, +42.5428, 6.06 }, { 4716, 186.0062, +51.5622, 4.80 }, + { 4717, 186.0771, +26.0986, 5.18 }, { 4718, 186.1863, -40.6158, 6.25 }, { 4719, 186.1113, +25.5828, 6.42 }, { 4720, 186.3221, -64.2294, 6.30 }, + { 4721, 186.2854, -41.4856, 6.11 }, { 4722, 186.2988, -10.3897, 5.95 }, { 4723, 186.3267, -26.2508, 6.09 }, { 4724, 186.3408, -34.8136, 5.73 }, + { 4725, 186.3129, +23.9261, 6.03 }, { 4726, 186.2633, +56.7775, 5.81 }, { 4727, 186.2767, +63.8028, 6.32 }, { 4728, 186.4621, +39.0186, 5.02 }, + { 4729, 186.6288, -62.8775, 4.86 }, { 4730, 186.6496, -62.9008, 1.33 }, { 4731, 186.6521, -62.9006, 1.73 }, { 4732, 186.6317, -50.5492, 4.82 }, + { 4733, 186.6004, +27.2683, 4.95 }, { 4734, 186.7008, -47.0867, 6.26 }, { 4735, 186.7154, -31.1700, 5.55 }, { 4736, 186.8525, -62.2108, 6.00 }, + { 4737, 186.7346, +28.2683, 4.36 }, { 4738, 186.7471, +26.8256, 5.00 }, { 4739, 186.8696, -57.0081, 5.50 }, { 4740, 186.6008, +71.9297, 6.24 }, + { 4741, 186.9254, +8.6103, 6.37 }, { 4742, 186.9558, -15.3681, 6.35 }, { 4743, 187.0100, -49.7694, 3.91 }, { 4744, 187.0788, -63.6586, 6.04 }, + { 4745, 186.8963, +55.7128, 5.70 }, { 4746, 186.9650, -3.3847, 6.22 }, { 4747, 187.1062, -60.2047, 6.22 }, { 4748, 187.0938, -38.9586, 5.44 }, + { 4749, 187.1392, -55.5922, 6.15 }, { 4750, 187.1588, +26.2267, 6.54 }, { 4751, 187.1858, +25.8992, 6.65 }, { 4752, 187.2279, +25.9128, 5.29 }, + { 4753, 187.3621, +24.1089, 5.48 }, { 4754, 187.4746, -55.4753, 5.80 }, { 4755, 187.4913, -40.2639, 6.02 }, { 4756, 187.4300, +20.8961, 5.69 }, + { 4757, 187.4663, -15.4844, 2.95 }, { 4758, 187.5200, -12.6069, 6.35 }, { 4759, 187.5729, -22.3033, 5.63 }, { 4760, 187.4888, +58.4058, 5.35 }, + { 4761, 187.5121, +51.5356, 6.21 }, { 4762, 187.5179, +58.7675, 6.08 }, { 4763, 187.7912, -56.8867, 1.63 }, { 4764, 187.8196, -56.9189, 6.42 }, + { 4765, 187.5279, +69.2011, 4.95 }, { 4766, 187.7525, +24.5672, 5.46 }, { 4767, 187.7088, +53.0767, 6.21 }, { 4768, 187.9179, -58.5761, 5.48 }, + { 4769, 188.0417, -72.9983, 5.88 }, { 4770, 187.8392, +7.6042, 6.05 }, { 4771, 187.9825, -62.4939, 5.95 }, { 4772, 187.9113, -4.9475, 6.19 }, + { 4773, 188.1167, -71.8669, 3.87 }, { 4774, 188.0188, -31.4664, 6.46 }, { 4775, 188.0175, -15.8039, 4.31 }, { 4776, 188.1500, -12.1408, 5.74 }, + { 4777, 188.2621, +10.2956, 6.26 }, { 4778, 188.3433, -18.2081, 6.26 }, { 4779, 188.3929, -11.1697, 5.58 }, { 4780, 188.3925, +24.2831, 6.29 }, + { 4781, 188.4450, -8.5481, 5.48 }, { 4782, 188.4967, -48.0906, 6.38 }, { 4783, 188.4121, +33.2475, 5.42 }, { 4784, 188.4475, +33.3847, 6.24 }, + { 4785, 188.4354, +41.3575, 4.26 }, { 4786, 188.5967, -22.6033, 2.65 }, { 4787, 188.3708, +69.7883, 3.87 }, { 4788, 188.6763, -43.3267, 5.77 }, + { 4789, 188.7129, +22.6292, 4.81 }, { 4790, 188.8708, -60.1581, 6.22 }, { 4791, 188.7763, +18.3772, 6.56 }, { 4792, 188.7825, +18.3769, 5.02 }, + { 4793, 188.7838, +21.8814, 5.85 }, { 4794, 188.9396, -40.9781, 5.13 }, { 4795, 188.6833, +70.0219, 4.94 }, { 4796, 189.0050, -38.1300, 5.80 }, + { 4797, 188.9942, -19.4728, 6.20 }, { 4798, 189.2958, -68.8644, 2.69 }, { 4799, 189.1975, -4.1681, 5.87 }, { 4800, 189.0971, +59.4869, 5.50 }, + { 4801, 189.2429, +17.0894, 5.68 }, { 4802, 189.4258, -47.4589, 3.86 }, { 4803, 189.4258, -26.8611, 5.45 }, { 4804, 189.8104, -74.6306, 6.49 }, + { 4805, 189.5183, +3.2825, 6.33 }, { 4806, 189.7188, -66.8069, 6.25 }, { 4807, 189.5933, +1.8547, 5.71 }, { 4808, 189.6250, +6.9883, 7.08 }, + { 4809, 189.6858, -17.7497, 6.00 }, { 4810, 189.7646, -29.5778, 5.89 }, { 4811, 189.6929, +40.8744, 6.37 }, { 4812, 189.7587, +22.6594, 6.38 }, + { 4813, 189.8117, -6.0044, 4.66 }, { 4814, 189.9817, -65.4883, 6.26 }, { 4815, 189.7804, +21.0625, 5.46 }, { 4816, 189.8204, +35.9519, 6.45 }, + { 4817, 189.9688, -38.0125, 4.64 }, { 4818, 190.3458, -45.8544, 5.84 }, { 4819, 190.3792, -47.0403, 2.17 }, { 4820, 190.5213, -68.5925, 6.33 }, + { 4821, 190.3167, -12.9864, 6.08 }, { 4822, 190.3175, -12.9850, 5.98 }, { 4823, 190.4858, -58.3142, 4.93 }, { 4824, 190.3933, +10.4264, 6.19 }, + { 4825, 190.4150, -0.5506, 3.65 }, { 4826, 190.4150, -0.5506, 3.68 }, { 4827, 190.4550, -18.2414, 6.03 }, { 4828, 190.4713, +10.2356, 4.88 }, + { 4829, 190.4879, +6.8067, 5.59 }, { 4830, 190.7096, -62.9414, 5.31 }, { 4831, 190.6475, -47.1869, 4.66 }, { 4832, 190.7067, -54.0528, 6.08 }, + { 4833, 190.3913, +62.7131, 6.07 }, { 4834, 190.7879, -55.8239, 6.00 }, { 4835, 190.8675, -57.0969, 6.40 }, { 4836, 190.8596, -39.8222, 6.44 }, + { 4837, 190.9088, -0.4231, 5.93 }, { 4838, 190.9946, -35.6508, 6.39 }, { 4839, 191.0021, -27.6761, 5.48 }, { 4840, 190.7675, +61.1556, 6.38 }, + { 4841, 191.2571, -67.1689, 6.16 }, { 4842, 191.4079, -59.0189, 4.69 }, { 4843, 191.1129, +44.1031, 6.33 }, { 4844, 191.5704, -67.8919, 3.05 }, + { 4845, 191.2479, +39.2789, 5.95 }, { 4846, 191.2825, +45.4403, 4.99 }, { 4847, 191.4046, +7.6733, 5.22 }, { 4848, 191.5946, -55.5111, 4.65 }, + { 4849, 191.5938, +9.5400, 5.67 }, { 4850, 191.6917, -32.6844, 5.86 }, { 4851, 191.6613, +16.5775, 5.12 }, { 4852, 191.1083, +80.6211, 6.40 }, + { 4853, 191.9300, -58.3114, 1.25 }, { 4854, 191.7596, +5.9508, 6.34 }, { 4855, 191.8067, +11.9581, 6.07 }, { 4856, 191.8892, -5.6981, 6.26 }, + { 4857, 191.9738, -23.1483, 6.44 }, { 4858, 191.9642, +3.5728, 6.41 }, { 4859, 191.8288, +62.7808, 5.89 }, { 4860, 192.1100, -26.4025, 5.66 }, + { 4861, 192.0596, +13.5531, 6.56 }, { 4862, 192.4371, -70.0136, 5.55 }, { 4863, 191.8933, +66.7903, 5.43 }, { 4864, 192.1958, +24.8403, 6.31 }, + { 4865, 192.2258, +14.1225, 5.70 }, { 4866, 192.1742, +48.4669, 6.27 }, { 4867, 192.1642, +60.3200, 5.85 }, { 4868, 192.5500, -59.5992, 6.75 }, + { 4869, 192.3225, +27.5522, 5.78 }, { 4870, 193.7442, -84.8767, 5.46 }, { 4871, 192.5817, -47.5403, 6.24 }, { 4872, 192.7413, -51.2125, 5.73 }, + { 4873, 192.5725, +22.8633, 6.43 }, { 4874, 192.6717, -32.0006, 4.91 }, { 4875, 192.5446, +37.5169, 5.89 }, { 4876, 192.8242, -59.6703, 5.72 }, + { 4877, 192.8454, -9.6617, 6.41 }, { 4878, 192.9038, +3.0567, 6.02 }, { 4879, 192.9867, -38.3192, 5.98 }, { 4880, 193.0221, -47.9058, 6.33 }, + { 4881, 192.9913, -25.2619, 6.15 }, { 4882, 193.1025, -52.1706, 6.24 }, { 4883, 192.9246, +27.5406, 4.94 }, { 4884, 193.0513, +17.0739, 6.32 }, + { 4885, 193.2663, -53.0475, 5.93 }, { 4886, 193.1150, +16.1225, 6.30 }, { 4887, 193.3408, -59.6714, 5.76 }, { 4888, 193.2788, -47.0567, 4.33 }, + { 4889, 193.3592, -39.8211, 4.27 }, { 4890, 193.4546, -59.6231, 5.90 }, { 4891, 193.2967, -2.4469, 6.11 }, { 4892, 192.2775, +83.4181, 5.85 }, + { 4893, 192.3067, +83.4128, 5.28 }, { 4894, 193.3242, +21.2450, 4.90 }, { 4895, 193.5917, -57.5694, 6.58 }, { 4896, 193.4088, -3.7761, 6.44 }, + { 4897, 193.6633, -58.8533, 4.62 }, { 4898, 193.6483, -56.8222, 4.03 }, { 4899, 193.6533, -56.8317, 5.17 }, { 4900, 193.4571, +12.4186, 6.25 }, + { 4901, 193.5779, -10.3514, 6.00 }, { 4902, 193.5883, -8.4611, 4.79 }, { 4903, 193.7438, -43.8481, 5.89 }, { 4904, 193.5546, +33.5344, 6.26 }, + { 4905, 193.5071, +55.9597, 1.77 }, { 4906, 193.8308, -41.0842, 5.47 }, { 4907, 194.1312, -71.8147, 5.93 }, { 4908, 193.9875, -55.1639, 5.32 }, + { 4909, 193.7354, +47.1967, 5.84 }, { 4910, 193.9008, +3.3975, 3.38 }, { 4911, 193.9721, -14.6731, 6.17 }, { 4912, 194.1254, -25.5397, 6.62 }, + { 4913, 194.2683, -50.8014, 5.16 }, { 4914, 194.0017, +38.3147, 5.60 }, { 4915, 194.0071, +38.3183, 2.90 }, { 4916, 193.8688, +65.4386, 5.24 }, + { 4917, 194.0733, +54.0994, 5.82 }, { 4918, 194.3883, -21.2461, 6.31 }, { 4919, 194.2821, +46.1769, 6.12 }, { 4920, 194.7308, +17.4094, 4.78 }, + { 4921, 194.9146, -2.1881, 5.79 }, { 4922, 195.1358, -32.4947, 6.02 }, { 4923, 195.5675, -70.4511, 3.62 }, { 4924, 195.0687, +30.7850, 4.90 }, + { 4925, 195.1496, -2.6314, 5.99 }, { 4926, 195.1617, +18.3731, 6.20 }, { 4927, 194.6971, +75.4725, 6.01 }, { 4928, 194.9796, +66.5972, 5.32 }, + { 4929, 195.2900, +17.1231, 5.96 }, { 4930, 195.7717, -70.5239, 6.03 }, { 4931, 195.1825, +56.3664, 4.93 }, { 4932, 195.5442, +10.9592, 2.83 }, + { 4933, 195.8883, -48.4728, 4.85 }, { 4934, 195.4450, +63.6103, 6.00 }, { 4935, 195.9421, -19.4169, 5.58 }, { 4936, 195.6683, +59.7161, 6.53 }, + { 4937, 195.9767, -2.3367, 6.59 }, { 4938, 196.2004, -40.8033, 6.26 }, { 4939, 196.3783, -51.8850, 6.43 }, { 4940, 196.5696, -47.5364, 4.71 }, + { 4941, 196.6463, -40.4114, 5.59 }, { 4942, 196.7275, -48.0939, 4.27 }, { 4943, 196.4354, +35.7989, 5.25 }, { 4944, 196.8508, -58.1394, 5.99 }, + { 4945, 196.4679, +45.2686, 5.63 }, { 4946, 196.5883, +21.1533, 5.99 }, { 4947, 196.7262, -34.1381, 6.54 }, { 4948, 196.5425, +29.0294, 6.54 }, + { 4949, 196.5942, +22.6161, 5.60 }, { 4950, 196.2071, +73.0253, 6.31 }, { 4951, 196.9096, -52.5403, 5.71 }, { 4952, 197.0292, -64.6936, 5.51 }, + { 4953, 196.5946, +62.0419, 6.14 }, { 4954, 196.7946, +27.6247, 4.80 }, { 4955, 196.9742, -9.2597, 5.19 }, { 4956, 196.9733, +27.5558, 6.19 }, + { 4957, 197.1354, -7.0156, 5.55 }, { 4958, 197.2637, -22.8819, 4.95 }, { 4959, 197.3100, -8.4617, 6.32 }, { 4960, 197.3017, +10.0222, 5.78 }, + { 4961, 197.4388, -9.6706, 5.94 }, { 4962, 197.4492, +16.8486, 5.91 }, { 4963, 197.4875, -4.4611, 4.38 }, { 4964, 197.4113, +37.4231, 6.02 }, + { 4965, 197.7433, -51.4331, 6.06 }, { 4966, 197.9650, -68.0581, 5.91 }, { 4967, 197.4250, +38.5339, 6.28 }, { 4968, 197.4971, +17.5294, 5.22 }, + { 4969, 197.4971, +17.5294, 5.22 }, { 4970, 197.7867, -41.7669, 5.79 }, { 4971, 197.5133, +38.4989, 5.91 }, { 4972, 197.9713, -62.6972, 6.33 }, + { 4973, 197.8467, -42.6311, 5.25 }, { 4974, 197.4592, +62.2292, 6.54 }, { 4975, 198.0725, -58.0792, 4.60 }, { 4976, 198.5717, -77.5528, 5.85 }, + { 4977, 198.2038, -65.7731, 5.90 }, { 4978, 197.9133, -25.4483, 6.50 }, { 4979, 198.0133, -36.1969, 4.85 }, { 4980, 198.2333, -58.1833, 6.16 }, + { 4981, 198.0146, -15.8014, 5.04 }, { 4982, 198.2121, -41.3003, 6.22 }, { 4983, 197.9683, +27.8781, 4.26 }, { 4984, 198.0350, +24.2581, 6.33 }, + { 4985, 198.3479, -49.3000, 5.89 }, { 4986, 198.1371, +11.5561, 5.77 }, { 4987, 198.1496, +18.7517, 6.53 }, { 4988, 198.5504, -57.3161, 5.89 }, + { 4989, 198.5617, -58.8967, 4.92 }, { 4990, 198.3617, -17.1733, 6.28 }, { 4991, 198.4896, -42.8611, 6.16 }, { 4992, 198.3017, +18.7269, 6.11 }, + { 4993, 198.8121, -66.1056, 4.80 }, { 4994, 198.8571, -68.3203, 6.37 }, { 4995, 198.5454, -18.0692, 5.33 }, { 4996, 198.6796, -47.0433, 5.89 }, + { 4997, 198.4292, +40.1528, 4.92 }, { 4998, 198.6304, +11.3317, 5.67 }, { 4999, 198.7904, -35.6289, 6.19 }, { 5000, 199.1867, -64.8617, 6.07 }, + { 5001, 198.9950, -18.0569, 5.22 }, { 5002, 199.3042, -65.2164, 4.87 }, { 5003, 198.3833, +72.7989, 6.59 }, { 5004, 198.8833, +40.8553, 5.79 }, + { 5005, 199.1062, -0.6094, 6.68 }, { 5006, 199.2213, -30.4939, 5.10 }, { 5007, 199.0596, +19.0517, 6.45 }, { 5008, 199.3079, -42.0206, 5.84 }, + { 5009, 198.1058, +80.4714, 6.25 }, { 5010, 199.1346, +19.7853, 6.45 }, { 5011, 199.1937, +9.4242, 5.22 }, { 5012, 199.8288, -71.9644, 6.04 }, + { 5013, 199.3150, +13.6756, 5.33 }, { 5014, 199.3746, +0.6767, 6.37 }, { 5015, 199.4013, +5.4697, 4.80 }, { 5016, 199.6442, -50.7139, 6.19 }, + { 5017, 199.3854, +40.5725, 4.73 }, { 5018, 199.1192, +68.4081, 6.20 }, { 5019, 199.6012, -17.6886, 4.74 }, { 5020, 199.7304, -22.8283, 3.00 }, + { 5021, 199.7129, +3.6878, 6.62 }, { 5022, 199.6158, +34.0981, 5.82 }, { 5023, 199.5604, +49.6819, 5.15 }, { 5024, 200.1454, -58.2267, 6.18 }, + { 5025, 199.7675, +35.1281, 6.02 }, { 5026, 200.1575, -51.2519, 5.48 }, { 5027, 200.2012, -54.1994, 6.02 }, { 5028, 200.1492, -35.2878, 2.75 }, + { 5029, 200.2404, -45.1194, 5.77 }, { 5030, 200.7192, -71.8533, 6.05 }, { 5031, 200.1733, +2.9417, 6.26 }, { 5032, 200.0792, +40.1506, 5.60 }, + { 5033, 200.3746, -18.5111, 6.21 }, { 5034, 200.6488, -59.0278, 6.18 }, { 5035, 200.6579, -59.0117, 4.53 }, { 5036, 200.5675, -51.8169, 5.83 }, + { 5037, 200.4233, +2.0872, 5.69 }, { 5038, 200.7196, -46.0569, 6.16 }, { 5039, 200.7608, -47.4372, 6.38 }, { 5040, 200.5404, +5.1547, 5.87 }, + { 5041, 201.0021, -63.4642, 4.53 }, { 5042, 201.2796, -73.1122, 5.05 }, { 5043, 200.7863, -32.8100, 6.22 }, { 5044, 200.7546, -16.2647, 5.37 }, + { 5045, 200.5158, +43.9031, 6.35 }, { 5046, 200.9679, -48.1769, 6.48 }, { 5047, 200.8288, -3.0756, 5.89 }, { 5048, 201.3079, -63.5147, 5.31 }, + { 5049, 201.4588, -69.3725, 5.67 }, { 5050, 201.1383, -4.8361, 5.75 }, { 5051, 201.8262, -73.3081, 6.63 }, { 5052, 200.9750, +37.0339, 6.07 }, + { 5053, 201.1271, +12.4319, 6.44 }, { 5054, 200.9812, +54.9253, 2.27 }, { 5055, 200.9850, +54.9217, 3.95 }, { 5056, 201.2983, -10.8386, 0.98 }, + { 5057, 201.2779, +23.8544, 5.78 }, { 5058, 201.5325, -38.2447, 5.09 }, { 5059, 201.5475, -0.8075, 5.97 }, { 5060, 201.7337, -40.5019, 5.69 }, + { 5061, 201.7763, -48.8561, 6.31 }, { 5062, 201.3063, +54.9881, 4.01 }, { 5063, 201.8367, -48.6192, 6.28 }, { 5064, 201.6800, -11.2922, 5.25 }, + { 5065, 201.8113, -39.8369, 6.40 }, { 5066, 202.1933, -68.3719, 6.20 }, { 5067, 201.5692, +46.0281, 5.88 }, { 5068, 201.8633, -14.0264, 4.76 }, + { 5069, 202.2817, -63.3242, 6.11 }, { 5070, 201.4996, +63.2611, 6.50 }, { 5071, 202.3550, -50.8347, 5.06 }, { 5072, 202.1075, +13.7789, 4.98 }, + { 5073, 201.5338, +72.3914, 5.79 }, { 5074, 201.7692, +64.7356, 6.66 }, { 5075, 201.7946, +64.7194, 7.04 }, { 5076, 201.9979, +52.7458, 6.34 }, + { 5077, 202.1092, +40.7297, 6.47 }, { 5078, 202.3121, -0.6356, 6.43 }, { 5079, 202.0488, +50.5872, 6.80 }, { 5080, 202.4283, -22.7186, 4.97 }, + { 5081, 202.3042, +10.8183, 5.65 }, { 5082, 203.3117, -76.4317, 6.48 }, { 5083, 202.1904, +50.7183, 6.43 }, { 5084, 205.2312, -84.2139, 5.58 }, + { 5085, 202.1129, +59.9458, 5.40 }, { 5086, 202.5004, +7.1789, 6.17 }, { 5087, 202.4900, +6.0133, 6.51 }, { 5088, 202.6071, -5.5297, 6.09 }, + { 5089, 202.7612, -38.5925, 3.88 }, { 5090, 202.8887, -27.8872, 6.47 }, { 5091, 201.7363, +78.6439, 5.77 }, { 5092, 203.0221, -37.6008, 6.16 }, + { 5093, 203.3988, -64.3675, 6.37 }, { 5094, 203.0117, -17.2711, 6.01 }, { 5095, 202.9913, -5.7442, 4.69 }, { 5096, 202.8158, +42.1061, 6.08 }, + { 5097, 203.1496, -27.3072, 5.69 }, { 5098, 203.1438, -28.4347, 6.45 }, { 5099, 203.2154, -14.6369, 5.55 }, { 5100, 203.2421, -9.8350, 5.21 }, + { 5101, 203.2529, -6.8050, 6.68 }, { 5102, 203.2004, +24.3464, 6.11 }, { 5103, 203.6204, -47.7278, 6.33 }, { 5104, 203.6817, -32.6892, 6.44 }, + { 5105, 203.5329, +3.6589, 4.94 }, { 5106, 203.6687, -12.7856, 5.91 }, { 5107, 203.6733, +0.5958, 3.37 }, { 5108, 203.5908, +38.7892, 6.37 }, + { 5109, 203.5304, +55.3486, 5.60 }, { 5110, 203.6992, +37.1825, 4.98 }, { 5111, 203.8804, -4.6039, 5.73 }, { 5112, 203.6138, +49.0161, 4.70 }, + { 5113, 204.3008, -60.3081, 5.63 }, { 5114, 203.8887, +10.2047, 6.49 }, { 5115, 204.7996, -74.3161, 6.34 }, { 5116, 203.8088, +44.1969, 6.84 }, + { 5117, 204.2104, -33.5322, 6.50 }, { 5118, 204.2750, -43.8567, 5.98 }, { 5119, 204.6904, -69.5550, 6.10 }, { 5120, 204.2017, -25.5050, 5.78 }, + { 5121, 204.3488, -45.5717, 5.90 }, { 5122, 204.5317, -57.5850, 6.42 }, { 5123, 204.2463, +24.6133, 5.74 }, { 5124, 204.7046, -56.3769, 6.01 }, + { 5125, 205.0025, -69.2117, 6.59 }, { 5126, 204.1658, +49.4867, 6.49 }, { 5127, 204.3650, +36.2950, 4.82 }, { 5128, 204.6750, -28.4392, 5.83 }, + { 5129, 204.5329, +14.3017, 6.52 }, { 5130, 205.0454, -63.4231, 5.79 }, { 5131, 203.6783, +76.5467, 6.57 }, { 5132, 204.9717, -52.5336, 2.30 }, + { 5133, 204.4292, +50.7147, 6.48 }, { 5134, 204.9988, -48.0497, 6.00 }, { 5135, 204.9200, -38.2519, 6.27 }, { 5136, 204.9525, -39.9481, 5.60 }, + { 5137, 204.7596, +18.2653, 6.48 }, { 5138, 204.8942, +10.7461, 5.57 }, { 5139, 204.2958, +71.2422, 5.50 }, { 5140, 205.5046, -57.2128, 5.38 }, + { 5141, 205.4363, -53.4400, 5.01 }, { 5142, 204.8767, +52.9214, 5.46 }, { 5143, 205.0650, +31.0119, 6.21 }, { 5144, 205.1687, +19.9556, 5.75 }, + { 5145, 205.1629, +28.0653, 6.23 }, { 5146, 205.3788, -22.5503, 6.59 }, { 5147, 205.4404, -32.4031, 6.05 }, { 5148, 205.0967, +50.5194, 6.32 }, + { 5149, 205.2596, +22.4958, 5.62 }, { 5150, 205.4033, -7.2969, 5.01 }, { 5151, 205.7337, -55.2319, 6.00 }, { 5152, 205.7275, -49.2094, 6.41 }, + { 5153, 205.0888, +57.2075, 6.29 }, { 5154, 205.1846, +54.6817, 4.66 }, { 5155, 205.7292, -40.5989, 5.98 }, { 5156, 205.5529, +8.3883, 6.16 }, + { 5157, 205.9167, -41.9325, 5.98 }, { 5158, 206.0663, -50.9869, 6.47 }, { 5159, 205.7654, +3.5381, 5.36 }, { 5160, 205.6200, +41.6742, 6.30 }, + { 5161, 205.6808, +34.9889, 5.98 }, { 5162, 205.3746, +64.8225, 5.85 }, { 5163, 205.9762, -4.5011, 6.51 }, { 5164, 205.9383, +22.7003, 6.13 }, + { 5165, 206.1242, -15.8208, 5.60 }, { 5166, 206.1904, -24.4992, 6.21 }, { 5167, 206.4038, -25.8839, 5.81 }, { 5168, 206.4217, -32.9561, 4.23 }, + { 5169, 205.9779, +52.0644, 6.02 }, { 5170, 206.3963, -14.2325, 6.19 }, { 5171, 206.7946, -61.4100, 6.51 }, { 5172, 206.6637, -50.5672, 4.65 }, + { 5173, 206.4846, -11.5733, 5.51 }, { 5174, 206.7350, -35.7481, 5.15 }, { 5175, 206.8650, -49.7506, 5.91 }, { 5176, 206.9100, -49.6789, 5.45 }, + { 5177, 206.3050, +55.8794, 6.50 }, { 5178, 206.8063, -8.2908, 6.05 }, { 5179, 206.5563, +41.0886, 5.87 }, { 5180, 206.5792, +38.5039, 5.94 }, + { 5181, 206.8558, -16.1400, 5.43 }, { 5182, 206.6804, +25.7022, 5.95 }, { 5183, 206.7379, +6.3506, 6.33 }, { 5184, 205.6637, +78.0644, 5.91 }, + { 5185, 206.8154, +17.4567, 4.50 }, { 5186, 206.7492, +38.5428, 5.50 }, { 5187, 206.6488, +54.4328, 5.70 }, { 5188, 208.9113, -81.3339, 5.95 }, + { 5189, 207.2296, -34.2961, 6.53 }, { 5190, 207.3763, -40.3122, 3.41 }, { 5191, 206.8850, +49.3133, 1.86 }, { 5192, 207.3613, -33.5492, 4.19 }, + { 5193, 207.4042, -41.5261, 3.04 }, { 5194, 207.9475, -68.5986, 5.75 }, { 5195, 207.1613, +31.1903, 5.62 }, { 5196, 207.4679, -17.8658, 4.97 }, + { 5197, 207.5271, -28.9186, 6.18 }, { 5198, 207.5808, -38.0989, 6.44 }, { 5199, 207.2383, +39.5428, 7.40 }, { 5200, 207.3692, +15.7978, 4.07 }, + { 5201, 207.4283, +21.2642, 4.91 }, { 5202, 207.6438, -18.1028, 6.53 }, { 5203, 205.5963, +82.7525, 5.98 }, { 5204, 207.4375, +36.6328, 6.38 }, + { 5205, 207.6029, +5.4972, 6.01 }, { 5206, 207.9467, -45.1008, 5.77 }, { 5207, 208.0200, -51.1883, 5.25 }, { 5208, 207.9025, -35.5667, 6.35 }, + { 5209, 207.8350, -23.6092, 6.45 }, { 5210, 207.9567, -31.0056, 4.56 }, { 5211, 207.9588, -31.0053, 6.06 }, { 5212, 208.0038, -30.3806, 6.12 }, + { 5213, 207.4396, +61.4892, 5.96 }, { 5214, 207.7688, +34.7725, 6.65 }, { 5215, 207.7883, +34.6644, 5.87 }, { 5216, 207.6154, +58.5394, 6.46 }, + { 5217, 208.4296, -52.6264, 5.89 }, { 5218, 208.7038, -66.3475, 5.71 }, { 5219, 207.9479, +34.4442, 4.74 }, { 5220, 208.0767, +12.1653, 6.04 }, + { 5221, 208.3021, -30.0722, 4.73 }, { 5222, 208.3867, -34.3358, 5.54 }, { 5223, 208.4871, -46.8719, 6.10 }, { 5224, 208.4675, -34.6856, 6.19 }, + { 5225, 208.3038, +17.9328, 5.70 }, { 5226, 207.8579, +64.7233, 4.65 }, { 5227, 207.7467, +68.3153, 6.40 }, { 5228, 208.5692, -27.4303, 6.04 }, + { 5229, 208.2929, +28.6481, 5.90 }, { 5230, 208.8008, -51.8389, 5.71 }, { 5231, 208.8850, -46.7117, 2.55 }, { 5232, 208.6754, -0.4969, 5.15 }, + { 5233, 208.7425, -7.9411, 6.19 }, { 5234, 209.0825, -53.8681, 6.14 }, { 5235, 208.6712, +18.3978, 2.68 }, { 5236, 209.1375, -53.2956, 6.00 }, + { 5237, 208.9354, -30.7150, 6.51 }, { 5238, 208.4625, +53.7286, 5.70 }, { 5239, 209.0813, -45.4075, 5.83 }, { 5240, 210.1367, -77.4100, 6.09 }, + { 5241, 209.4121, -62.3133, 4.71 }, { 5242, 209.6300, -64.1994, 6.20 }, { 5243, 208.9583, +14.0564, 6.16 }, { 5244, 209.1163, +1.0506, 5.91 }, + { 5245, 209.0437, +32.0325, 6.32 }, { 5246, 209.3654, -22.9772, 6.14 }, { 5247, 209.1425, +27.4919, 5.01 }, { 5248, 209.5679, -41.8992, 3.83 }, + { 5249, 209.6700, -43.1964, 3.87 }, { 5250, 209.6296, -23.0278, 5.15 }, { 5251, 209.8221, -49.6300, 5.91 }, { 5252, 210.0721, -60.5186, 6.49 }, + { 5253, 210.2175, -65.7314, 5.97 }, { 5254, 209.6662, +14.6494, 6.00 }, { 5255, 209.6621, +21.6961, 5.76 }, { 5256, 209.3837, +61.4928, 6.37 }, + { 5257, 210.0004, -24.9897, 5.77 }, { 5258, 209.9554, -2.4503, 6.40 }, { 5259, 210.3292, -39.7778, 6.13 }, { 5260, 210.4308, -44.3964, 4.34 }, + { 5261, 211.3325, -75.2033, 5.50 }, { 5262, 210.3350, +8.8947, 5.99 }, { 5263, 210.2937, +27.3867, 6.23 }, { 5264, 210.4117, +1.5444, 4.26 }, + { 5265, 210.5950, -26.5700, 5.48 }, { 5266, 210.8592, -55.7864, 5.92 }, { 5267, 210.9558, -59.6269, 0.61 }, { 5268, 210.7571, -30.3161, 6.18 }, + { 5269, 210.8646, -40.5767, 6.11 }, { 5270, 210.6325, +9.6864, 6.20 }, { 5271, 210.5508, +45.7536, 6.27 }, { 5272, 210.9713, -21.5783, 6.30 }, + { 5273, 210.8846, +10.7867, 6.30 }, { 5274, 210.9033, +7.5464, 6.26 }, { 5275, 210.9825, +4.9008, 6.24 }, { 5276, 211.0608, -4.6186, 6.39 }, + { 5277, 211.1125, -13.0283, 6.28 }, { 5278, 211.4437, -53.3306, 6.17 }, { 5279, 212.1129, -73.1497, 6.02 }, { 5280, 210.7488, +50.9719, 6.15 }, + { 5281, 211.6046, -58.2844, 6.42 }, { 5282, 210.4608, +68.6786, 6.34 }, { 5283, 211.1563, +2.2975, 6.28 }, { 5284, 211.3083, -15.6642, 6.56 }, + { 5285, 211.5117, -40.8203, 4.36 }, { 5286, 211.5454, -42.9081, 6.20 }, { 5287, 211.5929, -25.3175, 3.27 }, { 5288, 211.6708, -35.6300, 2.06 }, + { 5289, 212.0596, -62.7919, 6.40 }, { 5290, 211.6783, -8.6867, 5.46 }, { 5291, 211.0971, +64.3758, 3.65 }, { 5292, 212.2346, -58.7233, 6.34 }, + { 5293, 212.6288, -69.6944, 6.05 }, { 5294, 212.2163, -42.5289, 6.17 }, { 5295, 212.7579, -68.2803, 6.06 }, { 5296, 212.3958, -50.4953, 6.00 }, + { 5297, 212.4783, -52.5608, 4.75 }, { 5298, 212.2525, -9.6656, 6.47 }, { 5299, 211.9825, +43.8544, 5.27 }, { 5300, 212.0721, +49.4581, 5.25 }, + { 5301, 212.7104, -15.6981, 4.91 }, { 5302, 212.1917, +59.3378, 6.46 }, { 5303, 214.5575, -80.9922, 4.91 }, { 5304, 212.5996, +25.0917, 4.83 }, + { 5305, 211.7350, +74.5936, 6.45 }, { 5306, 214.2287, -76.3361, 6.47 }, { 5307, 212.8800, +1.3622, 6.43 }, { 5308, 213.3183, -52.3342, 5.56 }, + { 5309, 213.1021, -23.6358, 6.34 }, { 5310, 212.8129, +32.2956, 6.11 }, { 5311, 213.4162, -53.3742, 6.11 }, { 5312, 213.1917, -26.7389, 5.08 }, + { 5313, 213.0658, +2.4094, 5.01 }, { 5314, 213.3050, -25.3878, 6.24 }, { 5315, 213.2242, -9.7264, 4.19 }, { 5316, 213.7375, -56.9142, 5.07 }, + { 5317, 213.4200, +0.8456, 5.91 }, { 5318, 213.6775, -40.1625, 5.61 }, { 5319, 213.8383, -52.4903, 6.39 }, { 5320, 214.1608, -65.4122, 5.75 }, + { 5321, 212.2121, +77.5475, 4.82 }, { 5322, 213.5888, -4.0525, 6.36 }, { 5323, 213.5217, +12.9594, 5.54 }, { 5324, 213.7554, -28.7181, 6.08 }, + { 5325, 213.9117, -44.9992, 6.31 }, { 5326, 214.1425, -58.0861, 6.39 }, { 5327, 216.0971, -81.1514, 6.42 }, { 5328, 213.3654, +51.7878, 6.69 }, + { 5329, 213.3708, +51.7903, 4.54 }, { 5330, 213.7117, +10.1006, 5.29 }, { 5331, 213.7208, +3.3361, 6.45 }, { 5332, 213.8504, -17.7992, 5.43 }, + { 5333, 213.6708, +21.8733, 6.39 }, { 5334, 213.0167, +69.4325, 5.24 }, { 5335, 213.5979, +41.5189, 6.24 }, { 5336, 215.5946, -79.8911, 5.06 }, + { 5337, 214.0762, -32.7586, 6.55 }, { 5338, 214.0038, -5.9994, 4.08 }, { 5339, 216.7287, -82.3322, 4.32 }, { 5340, 213.9154, +19.1825, -0.04 }, + { 5341, 214.0896, -5.3781, 6.44 }, { 5342, 214.1254, -2.8036, 6.15 }, { 5343, 214.0175, +18.9119, 5.98 }, { 5344, 214.2658, -17.4147, 6.22 }, + { 5345, 213.8204, +52.5358, 6.58 }, { 5346, 214.1367, +20.1214, 6.25 }, { 5347, 214.1008, +39.7447, 6.38 }, { 5348, 214.5992, -32.7794, 6.54 }, + { 5349, 214.9646, -60.7269, 5.23 }, { 5350, 214.0412, +51.3672, 4.75 }, { 5351, 214.0958, +46.0883, 4.18 }, { 5352, 214.3683, +15.2633, 5.80 }, + { 5353, 214.5025, -6.4575, 6.47 }, { 5354, 214.8508, -45.9422, 3.55 }, { 5355, 214.6596, -17.2839, 5.90 }, { 5356, 214.7533, -24.1844, 5.87 }, + { 5357, 214.8496, -36.9964, 5.94 }, { 5358, 215.0813, -55.6133, 4.33 }, { 5359, 214.7775, -12.6289, 4.52 }, { 5360, 214.3379, +51.3072, 6.20 }, + { 5361, 214.4992, +35.5094, 4.81 }, { 5362, 215.0404, -42.9411, 5.56 }, { 5363, 214.4550, +48.0017, 6.32 }, { 5364, 215.1771, -44.8128, 4.77 }, + { 5365, 214.8179, +13.0042, 5.41 }, { 5366, 214.8854, -1.7344, 5.14 }, { 5367, 215.1392, -36.1147, 4.05 }, { 5368, 214.9204, +0.3842, 6.19 }, + { 5369, 214.7321, +38.7675, 6.86 }, { 5370, 214.9383, +16.3069, 4.86 }, { 5371, 215.6542, -57.5406, 4.92 }, { 5372, 214.7325, +54.8642, 6.53 }, + { 5373, 214.9487, +38.7939, 6.33 }, { 5374, 215.0363, +30.4292, 6.44 }, { 5375, 215.6613, -47.6797, 6.09 }, { 5376, 215.5821, -33.2131, 5.56 }, + { 5377, 215.8346, -49.2278, 6.02 }, { 5378, 215.7592, -38.4878, 4.42 }, { 5379, 216.2763, -67.8047, 5.61 }, { 5380, 215.9517, -52.8233, 6.00 }, + { 5381, 215.7742, -26.2461, 4.77 }, { 5382, 216.4146, -65.8267, 6.36 }, { 5383, 215.8567, -10.2858, 6.21 }, { 5384, 215.8138, +1.2417, 6.27 }, + { 5385, 215.8442, +8.4450, 6.86 }, { 5386, 215.8446, +8.4467, 5.12 }, { 5387, 215.7783, +25.3381, 6.22 }, { 5388, 216.0038, +8.2436, 5.95 }, + { 5389, 217.4033, -75.2708, 6.07 }, { 5390, 216.2025, -23.1936, 5.32 }, { 5391, 216.7796, -64.1783, 5.85 }, { 5392, 216.0471, +5.8200, 5.10 }, + { 5393, 216.1704, -10.3303, 6.49 }, { 5394, 216.0762, +8.0850, 6.19 }, { 5395, 216.5342, -44.7786, 4.56 }, { 5396, 216.5450, -44.6206, 4.35 }, + { 5397, 216.3742, -18.0303, 6.61 }, { 5398, 216.5558, -41.6808, 6.32 }, { 5399, 216.4487, -25.1475, 6.48 }, { 5400, 216.7079, -38.1261, 6.35 }, + { 5401, 216.8008, -45.8656, 5.83 }, { 5402, 216.3717, +38.3931, 6.27 }, { 5403, 217.1813, -58.8022, 6.45 }, { 5404, 216.2992, +51.8508, 4.05 }, + { 5405, 216.6142, +19.2269, 5.39 }, { 5406, 216.8517, -5.8797, 6.17 }, { 5407, 217.0433, -28.5083, 4.97 }, { 5408, 217.8187, -66.2828, 5.83 }, + { 5409, 217.0504, -1.7719, 4.81 }, { 5410, 217.1738, -5.0994, 5.42 }, { 5411, 216.8638, +41.0250, 6.63 }, { 5412, 217.5358, -44.6783, 5.50 }, + { 5413, 217.5871, -48.4808, 5.37 }, { 5414, 217.1312, +28.2892, 7.62 }, { 5415, 217.1387, +28.2908, 7.12 }, { 5416, 217.0683, +36.1969, 6.10 }, + { 5417, 217.7354, -39.1550, 6.39 }, { 5418, 217.4604, +0.8289, 5.94 }, { 5419, 217.7950, -37.1303, 5.97 }, { 5420, 217.1575, +49.8447, 5.59 }, + { 5421, 218.1371, -55.1122, 6.93 }, { 5422, 217.4571, +31.7911, 6.06 }, { 5423, 217.4033, +41.7958, 6.35 }, { 5424, 217.6892, +4.7722, 6.02 }, + { 5425, 218.1538, -49.5431, 4.42 }, { 5426, 218.3850, -53.0017, 5.87 }, { 5427, 218.3746, -51.3200, 5.87 }, { 5428, 218.2900, -29.2858, 6.09 }, + { 5429, 217.9575, +30.3714, 3.58 }, { 5430, 216.8812, +75.6961, 4.25 }, { 5431, 218.5333, -41.9003, 6.60 }, { 5432, 218.8217, -59.9842, 6.40 }, + { 5433, 218.0842, +26.6772, 6.01 }, { 5434, 218.1354, +22.2600, 5.92 }, { 5435, 218.0196, +38.3083, 3.03 }, { 5436, 217.6921, +63.1856, 6.09 }, + { 5437, 217.9283, +60.2256, 6.27 }, { 5438, 218.7113, -19.5608, 6.50 }, { 5439, 218.8812, -40.4828, 5.87 }, { 5440, 218.8767, -41.8422, 2.31 }, + { 5441, 218.3346, +36.9594, 6.43 }, { 5442, 218.1288, +55.3978, 5.76 }, { 5443, 219.4429, -66.0678, 6.04 }, { 5444, 219.0792, -45.7547, 5.55 }, + { 5445, 218.5488, +32.5344, 6.33 }, { 5446, 219.1008, -38.4028, 6.13 }, { 5447, 218.6700, +29.7450, 4.46 }, { 5448, 218.6604, +36.6258, 6.03 }, + { 5449, 219.1842, -39.7883, 5.74 }, { 5450, 219.3338, -45.8661, 5.41 }, { 5451, 218.5663, +57.0653, 6.48 }, { 5452, 218.6650, +49.3683, 5.74 }, + { 5453, 219.4717, -48.5742, 4.05 }, { 5454, 219.0288, +23.2503, 6.38 }, { 5455, 219.2492, -11.6947, 6.20 }, { 5456, 219.5817, -37.2058, 6.02 }, + { 5457, 219.7958, -45.4158, 6.07 }, { 5458, 219.8529, -48.9444, 6.39 }, { 5459, 219.8996, -59.1647, -0.01 }, { 5460, 219.9004, -59.1644, 1.33 }, + { 5461, 220.1367, -55.5592, 6.30 }, { 5462, 219.5583, +18.2983, 5.91 }, { 5463, 220.6267, -63.0247, 3.19 }, { 5464, 219.5521, +43.6419, 5.70 }, + { 5465, 220.4821, -57.3839, 6.22 }, { 5466, 220.2558, -35.8650, 5.67 }, { 5467, 219.5633, +54.0233, 5.85 }, { 5468, 219.7092, +44.4044, 5.39 }, + { 5469, 220.4825, -46.6117, 2.30 }, { 5470, 221.9650, -78.9553, 3.83 }, { 5471, 220.4900, -36.2064, 4.00 }, { 5472, 220.0913, +21.9756, 6.10 }, + { 5473, 220.1767, +13.5342, 5.91 }, { 5474, 220.4629, -29.0667, 6.37 }, { 5475, 220.1817, +16.4183, 4.94 }, { 5476, 220.1829, +16.4178, 5.88 }, + { 5477, 220.2871, +13.7283, 4.83 }, { 5478, 220.2871, +13.7283, 4.43 }, { 5479, 218.4096, +79.6603, 6.26 }, { 5480, 220.4117, +8.1617, 4.86 }, + { 5481, 220.4313, +11.6606, 5.56 }, { 5482, 221.3221, -61.1242, 5.36 }, { 5483, 220.4758, +21.1236, 6.38 }, { 5484, 220.8067, -23.0025, 5.73 }, + { 5485, 220.9142, -34.8264, 4.05 }, { 5486, 221.2312, -57.5222, 6.11 }, { 5487, 220.7650, -4.3417, 3.88 }, { 5488, 221.2954, -54.3981, 6.10 }, + { 5489, 221.2467, -34.8081, 4.92 }, { 5490, 220.8558, +26.5278, 4.81 }, { 5491, 232.0796, -87.8669, 6.48 }, { 5492, 220.5133, +61.2619, 6.25 }, + { 5493, 220.9350, +40.4592, 5.73 }, { 5494, 221.6213, -46.5589, 5.74 }, { 5495, 221.7554, -51.6164, 5.21 }, { 5496, 221.2988, -0.5822, 6.07 }, + { 5497, 221.5004, -24.5569, 4.94 }, { 5498, 221.8013, -51.7944, 6.07 }, { 5499, 221.5283, -22.8469, 5.81 }, { 5500, 222.1850, -65.4061, 5.91 }, + { 5501, 221.3758, +0.7172, 5.69 }, { 5502, 221.3104, +16.9644, 4.60 }, { 5503, 221.4908, -14.5403, 6.33 }, { 5504, 221.5454, -20.8239, 6.40 }, + { 5505, 221.2467, +27.0750, 5.12 }, { 5506, 221.2467, +27.0742, 2.70 }, { 5507, 221.3363, +18.8847, 6.13 }, { 5508, 221.7713, -37.7092, 5.94 }, + { 5509, 221.8837, -42.4425, 6.30 }, { 5510, 221.3071, +32.7883, 6.28 }, { 5511, 221.5621, +1.8928, 3.72 }, { 5512, 221.5250, +15.1319, 5.63 }, + { 5513, 221.8071, -20.6753, 6.06 }, { 5514, 221.8438, -24.3756, 5.63 }, { 5515, 222.2788, -55.3322, 6.23 }, { 5516, 221.9367, -25.9125, 5.24 }, + { 5517, 221.9896, -25.3536, 5.77 }, { 5518, 221.9787, -11.1603, 6.35 }, { 5519, 222.1588, -35.3653, 6.04 }, { 5520, 223.3071, -72.8100, 5.60 }, + { 5521, 222.3279, -23.7483, 5.68 }, { 5522, 222.2254, +0.8478, 6.14 }, { 5523, 222.3296, -13.8511, 5.31 }, { 5524, 222.0971, +24.3667, 6.14 }, + { 5525, 225.4617, -82.7722, 5.65 }, { 5526, 222.5721, -26.0397, 4.41 }, { 5527, 223.1458, -62.1900, 5.87 }, { 5528, 222.9100, -42.4244, 4.32 }, + { 5529, 222.2779, +37.8111, 6.16 }, { 5530, 222.6717, -14.0028, 5.15 }, { 5531, 222.7196, -15.9583, 2.75 }, { 5532, 222.4933, +28.6158, 5.80 }, + { 5533, 222.3279, +46.1161, 5.74 }, { 5534, 222.5658, +23.9119, 5.85 }, { 5535, 222.7542, -1.7008, 4.94 }, { 5536, 222.7504, +0.2572, 6.18 }, + { 5537, 222.3846, +51.3747, 6.51 }, { 5538, 222.4221, +48.7206, 5.69 }, { 5539, 223.6767, -64.0086, 6.09 }, { 5540, 224.4704, -75.3372, 5.34 }, + { 5541, 222.6233, +37.2719, 5.48 }, { 5542, 223.1379, -29.4231, 6.29 }, { 5543, 223.2129, -36.1967, 5.03 }, { 5544, 222.8471, +19.1011, 4.55 }, + { 5545, 226.1946, -82.9617, 5.65 }, { 5546, 223.8942, -59.8858, 5.20 }, { 5547, 225.0492, -76.8397, 5.93 }, { 5548, 223.5838, -23.3578, 5.30 }, + { 5549, 223.6583, -32.6994, 5.82 }, { 5550, 223.3471, +15.7044, 6.40 }, { 5551, 224.1833, -61.2192, 5.11 }, { 5552, 222.8600, +59.2939, 5.46 }, + { 5553, 223.3488, +19.1528, 6.01 }, { 5554, 223.5954, -10.1017, 5.80 }, { 5555, 224.9833, -74.9675, 6.20 }, { 5556, 224.0721, -51.1903, 5.38 }, + { 5557, 227.7846, -83.2125, 5.91 }, { 5558, 223.9363, -32.1442, 5.32 }, { 5559, 224.1333, -46.1208, 5.64 }, { 5560, 224.2558, -50.5531, 6.64 }, + { 5561, 224.1492, -38.5839, 6.36 }, { 5562, 224.1288, -31.3633, 6.06 }, { 5563, 222.6763, +74.1556, 2.08 }, { 5564, 224.1921, -10.5903, 5.46 }, + { 5565, 224.3067, -28.8422, 6.29 }, { 5566, 224.5367, -47.1369, 6.35 }, { 5567, 224.0550, +14.4464, 5.77 }, { 5568, 224.3667, -20.5844, 5.74 }, + { 5569, 223.9946, +32.3003, 6.12 }, { 5570, 224.2958, -3.6536, 4.49 }, { 5571, 224.6329, -42.8661, 2.68 }, { 5572, 224.6533, -38.0933, 6.15 }, + { 5573, 224.3887, +0.1675, 5.53 }, { 5574, 224.2650, +21.5553, 6.49 }, { 5575, 224.2988, +16.3883, 5.71 }, { 5576, 224.7904, -41.8958, 3.13 }, + { 5577, 224.6633, -26.3428, 5.65 }, { 5578, 224.5558, -10.8450, 6.60 }, { 5579, 224.8079, -36.1186, 6.47 }, { 5580, 224.8629, -42.8400, 6.10 }, + { 5581, 224.0958, +49.6286, 5.63 }, { 5582, 224.7233, -10.8558, 5.87 }, { 5583, 224.7200, -3.0108, 6.09 }, { 5584, 224.8463, +4.5678, 5.93 }, + { 5585, 225.3042, -37.9417, 5.89 }, { 5586, 225.2433, -7.4811, 4.92 }, { 5587, 225.4921, -33.6411, 6.22 }, { 5588, 224.9038, +39.2653, 5.64 }, + { 5589, 224.3958, +65.9325, 4.60 }, { 5590, 225.3325, -1.2450, 5.52 }, { 5591, 225.5267, -27.9394, 5.85 }, { 5592, 225.2183, +22.0456, 6.38 }, + { 5593, 226.2008, -63.9683, 5.17 }, { 5594, 225.4538, +0.1406, 5.71 }, { 5595, 225.7471, -31.3567, 5.44 }, { 5596, 222.5850, +82.5119, 5.64 }, + { 5597, 225.1613, +47.2778, 6.37 }, { 5598, 226.7863, -70.0947, 6.52 }, { 5599, 225.6871, -2.9686, 6.61 }, { 5600, 225.5271, +25.0081, 4.81 }, + { 5601, 225.7250, +2.0914, 4.40 }, { 5602, 225.4867, +40.3906, 3.50 }, { 5603, 226.0175, -24.7181, 3.29 }, { 5604, 226.1788, -39.1386, 6.41 }, + { 5605, 226.2800, -46.9489, 4.72 }, { 5606, 226.2800, -46.9489, 4.82 }, { 5607, 226.3296, -40.9328, 5.15 }, { 5608, 225.3629, +60.2044, 5.93 }, + { 5609, 225.7754, +35.2058, 5.51 }, { 5610, 226.0267, +5.4925, 6.50 }, { 5611, 226.9867, -64.7244, 6.17 }, { 5612, 225.7775, +44.6444, 6.65 }, + { 5613, 225.9021, +34.5661, 6.59 }, { 5614, 226.4487, -24.2103, 6.67 }, { 5615, 226.5579, -35.7358, 6.27 }, { 5616, 226.1113, +26.9475, 4.54 }, + { 5617, 226.8579, -48.9117, 5.77 }, { 5618, 225.9475, +47.6544, 4.76 }, { 5619, 226.6387, -29.0811, 5.96 }, { 5620, 226.6129, -21.9681, 6.17 }, + { 5621, 227.3746, -66.9158, 5.76 }, { 5622, 226.6567, -15.7431, 5.20 }, { 5623, 227.3562, -62.3572, 6.28 }, { 5624, 227.0504, -39.4161, 5.79 }, + { 5625, 227.1629, -41.1322, 5.85 }, { 5626, 227.2108, -44.7203, 4.05 }, { 5627, 226.3575, +48.1511, 5.57 }, { 5628, 228.1408, -71.2297, 6.01 }, + { 5629, 225.9908, +65.9197, 6.13 }, { 5630, 226.6463, +36.4556, 6.35 }, { 5631, 226.9179, +5.4981, 6.16 }, { 5632, 227.6858, -60.5775, 6.30 }, + { 5633, 226.8350, +18.4417, 6.02 }, { 5634, 226.8254, +24.8692, 4.93 }, { 5635, 226.5696, +54.5564, 5.25 }, { 5636, 227.5313, -37.2075, 5.98 }, + { 5637, 227.8167, -54.6539, 5.54 }, { 5638, 227.0992, +26.3011, 5.67 }, { 5639, 227.2225, +13.2350, 6.10 }, { 5640, 227.1479, +25.1086, 5.81 }, + { 5641, 227.5775, -25.6672, 5.76 }, { 5642, 227.8954, -44.7225, 6.44 }, { 5643, 227.8829, -44.7206, 7.39 }, { 5644, 228.5796, -69.9206, 5.81 }, + { 5645, 228.2542, -60.2561, 6.32 }, { 5646, 227.9837, -47.2622, 3.87 }, { 5647, 227.9900, -47.2564, 5.69 }, { 5648, 227.0813, +50.0550, 6.39 }, + { 5649, 228.0712, -51.9008, 3.41 }, { 5650, 228.1304, -47.7814, 6.33 }, { 5651, 228.2063, -43.4994, 4.82 }, { 5652, 228.0554, -18.2083, 4.54 }, + { 5653, 228.2808, -35.9086, 6.10 }, { 5654, 228.0179, +18.9758, 5.89 }, { 5655, 228.3229, -23.9917, 6.47 }, { 5656, 228.3300, -18.3525, 6.08 }, + { 5657, 228.3696, -24.6908, 6.45 }, { 5658, 228.4721, -25.8064, 5.84 }, { 5659, 228.1813, +19.2858, 6.68 }, { 5660, 228.6554, -30.4808, 4.91 }, + { 5661, 229.1517, -59.0961, 5.73 }, { 5662, 228.6404, -16.2314, 6.17 }, { 5663, 228.9742, -47.9258, 5.95 }, { 5664, 229.2363, -59.0425, 5.09 }, + { 5665, 228.3829, +22.9833, 6.30 }, { 5666, 229.4121, -62.3894, 4.86 }, { 5667, 229.0167, -40.5089, 5.16 }, { 5668, 229.0437, -42.5153, 6.04 }, + { 5669, 228.7113, -4.4972, 6.28 }, { 5670, 229.3783, -57.1989, 4.07 }, { 5671, 229.7275, -67.3206, 2.89 }, { 5672, 227.6838, +67.7814, 6.17 }, + { 5673, 228.3983, +38.2647, 6.20 }, { 5674, 228.5254, +31.7881, 5.99 }, { 5675, 228.7975, +4.9394, 5.33 }, { 5676, 228.6217, +29.1642, 5.26 }, + { 5677, 228.5429, +42.1714, 6.13 }, { 5678, 229.0958, -21.6006, 5.50 }, { 5679, 228.9546, +0.3722, 5.63 }, { 5680, 229.7038, -59.5036, 5.46 }, + { 5681, 228.8758, +33.3147, 3.47 }, { 5682, 229.5392, -40.9392, 6.28 }, { 5683, 229.6333, -46.1250, 4.27 }, { 5684, 230.1696, -66.5186, 6.28 }, + { 5685, 229.2517, -8.6169, 2.61 }, { 5686, 229.4579, -29.8511, 4.34 }, { 5687, 229.7350, -39.2117, 5.59 }, { 5688, 229.6721, -30.7906, 6.18 }, + { 5689, 229.8817, -36.9033, 6.20 }, { 5690, 229.6092, +0.4614, 5.89 }, { 5691, 228.6596, +67.3467, 5.13 }, { 5692, 229.6021, +20.5728, 5.70 }, + { 5693, 228.7163, +68.9453, 6.51 }, { 5694, 229.8283, +1.7653, 5.06 }, { 5695, 230.3429, -39.3525, 3.22 }, { 5696, 230.3971, -39.2503, 6.20 }, + { 5697, 230.3754, -37.7808, 6.48 }, { 5698, 230.5346, -46.0722, 5.00 }, { 5699, 230.4508, -47.6822, 5.65 }, { 5700, 230.7933, -59.3431, 5.67 }, + { 5701, 230.2238, -17.8414, 6.17 }, { 5702, 229.8758, +32.5153, 6.32 }, { 5703, 230.2558, -14.4517, 6.30 }, { 5704, 230.8446, -58.6792, 4.51 }, + { 5705, 230.4517, -35.7386, 3.56 }, { 5706, 230.1962, -1.5867, 6.35 }, { 5707, 230.2817, -4.1753, 5.54 }, { 5708, 230.6704, -43.3106, 3.37 }, + { 5709, 230.0354, +29.6161, 5.51 }, { 5710, 230.2583, +0.7153, 5.35 }, { 5711, 230.2788, +24.9578, 6.39 }, { 5712, 230.7892, -35.1414, 4.54 }, + { 5713, 231.5613, -67.6908, 5.89 }, { 5714, 229.2746, +71.8239, 5.02 }, { 5715, 230.0217, +51.9586, 5.66 }, { 5716, 230.1733, +44.4342, 6.19 }, + { 5717, 230.5967, +12.5675, 6.28 }, { 5718, 230.4525, +32.9339, 5.37 }, { 5719, 231.1871, -38.2897, 5.37 }, { 5720, 230.9675, -11.6306, 5.72 }, + { 5721, 230.9321, -0.9775, 6.12 }, { 5722, 231.2775, -37.8306, 7.03 }, { 5723, 231.0496, -9.6778, 4.94 }, { 5724, 231.3342, -37.2664, 4.60 }, + { 5725, 231.8879, -63.4686, 5.71 }, { 5726, 230.6558, +39.5814, 5.50 }, { 5727, 230.8013, +30.2878, 5.58 }, { 5728, 230.8013, +30.2878, 6.08 }, + { 5729, 235.8200, -83.5347, 5.57 }, { 5730, 232.8783, -72.6106, 5.49 }, { 5731, 230.6554, +62.0472, 5.98 }, { 5732, 231.0213, +45.2711, 6.01 }, + { 5733, 231.1225, +37.3772, 4.31 }, { 5734, 231.1288, +37.3478, 6.50 }, { 5735, 230.1821, +71.8339, 3.05 }, { 5736, 231.8258, -35.2322, 5.45 }, + { 5737, 230.6600, +63.3414, 5.79 }, { 5738, 232.1133, -50.4025, 6.10 }, { 5739, 231.4475, +15.4281, 5.17 }, { 5740, 231.4721, +19.4808, 6.27 }, + { 5741, 231.5725, +34.3358, 5.46 }, { 5742, 232.3512, -45.2672, 5.24 }, { 5743, 232.0642, -15.2836, 5.64 }, { 5744, 231.2325, +58.9661, 3.29 }, + { 5745, 231.9121, +25.1017, 6.02 }, { 5746, 232.1592, +1.8422, 5.17 }, { 5747, 231.9571, +29.1058, 3.68 }, { 5748, 231.6354, +54.0200, 6.45 }, + { 5749, 232.6513, -19.2717, 6.22 }, { 5750, 232.6683, -15.3906, 5.82 }, { 5751, 233.0183, -37.3769, 6.25 }, { 5752, 232.1854, +47.2014, 6.15 }, + { 5753, 232.9596, -31.1189, 6.46 }, { 5754, 231.9200, +62.2756, 6.50 }, { 5755, 231.9642, +60.6703, 5.90 }, { 5756, 232.9308, -19.8353, 6.22 }, + { 5757, 234.8262, -76.0819, 6.18 }, { 5758, 232.7308, +8.5792, 6.57 }, { 5759, 232.2367, +55.1950, 6.43 }, { 5760, 232.5946, +31.2861, 6.46 }, + { 5761, 232.6163, +36.8042, 6.37 }, { 5762, 233.1529, -18.3294, 5.52 }, { 5763, 232.7325, +40.8331, 5.02 }, { 5764, 233.2300, -15.1472, 5.50 }, + { 5765, 233.2879, -23.5106, 7.00 }, { 5766, 234.0725, -64.3867, 6.51 }, { 5767, 233.5067, -39.9339, 5.82 }, { 5768, 232.3383, +62.0997, 6.38 }, + { 5769, 232.8433, +36.6164, 6.38 }, { 5770, 233.0404, +16.0561, 6.22 }, { 5771, 234.1800, -65.6831, 4.11 }, { 5772, 233.2413, -0.8136, 5.51 }, + { 5773, 233.5871, -38.6506, 6.36 }, { 5774, 232.9458, +40.8994, 5.02 }, { 5775, 233.6554, -27.9531, 5.15 }, { 5776, 233.7854, -40.8331, 2.78 }, + { 5777, 233.5446, -9.9356, 4.62 }, { 5778, 233.2325, +31.3592, 4.14 }, { 5779, 233.5867, -4.3050, 6.51 }, { 5780, 233.6108, -8.8167, 5.17 }, + { 5781, 233.9717, -43.0414, 4.54 }, { 5782, 235.0883, -72.5533, 5.65 }, { 5783, 233.4700, +17.1378, 6.45 }, { 5784, 234.0504, -43.6031, 5.43 }, + { 5785, 232.7321, +64.2086, 5.79 }, { 5786, 235.4775, -75.9181, 5.95 }, { 5787, 233.8817, -13.2106, 3.91 }, { 5788, 233.7004, +10.5375, 3.80 }, + { 5789, 233.7004, +10.5392, 3.80 }, { 5790, 234.0475, -32.9072, 6.24 }, { 5791, 233.7692, +1.6689, 6.56 }, { 5792, 235.0479, -69.7722, 6.44 }, + { 5793, 233.6721, +26.7147, 2.23 }, { 5794, 234.2562, -27.8650, 3.58 }, { 5795, 233.8883, +17.6556, 6.12 }, { 5796, 233.9725, +11.2656, 6.07 }, + { 5797, 234.5133, -41.4325, 4.33 }, { 5798, 234.7063, -51.6272, 5.44 }, { 5799, 234.1404, +0.5617, 6.51 }, { 5800, 233.8125, +39.0100, 5.11 }, + { 5801, 234.3688, -25.7200, 6.19 }, { 5802, 234.1233, +10.0100, 5.26 }, { 5803, 234.9854, -58.0917, 5.95 }, { 5804, 234.1221, +16.1189, 5.93 }, + { 5805, 234.6362, -38.8392, 6.57 }, { 5806, 234.4504, -22.8583, 5.78 }, { 5807, 234.6763, -38.8719, 6.04 }, { 5808, 233.9554, +38.3739, 6.42 }, + { 5809, 234.5654, -27.7933, 6.32 }, { 5810, 234.5679, -20.9839, 5.84 }, { 5811, 233.8179, +53.9219, 5.97 }, { 5812, 234.6642, -28.2222, 3.66 }, + { 5813, 234.2225, +29.9911, 6.52 }, { 5814, 234.7271, -18.6981, 5.38 }, { 5815, 234.6667, -7.2056, 6.50 }, { 5816, 234.6671, -7.2089, 6.48 }, + { 5817, 234.0171, +52.0697, 6.74 }, { 5818, 233.9879, +54.6306, 5.74 }, { 5819, 234.8388, -22.8497, 6.34 }, { 5820, 234.9417, -33.5881, 4.67 }, + { 5821, 235.2429, -46.2644, 6.23 }, { 5822, 235.0642, -30.7864, 6.34 }, { 5823, 234.4567, +40.3533, 5.24 }, { 5824, 235.0704, -22.1819, 4.96 }, + { 5825, 235.2971, -43.3389, 4.64 }, { 5826, 232.8537, +77.3494, 4.96 }, { 5827, 234.7038, +34.6750, 6.11 }, { 5828, 234.3833, +54.5089, 5.87 }, + { 5829, 232.2958, +80.4486, 6.58 }, { 5830, 234.5675, +46.7978, 5.75 }, { 5831, 235.0433, +12.0531, 6.25 }, { 5832, 235.6550, -48.5106, 6.04 }, + { 5833, 234.8425, +36.6367, 6.00 }, { 5834, 234.8446, +36.6358, 5.07 }, { 5835, 234.6429, +50.4233, 5.84 }, { 5836, 235.9796, -59.7128, 6.48 }, + { 5837, 235.6596, -36.5750, 5.24 }, { 5838, 235.4867, -18.3211, 4.74 }, { 5839, 235.6708, -33.2894, 4.75 }, { 5840, 235.2467, +16.0247, 6.01 }, + { 5841, 234.7896, +57.9244, 6.45 }, { 5842, 235.3879, +19.6703, 4.52 }, { 5843, 235.4475, +12.8475, 5.33 }, { 5844, 234.4129, +69.2833, 5.62 }, + { 5845, 235.4779, +18.4639, 5.81 }, { 5846, 236.0942, -40.1806, 5.94 }, { 5847, 235.8537, -14.9567, 6.31 }, { 5848, 236.0183, -14.3272, 5.41 }, + { 5849, 235.6858, +26.2956, 3.84 }, { 5850, 235.7942, +13.6678, 6.48 }, { 5851, 236.9733, -64.5575, 6.18 }, { 5852, 236.9738, -64.5575, 6.39 }, + { 5853, 236.0075, +2.5150, 5.88 }, { 5854, 236.0671, +6.4256, 2.65 }, { 5855, 235.9971, +32.5158, 5.56 }, { 5856, 236.5533, -27.9383, 6.51 }, + { 5857, 235.7113, +52.3608, 5.51 }, { 5858, 236.1754, +17.2642, 6.14 }, { 5859, 236.3479, +5.4469, 5.58 }, { 5860, 236.6842, -33.3175, 5.61 }, + { 5861, 236.4154, +0.8914, 6.33 }, { 5862, 236.8558, -39.8058, 6.42 }, { 5863, 236.5233, -0.1956, 5.40 }, { 5864, 236.8708, -36.0836, 6.01 }, + { 5865, 237.2096, -51.5619, 6.07 }, { 5866, 236.6892, -5.8797, 6.24 }, { 5867, 236.5471, +15.4219, 3.67 }, { 5868, 236.6108, +7.3531, 4.43 }, + { 5869, 237.5288, -52.7906, 5.77 }, { 5870, 236.8221, +14.1153, 5.71 }, { 5871, 237.4896, -47.0881, 5.84 }, { 5872, 237.5679, -44.5983, 6.12 }, + { 5873, 237.7783, -54.9442, 5.73 }, { 5874, 237.0554, +13.7886, 6.00 }, { 5875, 237.2367, -2.1814, 5.53 }, { 5876, 238.2363, -64.8475, 6.54 }, + { 5877, 237.0083, +31.7358, 6.44 }, { 5878, 236.6450, +55.4747, 5.92 }, { 5879, 237.1850, +18.1417, 4.09 }, { 5880, 237.1433, +28.1567, 5.85 }, + { 5881, 237.4050, -2.5697, 3.53 }, { 5882, 237.8812, -46.9394, 6.01 }, { 5883, 237.7396, -32.3728, 3.95 }, { 5884, 238.3450, -61.3931, 6.19 }, + { 5885, 237.7446, -24.2486, 4.64 }, { 5886, 236.6667, +62.5994, 5.19 }, { 5887, 236.9083, +55.3767, 5.86 }, { 5888, 237.5729, +2.1964, 5.23 }, + { 5889, 237.3988, +26.0683, 4.63 }, { 5890, 238.2146, -49.3847, 6.60 }, { 5891, 238.8733, -67.3969, 5.09 }, { 5892, 237.7042, +4.4778, 3.71 }, + { 5893, 238.0533, -28.1133, 6.40 }, { 5894, 237.6738, +15.1336, 5.20 }, { 5895, 237.8150, -2.9094, 5.11 }, { 5896, 237.9100, -13.8664, 6.19 }, + { 5897, 238.7854, -62.5694, 2.85 }, { 5898, 238.7192, -59.2567, 6.15 }, { 5899, 237.8163, +20.9778, 4.76 }, { 5900, 238.8846, -59.8222, 5.77 }, + { 5901, 237.8079, +35.6575, 4.82 }, { 5902, 238.3338, -19.8328, 5.03 }, { 5903, 236.0146, +77.7944, 4.32 }, { 5904, 238.4029, -24.6728, 4.59 }, + { 5905, 239.0250, -59.5172, 5.76 }, { 5906, 238.4742, -23.4669, 5.39 }, { 5907, 238.4825, -22.0219, 5.42 }, { 5908, 238.4563, -15.2706, 4.15 }, + { 5909, 238.2342, +17.4036, 6.36 }, { 5910, 238.6250, -26.6614, 6.14 }, { 5911, 238.3004, +13.1967, 6.10 }, { 5912, 238.6646, -24.7564, 5.87 }, + { 5913, 238.3954, +16.0750, 6.09 }, { 5914, 238.1687, +42.4517, 4.62 }, { 5915, 238.7513, -18.6169, 5.94 }, { 5916, 238.8767, -30.9164, 6.21 }, + { 5917, 238.8754, -25.7342, 5.62 }, { 5918, 239.0271, -38.1358, 6.03 }, { 5919, 238.6679, +8.5803, 6.29 }, { 5920, 239.7421, -64.9622, 5.75 }, + { 5921, 239.2658, -47.8378, 6.31 }, { 5922, 238.0692, +55.8267, 5.81 }, { 5923, 239.0579, -30.2142, 6.29 }, { 5924, 238.6442, +20.3108, 5.44 }, + { 5925, 239.2229, -32.0336, 5.12 }, { 5926, 239.2258, -32.0358, 5.62 }, { 5927, 239.0600, -13.6006, 6.37 }, { 5928, 239.2213, -28.7858, 3.88 }, + { 5929, 239.3388, -35.8150, 5.80 }, { 5930, 239.1392, -13.1708, 6.13 }, { 5931, 238.9158, +18.6206, 6.26 }, { 5932, 238.6579, +43.1386, 5.37 }, + { 5933, 239.1133, +15.6617, 3.85 }, { 5934, 239.4183, -19.0169, 5.85 }, { 5935, 239.6279, -36.4969, 6.31 }, { 5936, 238.9483, +37.9469, 5.45 }, + { 5937, 239.9750, -53.9789, 6.10 }, { 5938, 238.8775, +42.5661, 5.75 }, { 5939, 240.2946, -62.2233, 6.41 }, { 5940, 239.3108, +14.4144, 5.54 }, + { 5941, 239.5475, -13.7206, 4.88 }, { 5942, 239.6450, -23.1686, 5.43 }, { 5943, 239.8763, -40.2556, 4.99 }, { 5944, 239.7129, -25.8858, 2.89 }, + { 5945, 239.9917, -39.3472, 6.49 }, { 5946, 240.2767, -53.4222, 6.13 }, { 5947, 239.3971, +26.8778, 4.15 }, { 5948, 240.0304, -37.6031, 3.41 }, + { 5949, 238.9571, +58.9117, 6.31 }, { 5950, 239.3746, +39.6953, 6.31 }, { 5951, 240.7183, -61.4583, 6.25 }, { 5952, 240.2238, -39.5647, 6.21 }, + { 5953, 240.0833, -21.3783, 2.32 }, { 5954, 240.0817, -15.4667, 5.47 }, { 5955, 241.4825, -71.5992, 5.70 }, { 5956, 240.3313, -30.1106, 6.33 }, + { 5957, 239.7404, +36.6439, 5.62 }, { 5958, 239.8758, +25.9203, 2.00 }, { 5959, 240.1983, -7.5886, 5.55 }, { 5960, 239.4475, +54.7497, 4.95 }, + { 5961, 240.8829, -56.2247, 4.63 }, { 5962, 240.8038, -48.7703, 4.65 }, { 5963, 240.2129, +4.4275, 5.83 }, { 5964, 239.7683, +49.8811, 6.05 }, + { 5965, 240.6642, -28.8642, 6.03 }, { 5966, 240.3096, +17.8183, 5.12 }, { 5967, 240.8508, -37.3975, 4.89 }, { 5968, 240.2612, +33.3036, 5.41 }, + { 5969, 240.8358, -24.1347, 5.00 }, { 5970, 240.8929, -31.9994, 6.01 }, { 5971, 240.3608, +29.8511, 4.99 }, { 5972, 240.5737, +22.8044, 4.83 }, + { 5973, 240.9779, -23.2736, 6.21 }, { 5974, 241.0742, -32.7856, 6.10 }, { 5975, 241.1529, -36.1369, 5.90 }, { 5976, 240.9404, +4.9867, 6.08 }, + { 5977, 241.0921, -10.6269, 5.07 }, { 5978, 241.0921, -10.6269, 4.77 }, { 5979, 241.8500, -55.8086, 6.16 }, { 5980, 241.6225, -44.8267, 4.72 }, + { 5981, 240.5229, +52.9158, 5.93 }, { 5982, 240.6996, +46.0367, 4.76 }, { 5983, 240.8308, +36.6317, 5.83 }, { 5984, 241.3592, -18.1944, 2.62 }, + { 5985, 241.3604, -18.1981, 4.92 }, { 5986, 240.4721, +58.5653, 4.01 }, { 5987, 241.6479, -35.1978, 4.23 }, { 5988, 241.5263, -22.3936, 5.92 }, + { 5989, 241.4354, -5.7083, 6.53 }, { 5990, 241.4992, -5.8606, 6.41 }, { 5991, 241.8183, -35.2444, 5.73 }, { 5992, 241.4075, +8.0961, 6.29 }, + { 5993, 241.7017, -19.3308, 3.96 }, { 5994, 242.3275, -56.0656, 5.57 }, { 5995, 240.7887, +59.4108, 6.19 }, { 5996, 241.7642, -13.9292, 6.32 }, + { 5997, 241.8512, -19.1314, 4.32 }, { 5998, 241.9663, -23.5381, 6.33 }, { 5999, 242.1425, -38.8947, 7.05 }, { 6000, 242.1433, -38.9069, 6.65 }, + { 6001, 242.0317, -25.6733, 5.38 }, { 6002, 241.9017, -11.2544, 5.78 }, { 6003, 242.1821, -22.3144, 5.88 }, { 6004, 241.9063, +9.8917, 5.63 }, + { 6005, 241.8425, +21.8225, 6.14 }, { 6006, 242.3821, -31.3503, 6.19 }, { 6007, 242.4692, -32.4542, 5.54 }, { 6008, 242.0188, +17.0469, 5.00 }, + { 6009, 242.0204, +17.0544, 6.25 }, { 6010, 242.1167, +8.5342, 5.73 }, { 6011, 242.2454, +3.4544, 5.91 }, { 6012, 242.4800, -17.6592, 6.47 }, + { 6013, 242.1942, +17.2058, 6.14 }, { 6014, 242.2967, +6.3789, 5.97 }, { 6015, 242.8237, -40.8803, 5.86 }, { 6016, 242.4604, -2.5331, 5.37 }, + { 6017, 242.7583, -28.5836, 5.13 }, { 6018, 242.2429, +36.4908, 4.76 }, { 6019, 243.3442, -54.4592, 5.81 }, { 6020, 245.0867, -77.3042, 4.68 }, + { 6021, 245.1117, -77.3328, 5.27 }, { 6022, 243.3200, -52.3283, 5.83 }, { 6023, 242.1925, +44.9350, 4.26 }, { 6024, 243.3696, -53.3694, 4.94 }, + { 6025, 241.5821, +67.8103, 5.44 }, { 6026, 242.9942, -18.5503, 6.30 }, { 6027, 242.9988, -18.5394, 4.01 }, { 6028, 243.0758, -26.0736, 4.59 }, + { 6029, 243.0663, -27.5825, 5.67 }, { 6030, 243.8596, -62.3144, 3.85 }, { 6031, 243.0000, -9.9358, 4.94 }, { 6032, 242.8738, +9.7125, 6.53 }, + { 6033, 243.0304, -7.4525, 5.43 }, { 6034, 240.8804, +76.7936, 5.56 }, { 6035, 242.8696, +16.6656, 6.08 }, { 6036, 242.2621, +57.9378, 6.33 }, + { 6037, 244.2729, -66.0586, 5.75 }, { 6038, 242.3583, +55.8289, 6.49 }, { 6039, 242.9083, +23.4947, 5.70 }, { 6040, 243.9571, -56.0878, 5.63 }, + { 6041, 243.2354, -3.7792, 6.25 }, { 6042, 243.4404, -23.5781, 6.41 }, { 6043, 242.9154, +33.3425, 6.29 }, { 6044, 243.5929, -32.9886, 5.92 }, + { 6045, 243.8138, -46.6278, 5.14 }, { 6046, 242.9500, +36.4250, 5.63 }, { 6047, 243.3142, +5.0211, 5.48 }, { 6048, 243.4621, -10.1625, 5.22 }, + { 6049, 243.8500, -41.1003, 6.14 }, { 6050, 242.9483, +42.3744, 5.87 }, { 6051, 243.6200, -20.8925, 6.41 }, { 6052, 243.1888, +26.6708, 6.50 }, + { 6053, 243.6629, -17.4647, 6.32 }, { 6054, 243.7233, -24.5231, 6.05 }, { 6055, 244.1796, -52.1889, 5.44 }, { 6056, 243.5863, -2.3056, 2.74 }, + { 6057, 243.5563, +5.9019, 6.31 }, { 6058, 244.2538, -49.9317, 4.99 }, { 6059, 244.3371, -52.9133, 6.33 }, { 6060, 243.9054, -7.6306, 5.50 }, + { 6061, 243.9646, -13.1508, 6.09 }, { 6062, 244.7163, -56.1003, 6.49 }, { 6063, 243.6700, +33.8586, 5.64 }, { 6064, 243.6700, +33.8583, 6.66 }, + { 6065, 243.8696, +18.8083, 5.69 }, { 6066, 244.2450, -20.6961, 6.61 }, { 6067, 244.2304, -2.0467, 6.18 }, { 6068, 243.9475, +27.4222, 6.14 }, + { 6069, 243.1046, +67.1442, 6.21 }, { 6070, 244.5746, -27.3861, 4.78 }, { 6071, 244.8237, -41.3261, 5.45 }, { 6072, 244.9600, -49.8444, 4.02 }, + { 6073, 245.1050, -54.8600, 5.77 }, { 6074, 244.1867, +29.1503, 5.78 }, { 6075, 244.5804, -3.3075, 3.24 }, { 6076, 244.7821, -19.7822, 6.29 }, + { 6077, 244.8862, -29.0933, 5.49 }, { 6078, 244.7517, -13.1275, 5.94 }, { 6079, 242.7063, +75.8775, 5.48 }, { 6080, 245.1358, -38.5692, 6.12 }, + { 6081, 245.1592, -23.8306, 4.55 }, { 6082, 243.1342, +75.2106, 6.39 }, { 6083, 245.6167, -48.4278, 5.33 }, { 6084, 245.2971, -24.4072, 2.89 }, + { 6085, 245.6204, -42.0878, 5.88 }, { 6086, 244.3138, +59.7550, 5.40 }, { 6087, 245.0179, +21.1325, 6.05 }, { 6088, 243.6396, +73.3950, 5.98 }, + { 6089, 246.3417, -62.8753, 6.15 }, { 6090, 244.7967, +49.0381, 5.91 }, { 6091, 244.9796, +39.7086, 5.46 }, { 6092, 244.9350, +46.3133, 3.89 }, + { 6093, 245.5183, +1.0292, 4.82 }, { 6094, 246.0054, -38.8069, 5.40 }, { 6095, 245.4800, +19.1531, 3.75 }, { 6096, 245.6621, -1.9203, 6.23 }, + { 6097, 245.9863, -32.8006, 6.47 }, { 6098, 247.1171, -69.9156, 4.91 }, { 6099, 246.2258, -44.6508, 6.33 }, { 6100, 246.1321, -36.4342, 5.42 }, + { 6101, 244.5392, +68.5544, 6.41 }, { 6102, 248.3625, -77.1028, 3.89 }, { 6103, 245.5242, +30.8919, 4.85 }, { 6104, 246.0258, -19.9625, 4.50 }, + { 6105, 246.1650, -28.2967, 6.63 }, { 6106, 246.1654, -28.2953, 5.84 }, { 6107, 245.5892, +33.7992, 5.20 }, { 6108, 245.6217, +33.7036, 5.39 }, + { 6109, 246.9888, -63.9419, 5.27 }, { 6110, 245.7354, +32.3331, 6.40 }, { 6111, 246.0450, +6.9481, 5.85 }, { 6112, 246.3967, -22.5528, 5.02 }, + { 6113, 246.3963, -22.5539, 5.92 }, { 6114, 247.0633, -57.4003, 5.69 }, { 6115, 246.7962, -46.4450, 4.47 }, { 6116, 244.3763, +75.7553, 4.95 }, + { 6117, 246.3542, +14.0333, 4.57 }, { 6118, 246.7558, -17.5436, 4.42 }, { 6119, 246.4487, +18.8925, 6.70 }, { 6120, 247.4375, -56.2442, 6.06 }, + { 6121, 246.5479, +11.4075, 6.11 }, { 6122, 247.0613, -36.8206, 5.79 }, { 6123, 246.3508, +37.3939, 5.54 }, { 6124, 246.7088, +2.3475, 6.07 }, + { 6125, 247.7058, -60.3664, 5.20 }, { 6126, 245.4529, +69.1094, 5.25 }, { 6127, 246.1054, +55.2050, 5.74 }, { 6128, 246.9313, -6.4019, 5.23 }, + { 6129, 246.9504, -7.6283, 4.63 }, { 6130, 245.9458, +61.6967, 5.67 }, { 6131, 247.4263, -45.7567, 5.35 }, { 6132, 245.9979, +61.5142, 2.74 }, + { 6133, 258.9971, -86.4336, 6.57 }, { 6134, 247.3517, -25.5681, 0.96 }, { 6135, 248.5804, -69.0119, 5.50 }, { 6136, 247.1417, +0.6650, 5.39 }, + { 6137, 247.2038, -7.8711, 6.48 }, { 6138, 251.4733, -82.7611, 6.57 }, { 6139, 255.2438, -85.6356, 6.04 }, { 6140, 247.4454, -13.4492, 5.68 }, + { 6141, 247.5517, -24.8850, 4.79 }, { 6142, 247.9238, -40.1831, 5.33 }, { 6143, 247.8454, -33.2956, 4.23 }, { 6144, 247.6246, -6.4850, 6.50 }, + { 6145, 247.8450, -25.4622, 6.10 }, { 6146, 247.1604, +41.8817, 5.04 }, { 6147, 247.7846, -15.3872, 4.28 }, { 6148, 247.5550, +21.4897, 2.77 }, + { 6149, 247.7283, +1.9839, 3.82 }, { 6150, 247.1808, +51.4078, 6.29 }, { 6151, 248.9367, -64.5047, 5.52 }, { 6152, 247.6400, +20.4792, 5.25 }, + { 6153, 248.0342, -20.5336, 4.45 }, { 6154, 247.8058, +22.1953, 5.76 }, { 6155, 248.5208, -43.9547, 4.94 }, { 6156, 247.5250, +48.9608, 6.45 }, + { 6157, 247.7617, +35.2250, 6.25 }, { 6158, 248.1488, +5.5211, 5.63 }, { 6159, 248.1513, +11.4881, 4.84 }, { 6160, 248.7829, -44.7553, 6.46 }, + { 6161, 246.9958, +68.7681, 5.00 }, { 6162, 247.9471, +45.5983, 5.65 }, { 6163, 250.7692, -76.4825, 4.24 }, { 6164, 249.0938, -41.1411, 5.47 }, + { 6165, 248.9708, -27.7839, 2.82 }, { 6166, 249.0938, -34.7444, 4.16 }, { 6167, 249.7196, -59.0097, 6.18 }, { 6168, 248.5258, +42.4369, 4.20 }, + { 6169, 248.8596, +17.0572, 6.41 }, { 6170, 248.1071, +60.8233, 5.94 }, { 6171, 249.0896, -1.6753, 5.75 }, { 6172, 250.3471, -67.7039, 5.91 }, + { 6173, 246.4296, +78.9639, 5.56 }, { 6174, 249.6092, -42.6014, 5.83 }, { 6175, 249.2896, -9.4328, 2.56 }, { 6176, 249.1792, +15.4981, 6.30 }, + { 6177, 250.2104, -59.5539, 6.18 }, { 6178, 249.7717, -36.7825, 5.91 }, { 6179, 249.5067, -5.4619, 6.09 }, { 6180, 247.8671, +72.6119, 6.30 }, + { 6181, 249.4500, +13.6869, 6.31 }, { 6182, 250.8421, -66.5675, 6.03 }, { 6183, 249.0467, +46.6133, 5.79 }, { 6184, 249.0479, +52.9003, 5.53 }, + { 6185, 249.0571, +52.9244, 5.08 }, { 6186, 249.0588, +52.9242, 6.53 }, { 6187, 250.3346, -47.2369, 5.65 }, { 6188, 250.4175, -48.3483, 5.65 }, + { 6189, 249.9129, -8.4456, 6.35 }, { 6190, 250.1438, -19.5914, 6.26 }, { 6191, 247.6617, +77.4467, 6.34 }, { 6192, 250.4396, -32.8536, 5.87 }, + { 6193, 250.4008, -23.5319, 6.09 }, { 6194, 250.1463, +4.2072, 6.93 }, { 6195, 250.1613, +4.2197, 5.77 }, { 6196, 250.3933, -16.2578, 4.96 }, + { 6197, 250.7642, -45.9294, 6.23 }, { 6198, 249.2292, +63.0728, 6.16 }, { 6199, 249.5017, +56.0156, 5.29 }, { 6200, 249.6871, +48.9283, 4.90 }, + { 6201, 250.2979, -0.9994, 6.24 }, { 6202, 250.4738, -18.0756, 5.57 }, { 6203, 250.2142, +12.3950, 6.08 }, { 6204, 251.6667, -66.8903, 5.13 }, + { 6205, 250.4271, +1.1811, 5.74 }, { 6206, 250.9396, -40.8811, 6.20 }, { 6207, 251.1658, -52.8475, 5.96 }, { 6208, 250.2525, +24.8586, 6.06 }, + { 6209, 250.9746, -40.8869, 6.12 }, { 6210, 250.9483, -37.8433, 6.05 }, { 6211, 250.9113, -31.8939, 6.46 }, { 6212, 250.3217, +31.6031, 2.81 }, + { 6213, 250.4029, +26.9169, 5.92 }, { 6214, 251.1775, -39.1603, 5.71 }, { 6215, 251.5883, -57.4964, 5.74 }, { 6216, 251.0721, -26.5439, 6.58 }, + { 6217, 252.1662, -68.9722, 1.92 }, { 6218, 251.2508, -27.4903, 6.02 }, { 6219, 251.8313, -57.6586, 5.58 }, { 6220, 250.7242, +38.9222, 3.53 }, + { 6221, 251.6992, -38.6228, 5.48 }, { 6222, 250.9654, +34.0389, 5.99 }, { 6223, 250.2296, +64.5892, 4.83 }, { 6224, 251.3738, +1.0203, 6.03 }, + { 6225, 251.7138, -24.4714, 6.71 }, { 6226, 250.7433, +55.6903, 6.16 }, { 6227, 251.3438, +15.7453, 5.56 }, { 6228, 251.4579, +8.5825, 5.15 }, + { 6229, 252.4462, -58.9586, 3.76 }, { 6230, 251.2988, +43.2172, 6.05 }, { 6231, 253.0725, -66.3181, 6.32 }, { 6232, 251.7908, +2.0644, 6.10 }, + { 6233, 252.9746, -64.6244, 6.13 }, { 6234, 251.9433, +5.2467, 5.24 }, { 6235, 252.1125, -13.0906, 6.03 }, { 6236, 252.6496, -49.9544, 6.47 }, + { 6237, 251.3242, +56.7819, 4.85 }, { 6238, 249.4704, +78.9183, 6.32 }, { 6239, 252.0371, +13.5906, 6.35 }, { 6240, 252.3658, -14.3325, 6.10 }, + { 6241, 252.5408, -33.7067, 2.29 }, { 6242, 251.8325, +42.2389, 5.87 }, { 6243, 252.4583, -9.2169, 4.65 }, { 6244, 252.7492, -36.4856, 6.11 }, + { 6245, 252.8904, -40.7694, 5.22 }, { 6246, 252.3942, +13.2614, 5.91 }, { 6247, 252.9675, -37.9525, 3.08 }, { 6248, 252.5929, -1.3461, 6.32 }, + { 6249, 253.0796, -40.1456, 6.49 }, { 6250, 252.5808, +7.2478, 5.49 }, { 6251, 253.5021, -56.0906, 5.94 }, { 6252, 253.0838, -37.9825, 3.57 }, + { 6253, 253.8529, -62.7303, 6.02 }, { 6254, 252.3092, +45.9833, 4.82 }, { 6255, 252.8537, +1.2161, 5.51 }, { 6256, 252.4187, +43.4306, 6.13 }, + { 6257, 253.4271, -42.9492, 5.96 }, { 6258, 252.6625, +29.8067, 5.72 }, { 6259, 252.6796, +32.5536, 6.13 }, { 6260, 253.5075, -40.1936, 5.45 }, + { 6261, 253.4950, -40.0053, 6.32 }, { 6262, 253.4988, -41.6378, 4.73 }, { 6263, 253.5492, -40.1497, 6.45 }, { 6264, 252.6504, +41.8967, 6.29 }, + { 6265, 253.5817, -40.1800, 6.59 }, { 6266, 253.6121, -41.5211, 5.88 }, { 6267, 250.7750, +77.5142, 5.98 }, { 6268, 253.0204, +14.9742, 6.52 }, + { 6269, 253.3550, -19.5844, 5.88 }, { 6270, 252.9388, +24.6564, 5.04 }, { 6271, 253.6458, -41.6386, 3.62 }, { 6272, 253.7433, -40.8489, 5.77 }, + { 6273, 253.6500, -29.4128, 6.35 }, { 6274, 254.0371, -49.3250, 6.33 }, { 6275, 254.1196, -51.7161, 5.94 }, { 6276, 254.8908, -68.7317, 5.79 }, + { 6277, 253.5442, -0.3878, 6.25 }, { 6278, 253.6679, -10.2075, 6.57 }, { 6279, 253.2421, +31.7017, 5.32 }, { 6280, 253.6488, -5.8461, 5.25 }, + { 6281, 253.5021, +10.1653, 4.38 }, { 6282, 253.9908, -32.4928, 6.37 }, { 6283, 254.1500, -39.1764, 6.15 }, { 6284, 254.0075, -15.1939, 6.37 }, + { 6285, 254.6550, -54.0097, 3.13 }, { 6286, 253.3233, +47.4169, 6.00 }, { 6287, 253.7300, +20.9586, 5.41 }, { 6288, 254.2962, -32.7406, 5.48 }, + { 6289, 254.5750, -49.3589, 5.55 }, { 6290, 253.8167, +13.6197, 6.34 }, { 6291, 254.2000, -22.8500, 5.58 }, { 6292, 253.7587, +25.7306, 6.08 }, + { 6293, 253.8425, +18.4333, 5.35 }, { 6294, 254.2667, -18.4600, 6.27 }, { 6295, 254.8963, -52.8394, 4.06 }, { 6296, 254.3587, -9.0367, 6.19 }, + { 6297, 255.0258, -53.4031, 5.65 }, { 6298, 254.7183, -36.3789, 6.09 }, { 6299, 254.4171, +9.3750, 3.20 }, { 6300, 255.1129, -47.3522, 6.00 }, + { 6301, 254.3833, +13.8842, 6.37 }, { 6302, 254.6733, -13.1303, 6.59 }, { 6303, 255.1346, -44.5483, 6.65 }, { 6304, 255.4475, -57.0417, 6.11 }, + { 6305, 254.3792, +25.3528, 6.28 }, { 6306, 254.0267, +50.0389, 6.56 }, { 6307, 254.4263, +24.3814, 6.32 }, { 6308, 254.9900, -24.9081, 5.86 }, + { 6309, 0.0000, +0.0000, 0.00 }, { 6310, 255.0396, -23.0108, 5.75 }, { 6311, 255.1538, -34.0658, 5.97 }, { 6312, 255.4421, -50.8692, 6.45 }, + { 6313, 254.4592, +42.5125, 6.34 }, { 6314, 255.7867, -52.7631, 5.29 }, { 6315, 254.0071, +65.1347, 4.89 }, { 6316, 255.4696, -31.8564, 5.03 }, + { 6317, 255.1225, +6.5836, 6.59 }, { 6318, 255.2650, -3.7775, 4.82 }, { 6319, 254.1050, +65.0392, 6.41 }, { 6320, 256.1029, -56.2878, 5.73 }, + { 6321, 255.4633, -17.1144, 6.26 }, { 6322, 251.4921, +82.0372, 4.23 }, { 6323, 255.9238, -46.8400, 6.06 }, { 6324, 255.0725, +30.9264, 3.92 }, + { 6325, 255.2421, +22.6322, 5.65 }, { 6326, 255.3875, +14.9494, 6.31 }, { 6327, 255.9617, -37.8478, 5.91 }, { 6328, 255.2900, +27.1964, 6.55 }, + { 6329, 255.4963, +8.4506, 6.33 }, { 6330, 254.8396, +56.6886, 6.03 }, { 6331, 256.2721, -44.4983, 6.28 }, { 6332, 255.4017, +33.5683, 5.25 }, + { 6333, 255.5779, +25.5056, 5.75 }, { 6334, 256.2058, -33.8772, 4.87 }, { 6335, 254.0700, +73.1278, 6.30 }, { 6336, 255.5717, +31.8847, 6.36 }, + { 6337, 255.7825, +14.0919, 4.98 }, { 6338, 256.4525, -43.8950, 6.19 }, { 6339, 255.7933, +14.5111, 6.52 }, { 6340, 256.1888, -19.5053, 6.30 }, + { 6341, 255.9137, +13.6053, 5.93 }, { 6342, 255.9917, +13.5675, 6.08 }, { 6343, 255.9696, +19.6906, 6.35 }, { 6344, 256.5846, -36.7725, 5.98 }, + { 6345, 254.7608, +69.1864, 6.40 }, { 6346, 255.8758, +35.4142, 6.69 }, { 6347, 256.6183, -34.5489, 6.13 }, { 6348, 255.3196, +60.6492, 6.13 }, + { 6349, 256.3204, +0.7025, 6.01 }, { 6350, 256.5492, -20.4353, 6.30 }, { 6351, 255.9729, +34.7903, 6.04 }, { 6352, 256.1721, +19.5992, 6.17 }, + { 6353, 256.3846, +0.8919, 5.64 }, { 6354, 256.7217, -25.4869, 6.29 }, { 6355, 256.3446, +12.7408, 4.91 }, { 6356, 257.5263, -60.3244, 6.39 }, + { 6357, 258.0825, -69.2789, 6.22 }, { 6358, 256.5404, +9.7333, 6.37 }, { 6359, 256.5546, +10.4542, 6.37 }, { 6360, 255.5638, +64.6006, 6.10 }, + { 6361, 256.7204, -0.3436, 6.38 }, { 6362, 256.2708, +43.8122, 6.43 }, { 6363, 256.2075, +48.8042, 6.09 }, { 6364, 256.5754, +22.0842, 5.56 }, + { 6365, 257.0621, -16.3908, 5.99 }, { 6366, 257.1979, -29.5964, 5.97 }, { 6367, 257.0567, -0.9206, 6.06 }, { 6368, 258.3229, -66.8033, 5.89 }, + { 6369, 256.3325, +54.4703, 5.83 }, { 6370, 256.3321, +54.4703, 5.80 }, { 6371, 257.6762, -43.4425, 5.08 }, { 6372, 257.2271, -2.1172, 6.36 }, + { 6373, 259.1483, -73.4669, 6.25 }, { 6374, 257.9121, -47.1258, 5.84 }, { 6375, 257.4500, -9.4767, 5.56 }, { 6376, 256.9446, +40.5161, 6.34 }, + { 6377, 257.0083, +35.9353, 5.39 }, { 6378, 257.5946, -14.2753, 2.43 }, { 6379, 255.4175, +75.2972, 6.21 }, { 6380, 258.0383, -42.7608, 3.33 }, + { 6381, 258.0675, -38.4931, 5.67 }, { 6382, 258.0688, -37.1778, 6.30 }, { 6383, 257.0713, +50.8422, 6.46 }, { 6384, 258.5550, -55.1117, 6.09 }, + { 6385, 257.6908, +12.4672, 6.57 }, { 6386, 258.0567, -24.7453, 6.54 }, { 6387, 258.1042, -26.2381, 6.14 }, { 6388, 257.3888, +40.7772, 5.08 }, + { 6389, 258.2446, -31.5614, 6.01 }, { 6390, 257.9383, +7.8947, 6.33 }, { 6391, 257.7633, +24.2378, 6.19 }, { 6392, 258.6154, -38.2331, 6.60 }, + { 6393, 258.1158, +10.5853, 5.33 }, { 6394, 258.2267, +0.3519, 6.65 }, { 6395, 257.6275, +52.4089, 6.29 }, { 6396, 257.1967, +65.7147, 3.17 }, + { 6397, 258.8304, -32.4517, 5.53 }, { 6398, 258.8996, -37.4061, 5.96 }, { 6399, 257.9175, +49.7467, 6.04 }, { 6400, 260.0533, -69.9544, 6.53 }, + { 6401, 258.8375, -25.3972, 5.11 }, { 6402, 258.8367, -25.3986, 5.07 }, { 6403, 258.9646, -29.7894, 6.21 }, { 6404, 258.8346, -13.4161, 5.99 }, + { 6405, 259.0896, -34.2506, 6.12 }, { 6406, 258.6621, +14.3903, 3.48 }, { 6407, 258.6633, +14.3900, 5.39 }, { 6408, 259.8017, -58.3056, 5.91 }, + { 6409, 259.2654, -31.3372, 5.55 }, { 6410, 258.7579, +24.8392, 3.14 }, { 6411, 260.5246, -69.8767, 5.41 }, { 6412, 259.0592, +2.1861, 6.17 }, + { 6413, 259.1783, -5.7550, 6.09 }, { 6414, 259.1321, +1.2106, 5.88 }, { 6415, 259.1529, +0.4453, 4.73 }, { 6416, 259.7633, -45.3661, 5.48 }, + { 6417, 260.4975, -66.2294, 4.78 }, { 6418, 258.7617, +36.8092, 3.16 }, { 6419, 258.9233, +23.7428, 5.96 }, { 6420, 259.7000, -43.8703, 5.76 }, + { 6421, 258.1358, +62.8744, 5.56 }, { 6422, 259.5850, -31.4467, 6.36 }, { 6423, 259.8763, -49.9367, 6.27 }, { 6424, 259.5029, -23.7131, 5.20 }, + { 6425, 259.5021, -23.7158, 6.80 }, { 6426, 259.7383, -33.0103, 5.91 }, { 6427, 259.8521, -43.7769, 6.65 }, { 6428, 259.5800, -15.6881, 6.43 }, + { 6429, 262.8637, -79.1408, 5.88 }, { 6430, 259.3996, +23.0908, 6.45 }, { 6431, 259.3313, +33.1000, 4.82 }, { 6432, 259.5208, +17.3181, 6.00 }, + { 6433, 259.6542, +10.8644, 5.03 }, { 6434, 259.7200, +6.0853, 6.51 }, { 6435, 259.9721, -16.2436, 6.02 }, { 6436, 259.4179, +37.2917, 4.65 }, + { 6437, 259.2025, +49.6911, 7.48 }, { 6438, 260.7292, -57.9897, 5.88 }, { 6439, 259.9979, -4.0828, 6.32 }, { 6440, 261.0046, -61.1358, 5.70 }, + { 6441, 260.1425, -18.6672, 6.52 }, { 6442, 260.7788, -55.4747, 5.80 }, { 6443, 259.7021, +28.8231, 5.65 }, { 6444, 259.5971, +38.8114, 5.94 }, + { 6445, 260.2508, -20.8872, 4.39 }, { 6446, 260.2071, -11.1531, 4.33 }, { 6447, 261.0779, -59.3264, 5.77 }, { 6448, 259.1225, +60.6706, 6.32 }, + { 6449, 260.2196, -9.3039, 6.46 }, { 6450, 260.6642, -36.1950, 6.41 }, { 6451, 260.8171, -46.5317, 5.25 }, { 6452, 260.0788, +18.0572, 5.00 }, + { 6453, 260.5025, -23.0006, 3.27 }, { 6454, 260.6583, -34.0900, 6.47 }, { 6455, 260.0408, +25.5375, 5.38 }, { 6456, 260.7287, -36.7794, 5.93 }, + { 6457, 260.2258, +24.4994, 5.12 }, { 6458, 260.1650, +32.4678, 5.39 }, { 6459, 260.8400, -27.8569, 5.35 }, { 6460, 261.0542, -43.8375, 5.12 }, + { 6461, 261.3250, -54.4700, 2.85 }, { 6462, 261.3483, -55.6225, 3.34 }, { 6463, 260.3892, +16.7308, 6.35 }, { 6464, 260.0879, +46.2408, 5.59 }, + { 6465, 260.7138, -1.6117, 6.29 }, { 6466, 260.3800, +28.7581, 6.35 }, { 6467, 260.1400, +48.1883, 6.43 }, { 6468, 261.5000, -49.3664, 5.23 }, + { 6469, 260.4317, +39.9744, 5.51 }, { 6470, 261.2613, -33.3036, 6.16 }, { 6471, 262.0321, -62.9636, 6.24 }, { 6472, 261.1750, -20.5583, 5.85 }, + { 6473, 261.1546, -17.5542, 6.21 }, { 6474, 261.2758, -23.7564, 6.19 }, { 6475, 261.7346, -50.0508, 6.19 }, { 6476, 260.9900, +8.8528, 5.77 }, + { 6477, 261.7146, -44.1564, 5.29 }, { 6478, 261.8017, -49.3697, 5.92 }, { 6479, 260.4392, +53.4206, 5.67 }, { 6480, 261.0275, +22.9603, 5.74 }, + { 6481, 261.1313, +16.3011, 5.71 }, { 6482, 261.1408, +15.6061, 6.35 }, { 6483, 261.9900, -51.7028, 5.75 }, { 6484, 260.9196, +37.1467, 5.47 }, + { 6485, 260.9208, +37.1458, 4.52 }, { 6486, 261.5925, -23.8247, 4.17 }, { 6487, 262.1613, -54.8303, 5.94 }, { 6488, 261.0092, +38.5828, 6.49 }, + { 6489, 261.4912, -0.3483, 6.44 }, { 6490, 261.7300, -24.0567, 6.44 }, { 6491, 261.1129, +36.9519, 6.28 }, { 6492, 261.8388, -28.1331, 4.29 }, + { 6493, 261.6579, -4.9133, 4.54 }, { 6494, 261.9063, -28.2756, 6.00 }, { 6495, 261.4767, +16.9175, 5.98 }, { 6496, 261.7588, -11.4875, 6.21 }, + { 6497, 261.5792, +7.5956, 6.06 }, { 6498, 261.6288, +4.1403, 4.34 }, { 6499, 261.5038, +26.8789, 6.41 }, { 6500, 262.7746, -59.3161, 3.62 }, + { 6501, 262.2337, -35.2217, 6.02 }, { 6502, 261.7046, +20.0808, 5.54 }, { 6503, 262.3571, -37.4833, 6.39 }, { 6504, 262.0096, -7.7917, 6.37 }, + { 6505, 262.8458, -55.0794, 5.95 }, { 6506, 261.6925, +34.6958, 5.94 }, { 6507, 262.2071, +0.3306, 5.44 }, { 6508, 262.6908, -36.7042, 2.69 }, + { 6509, 261.6842, +48.2600, 5.85 }, { 6510, 262.9604, -48.1239, 2.95 }, { 6511, 261.4221, +60.0483, 5.65 }, { 6512, 262.4475, -4.0803, 6.37 }, + { 6513, 262.9546, -45.9636, 6.03 }, { 6514, 261.5204, +58.6519, 6.51 }, { 6515, 0.0000, +0.0000, 0.00 }, { 6516, 262.5992, -0.9375, 5.31 }, + { 6517, 262.9475, -32.2972, 6.44 }, { 6518, 261.2508, +67.3064, 6.43 }, { 6519, 262.8542, -22.0372, 4.81 }, { 6520, 262.9350, -25.7303, 6.05 }, + { 6521, 262.5933, +11.9250, 6.39 }, { 6522, 263.1021, -33.7203, 6.17 }, { 6523, 263.2808, -40.8264, 5.84 }, { 6524, 262.8388, +2.7244, 5.59 }, + { 6525, 263.8954, -58.1539, 6.28 }, { 6526, 262.6846, +26.1106, 4.41 }, { 6527, 263.4021, -36.8961, 1.63 }, { 6528, 262.7308, +31.1583, 5.61 }, + { 6529, 259.9042, +80.1364, 5.72 }, { 6530, 263.8333, -52.6472, 6.10 }, { 6531, 262.6679, +38.8822, 6.43 }, { 6532, 263.0625, +11.9303, 6.42 }, + { 6533, 262.9567, +28.4075, 5.62 }, { 6534, 263.3746, -4.2553, 5.62 }, { 6535, 263.6771, -31.4183, 5.70 }, { 6536, 262.6083, +52.3014, 2.79 }, + { 6537, 263.9150, -45.4944, 4.59 }, { 6538, 263.0046, +34.2708, 6.56 }, { 6539, 263.9292, -36.5600, 6.48 }, { 6540, 262.6825, +57.8764, 6.40 }, + { 6541, 263.3450, +19.2567, 5.64 }, { 6542, 263.4142, +16.3175, 5.69 }, { 6543, 263.4283, +14.8417, 6.48 }, { 6544, 263.6933, -10.7581, 5.55 }, + { 6545, 263.8271, -21.9561, 6.57 }, { 6546, 264.1367, -37.3647, 4.29 }, { 6547, 264.3633, -49.9400, 5.93 }, { 6548, 263.6529, +9.5867, 5.81 }, + { 6549, 264.5233, -53.4997, 5.25 }, { 6550, 263.2804, +41.2436, 5.74 }, { 6551, 263.6133, +16.5039, 6.40 }, { 6552, 270.3921, -84.7853, 6.45 }, + { 6553, 264.3300, -41.0022, 1.87 }, { 6554, 263.0442, +55.1842, 4.88 }, { 6555, 263.0667, +55.1731, 4.87 }, { 6556, 263.7337, +12.5600, 2.08 }, + { 6557, 264.3617, -37.9344, 6.26 }, { 6558, 264.5354, -41.1194, 6.10 }, { 6559, 263.9983, +20.9961, 6.10 }, { 6560, 263.3821, +57.5589, 6.17 }, + { 6561, 264.3967, -14.6014, 3.54 }, { 6562, 264.4008, -14.4289, 5.94 }, { 6563, 263.9267, +37.3017, 6.10 }, { 6564, 264.0329, +28.1847, 6.38 }, + { 6565, 266.0821, -71.7792, 6.49 }, { 6566, 262.9912, +68.1350, 5.05 }, { 6567, 264.4613, -7.8811, 4.62 }, { 6568, 264.5396, -9.0736, 5.75 }, + { 6569, 265.0983, -48.5844, 4.77 }, { 6570, 264.1529, +30.7853, 6.02 }, { 6571, 264.3796, +24.3100, 5.77 }, { 6572, 265.3179, -45.0781, 5.79 }, + { 6573, 263.7479, +61.8750, 5.23 }, { 6574, 264.1567, +48.5856, 5.37 }, { 6575, 264.7854, +2.0281, 6.26 }, { 6576, 265.5163, -49.4894, 6.24 }, + { 6577, 264.7408, +13.3292, 6.12 }, { 6578, 265.0492, -1.8475, 6.19 }, { 6579, 264.7071, +32.7394, 6.37 }, { 6580, 265.6221, -38.9700, 2.41 }, + { 6581, 265.3537, -11.1247, 4.26 }, { 6582, 266.4333, -63.2761, 3.62 }, { 6583, 265.7125, -35.0542, 5.54 }, { 6584, 264.9896, +31.2025, 6.03 }, + { 6585, 266.0363, -50.1658, 5.15 }, { 6586, 266.2325, -56.4547, 6.01 }, { 6587, 265.7788, -32.9489, 6.40 }, { 6588, 264.8662, +46.0064, 3.80 }, + { 6589, 265.2958, +15.1781, 6.34 }, { 6590, 265.3846, +6.3128, 5.95 }, { 6591, 265.1717, +31.2875, 6.28 }, { 6592, 265.2729, +24.5133, 6.36 }, + { 6593, 265.8242, -26.1158, 6.36 }, { 6594, 265.4946, +15.9519, 5.52 }, { 6595, 265.8575, -20.3167, 4.87 }, { 6596, 264.2379, +68.7581, 4.80 }, + { 6597, 266.1750, -41.2711, 5.87 }, { 6598, 264.1654, +69.5708, 6.42 }, { 6599, 265.1567, +43.4708, 6.59 }, { 6600, 265.9525, -12.4914, 6.39 }, + { 6601, 265.9458, -6.9206, 6.30 }, { 6602, 265.6183, +24.5642, 5.52 }, { 6603, 265.8683, +4.5672, 2.77 }, { 6604, 265.8417, +14.2950, 6.24 }, + { 6605, 265.1508, +57.3103, 6.77 }, { 6606, 264.2867, +72.4558, 5.86 }, { 6607, 265.3408, +51.8181, 5.99 }, { 6608, 265.8400, +24.3278, 5.71 }, + { 6609, 266.1417, +2.5794, 6.17 }, { 6610, 266.1475, +2.5789, 6.56 }, { 6611, 266.0721, +14.4103, 6.19 }, { 6612, 265.7733, +44.0844, 6.34 }, + { 6613, 266.7804, -37.8883, 6.43 }, { 6614, 267.1588, -54.5983, 6.11 }, { 6615, 266.8963, -39.8731, 3.03 }, { 6616, 266.8900, -26.1692, 4.54 }, + { 6617, 266.9400, -21.5219, 6.18 }, { 6618, 265.9971, +53.8017, 5.75 }, { 6619, 266.4179, +31.5047, 6.23 }, { 6620, 266.9033, -13.2742, 5.94 }, + { 6621, 267.1158, -25.0250, 6.35 }, { 6622, 267.6175, -52.3878, 5.92 }, { 6623, 266.6146, +27.7206, 3.42 }, { 6624, 267.8979, -59.8356, 5.78 }, + { 6625, 266.4738, +38.8814, 6.52 }, { 6626, 266.4937, +39.3225, 6.68 }, { 6627, 266.7833, +17.6972, 5.72 }, { 6628, 267.2937, -30.2967, 4.83 }, + { 6629, 266.9733, +2.7072, 3.75 }, { 6630, 267.4646, -36.9567, 3.21 }, { 6631, 267.5467, -39.9094, 4.81 }, { 6632, 267.7958, -52.8694, 6.09 }, + { 6633, 267.0842, +3.8042, 6.22 }, { 6634, 268.3267, -64.5108, 6.49 }, { 6635, 269.4242, -75.8225, 6.07 }, { 6636, 265.4846, +72.1489, 4.58 }, + { 6637, 265.4917, +72.1569, 5.79 }, { 6638, 267.1033, +20.5656, 5.69 }, { 6639, 267.3288, +1.9611, 6.47 }, { 6640, 267.9354, -44.3994, 6.11 }, + { 6641, 266.7838, +47.6122, 6.43 }, { 6642, 267.1996, +19.2553, 6.12 }, { 6643, 267.8867, -39.2275, 5.96 }, { 6644, 267.2050, +25.6228, 5.12 }, + { 6645, 267.8021, -29.4428, 6.66 }, { 6646, 271.3612, -80.5136, 6.35 }, { 6647, 268.0567, -33.2008, 5.90 }, { 6648, 268.0821, -33.5833, 5.84 }, + { 6649, 268.2196, -40.0033, 6.20 }, { 6650, 267.6812, +11.9467, 6.17 }, { 6651, 268.2050, -33.8858, 6.06 }, { 6652, 268.2329, -34.9814, 6.45 }, + { 6653, 268.2412, -34.3758, 6.03 }, { 6654, 267.5954, +29.3222, 5.50 }, { 6655, 267.7017, +22.3164, 5.98 }, { 6656, 267.2679, +50.7811, 5.02 }, + { 6657, 268.3317, -33.2694, 6.17 }, { 6658, 268.3471, -33.1047, 5.60 }, { 6659, 267.9979, -0.7633, 6.35 }, { 6660, 268.4396, -33.2142, 6.38 }, + { 6661, 268.1617, -5.8564, 6.21 }, { 6662, 268.4787, -33.2475, 5.96 }, { 6663, 268.4921, -33.1683, 6.42 }, { 6664, 267.5138, +48.3942, 6.68 }, + { 6665, 267.9937, +15.3258, 6.46 }, { 6666, 268.2650, -9.1003, 6.18 }, { 6667, 268.1475, +1.3050, 5.95 }, { 6668, 268.6133, -33.5336, 5.96 }, + { 6669, 267.8083, +40.0725, 6.46 }, { 6670, 268.3092, +6.1014, 5.77 }, { 6671, 268.7829, -35.5242, 6.06 }, { 6672, 268.7250, -23.1128, 6.20 }, + { 6673, 268.0196, +39.9822, 6.04 }, { 6674, 268.0042, +46.6433, 6.38 }, { 6675, 269.1975, -43.6578, 4.86 }, { 6676, 268.5592, +11.1306, 6.38 }, + { 6677, 268.3254, +40.0081, 5.16 }, { 6678, 269.2325, -39.6944, 6.43 }, { 6679, 268.9792, -17.1978, 6.52 }, { 6680, 269.1746, -27.9347, 5.80 }, + { 6681, 269.0792, -14.1875, 5.89 }, { 6682, 269.4488, -40.2839, 4.88 }, { 6683, 269.4908, -38.8631, 6.29 }, { 6684, 269.0767, +0.6703, 5.82 }, + { 6685, 268.8550, +26.0500, 5.46 }, { 6686, 269.1988, -3.9181, 5.47 }, { 6687, 268.9617, +22.4642, 5.58 }, { 6688, 268.3821, +56.8728, 3.75 }, + { 6689, 269.2679, +0.0664, 5.97 }, { 6690, 269.2333, +6.4878, 6.29 }, { 6691, 269.7317, -35.1417, 5.74 }, { 6692, 269.6629, -27.2408, 6.01 }, + { 6693, 269.7717, -29.7469, 5.16 }, { 6694, 269.7729, -29.7467, 7.04 }, { 6695, 269.0633, +37.2506, 3.86 }, { 6696, 269.3621, +11.0442, 6.36 }, + { 6697, 269.3096, +23.9958, 6.30 }, { 6698, 269.7567, -8.2264, 3.34 }, { 6699, 268.8488, +55.9714, 6.10 }, { 6700, 269.9483, -22.1839, 4.76 }, + { 6701, 267.3625, +76.9628, 5.04 }, { 6702, 269.2017, +45.3508, 6.02 }, { 6703, 269.4413, +29.2478, 3.70 }, { 6704, 270.0004, -19.6608, 6.21 }, + { 6705, 269.1517, +51.4889, 2.23 }, { 6706, 269.9029, -3.1786, 5.87 }, { 6707, 269.6258, +30.1894, 4.41 }, { 6708, 270.4513, -35.6222, 6.30 }, + { 6709, 270.0646, +0.6294, 6.37 }, { 6710, 270.1208, -2.3097, 4.62 }, { 6711, 269.6762, +36.2878, 6.00 }, { 6712, 270.0658, +4.3686, 4.64 }, + { 6713, 270.0142, +16.7508, 4.67 }, { 6714, 270.1613, +2.9317, 3.97 }, { 6715, 270.3463, -16.8431, 6.28 }, { 6716, 270.4767, -21.2194, 5.77 }, + { 6717, 267.5437, +78.3067, 6.24 }, { 6718, 269.7179, +45.4761, 6.48 }, { 6719, 270.2204, +6.2683, 6.34 }, { 6720, 270.1154, +19.5058, 6.50 }, + { 6721, 283.6954, -86.3942, 5.28 }, { 6722, 270.2383, +15.0933, 6.26 }, { 6723, 270.4383, +1.3053, 4.45 }, { 6724, 270.7129, -23.7178, 5.34 }, + { 6725, 268.7967, +72.0050, 5.45 }, { 6726, 270.1517, +33.2139, 5.99 }, { 6727, 270.7571, -21.2817, 6.74 }, { 6728, 269.9842, +45.5014, 5.67 }, + { 6729, 270.3746, +21.5953, 5.18 }, { 6730, 270.3767, +21.5956, 4.96 }, { 6731, 272.8154, -74.1086, 5.86 }, { 6732, 270.6929, -4.6414, 6.76 }, + { 6733, 270.7708, -7.8197, 5.94 }, { 6734, 270.7704, -7.8194, 5.24 }, { 6735, 268.6108, +75.1708, 6.36 }, { 6736, 270.9683, -23.6394, 5.97 }, + { 6737, 270.3996, +33.3114, 6.15 }, { 6738, 270.5963, +20.8336, 5.28 }, { 6739, 271.2100, -34.0986, 6.00 }, { 6740, 271.9513, -63.4500, 6.41 }, + { 6741, 270.6254, +22.9231, 6.21 }, { 6742, 271.2554, -28.4200, 4.69 }, { 6743, 271.6579, -49.9083, 3.66 }, { 6744, 270.8112, +19.6131, 6.50 }, + { 6745, 272.1450, -62.3317, 4.35 }, { 6746, 271.4521, -29.5758, 2.99 }, { 6747, 271.1554, +1.9192, 6.14 }, { 6748, 271.5988, -35.9803, 5.95 }, + { 6749, 271.7075, -42.5753, 5.77 }, { 6750, 271.7075, -42.5753, 5.77 }, { 6751, 273.1438, -72.3283, 5.85 }, { 6752, 271.3637, +2.4994, 4.03 }, + { 6753, 270.7875, +48.4644, 6.21 }, { 6754, 271.1675, +23.9425, 6.34 }, { 6755, 271.5308, -7.6761, 5.85 }, { 6756, 271.5633, -3.2486, 5.77 }, + { 6757, 271.5308, +0.4467, 6.34 }, { 6758, 271.4304, +12.0039, 7.04 }, { 6759, 272.1254, -44.2328, 6.15 }, { 6760, 272.4900, -58.9600, 6.38 }, + { 6761, 272.6087, -61.9978, 5.49 }, { 6762, 271.7975, -20.5561, 6.28 }, { 6763, 271.3758, +21.6469, 6.15 }, { 6764, 271.1800, +40.0842, 6.52 }, + { 6765, 271.5079, +22.2189, 5.06 }, { 6766, 272.0208, -27.5428, 4.57 }, { 6767, 271.2533, +41.9467, 6.34 }, { 6768, 271.4567, +32.2306, 5.71 }, + { 6769, 271.9517, -16.8458, 5.52 }, { 6770, 271.8267, +8.7339, 4.64 }, { 6771, 271.8375, +9.5639, 3.73 }, { 6772, 272.3433, -35.3275, 6.58 }, + { 6773, 272.2254, -24.5275, 6.61 }, { 6774, 273.6004, -69.2486, 6.73 }, { 6775, 271.7563, +30.5619, 5.04 }, { 6776, 271.9517, +13.0711, 6.63 }, + { 6777, 272.4996, -31.2803, 6.43 }, { 6778, 272.7688, -46.4869, 6.07 }, { 6779, 271.8858, +28.7625, 3.83 }, { 6780, 272.5238, -29.2714, 5.53 }, + { 6781, 271.9563, +26.1014, 5.86 }, { 6782, 271.9563, +26.0975, 5.90 }, { 6783, 272.8075, -44.0456, 4.53 }, { 6784, 272.1404, +14.2847, 6.37 }, + { 6785, 272.4308, -12.0656, 6.39 }, { 6786, 272.7733, -40.6408, 5.86 }, { 6787, 272.1896, +20.8144, 4.36 }, { 6788, 272.7300, -32.2003, 6.16 }, + { 6789, 263.0537, +86.5864, 4.36 }, { 6790, 271.7229, +50.8228, 6.29 }, { 6791, 271.8700, +43.4617, 5.00 }, { 6792, 271.7763, +49.7106, 6.32 }, + { 6793, 272.0092, +36.4014, 5.48 }, { 6794, 272.2204, +20.0453, 5.10 }, { 6795, 272.3908, +3.9933, 5.73 }, { 6796, 273.5675, -62.3106, 6.47 }, + { 6797, 272.4750, +3.1197, 5.69 }, { 6798, 272.8117, -18.1578, 6.36 }, { 6799, 272.2925, +30.4694, 6.38 }, { 6800, 272.6679, +3.3242, 5.51 }, + { 6801, 272.9308, -22.2989, 4.98 }, { 6802, 272.9925, -27.0986, 6.51 }, { 6803, 272.5363, +16.4767, 6.09 }, { 6804, 273.3025, -40.6639, 5.47 }, + { 6805, 273.9204, -62.9444, 5.60 }, { 6806, 272.4063, +38.4575, 6.40 }, { 6807, 272.4958, +36.4664, 5.58 }, { 6808, 274.5038, -67.7708, 6.33 }, + { 6809, 270.0142, +80.0008, 6.04 }, { 6810, 270.0383, +80.0042, 5.68 }, { 6811, 262.7000, +86.9681, 5.79 }, { 6812, 273.4408, -20.9411, 3.86 }, + { 6813, 273.2917, -3.9883, 6.59 }, { 6814, 272.9379, +33.4469, 5.88 }, { 6815, 272.9758, +31.4053, 4.97 }, { 6816, 273.5663, -20.2869, 5.44 }, + { 6817, 272.6317, +54.2867, 5.95 }, { 6818, 273.9696, -43.7933, 5.46 }, { 6819, 274.2813, -55.9767, 5.33 }, { 6820, 273.3188, +21.8803, 6.12 }, + { 6821, 274.2538, -50.9317, 6.06 }, { 6822, 273.8037, -19.2717, 5.38 }, { 6823, 273.8037, -19.6119, 5.95 }, { 6824, 273.1775, +41.1469, 6.36 }, + { 6825, 273.8783, -17.3386, 6.07 }, { 6826, 273.2700, +38.7736, 6.04 }, { 6827, 272.7796, +60.4094, 6.49 }, { 6828, 274.9175, -62.1131, 6.18 }, + { 6829, 275.9004, -74.9558, 5.47 }, { 6830, 273.9917, -2.3825, 6.36 }, { 6831, 273.6833, +29.2072, 6.56 }, { 6832, 274.4067, -35.2383, 3.11 }, + { 6833, 274.4004, -33.8928, 6.16 }, { 6834, 274.0233, +2.3778, 6.01 }, { 6835, 274.3500, -27.3475, 6.19 }, { 6836, 274.3488, -27.7108, 6.40 }, + { 6837, 277.3313, -79.7672, 5.95 }, { 6838, 274.2983, -16.6261, 5.75 }, { 6839, 274.6667, -41.7117, 6.30 }, { 6840, 274.2213, -2.9928, 6.00 }, + { 6841, 274.3687, -17.5367, 6.54 }, { 6842, 274.5133, -26.9575, 4.65 }, { 6843, 274.3508, -8.2414, 6.31 }, { 6844, 274.2700, +1.0058, 6.63 }, + { 6845, 273.9117, +42.1594, 5.59 }, { 6846, 274.6737, -24.3953, 6.51 }, { 6847, 273.8858, +45.2094, 6.29 }, { 6848, 274.6804, -17.3806, 6.84 }, + { 6849, 273.6712, +56.5883, 6.37 }, { 6850, 273.4742, +64.3972, 5.03 }, { 6851, 274.5121, +13.7769, 6.30 }, { 6852, 274.5321, +18.1314, 5.99 }, + { 6853, 274.2783, +40.9367, 6.11 }, { 6854, 274.5321, +23.2967, 6.63 }, { 6855, 275.8067, -60.5061, 4.36 }, { 6856, 275.2304, -36.5125, 6.45 }, + { 6857, 274.7896, +7.2597, 5.39 }, { 6858, 275.0367, -14.1683, 5.39 }, { 6859, 275.2487, -28.1719, 2.70 }, { 6860, 274.7946, +24.4461, 5.27 }, + { 6861, 275.3808, -23.0850, 6.25 }, { 6862, 275.5775, -37.3431, 5.10 }, { 6863, 275.3463, -17.1400, 5.75 }, { 6864, 275.5008, -27.5700, 6.16 }, + { 6865, 273.8208, +68.7558, 5.95 }, { 6866, 275.2171, +3.3772, 4.86 }, { 6867, 274.9671, +29.6661, 5.99 }, { 6868, 275.0746, +21.9614, 4.95 }, + { 6869, 275.3275, -1.1011, 3.26 }, { 6870, 275.7213, -35.3306, 5.34 }, { 6871, 276.3813, -62.9786, 6.14 }, { 6872, 274.9654, +36.0644, 4.33 }, + { 6873, 275.3687, +5.4358, 6.13 }, { 6874, 275.8704, -35.7617, 5.55 }, { 6875, 276.0758, -43.8897, 5.25 }, { 6876, 275.2379, +29.8589, 5.63 }, + { 6877, 275.2542, +28.8700, 5.12 }, { 6878, 275.7592, -9.7814, 6.33 }, { 6879, 276.0429, -33.6153, 1.85 }, { 6880, 274.9837, +51.3478, 6.30 }, + { 6881, 275.8008, -11.9853, 5.73 }, { 6882, 275.5363, +23.2853, 5.41 }, { 6883, 275.6471, +12.0289, 5.89 }, { 6884, 275.9146, -7.0658, 4.68 }, + { 6885, 275.7042, +17.8267, 5.25 }, { 6886, 275.2796, +49.7256, 6.40 }, { 6887, 275.7621, +16.6881, 6.22 }, { 6888, 276.2563, -29.2433, 5.60 }, + { 6889, 276.3404, -34.0083, 6.15 }, { 6890, 276.0146, -2.4167, 6.38 }, { 6891, 275.3863, +49.1217, 5.05 }, { 6892, 276.1754, -6.9247, 6.31 }, + { 6893, 276.4775, -32.0547, 6.30 }, { 6894, 276.7246, -47.8831, 5.46 }, { 6895, 275.9246, +21.7697, 3.84 }, { 6896, 276.3375, -19.4583, 4.81 }, + { 6897, 276.7433, -44.0317, 3.51 }, { 6898, 276.2375, -0.4206, 6.15 }, { 6899, 278.2304, -72.0344, 5.89 }, { 6900, 276.2867, +5.0847, 6.74 }, + { 6901, 275.9892, +38.7392, 6.36 }, { 6902, 276.4117, +8.0319, 5.65 }, { 6903, 276.0575, +39.5072, 5.12 }, { 6904, 276.2437, +27.3953, 6.27 }, + { 6905, 277.2079, -48.9292, 4.13 }, { 6906, 276.4808, +14.9667, 6.37 }, { 6907, 276.9563, -28.1836, 5.92 }, { 6908, 277.4862, -56.4769, 5.76 }, + { 6909, 276.9325, -25.3653, 6.31 }, { 6910, 277.1129, -37.0044, 5.64 }, { 6911, 275.9492, +53.3008, 6.32 }, { 6912, 280.5587, -80.1922, 6.27 }, + { 6913, 276.9925, -24.5783, 2.81 }, { 6914, 277.0258, -25.2428, 6.27 }, { 6915, 277.3037, -42.1542, 6.36 }, { 6916, 277.8433, -61.7217, 4.64 }, + { 6917, 276.4950, +29.8289, 5.83 }, { 6918, 276.8021, +0.1961, 5.21 }, { 6919, 276.9854, -16.2000, 6.20 }, { 6920, 275.1896, +71.3378, 4.22 }, + { 6921, 277.3200, -37.1489, 6.63 }, { 6922, 277.4825, -46.7797, 5.70 }, { 6923, 275.9771, +58.8006, 4.98 }, { 6924, 276.6704, +26.4494, 6.53 }, + { 6925, 276.9596, +3.7486, 6.07 }, { 6926, 277.2392, -25.4183, 6.50 }, { 6927, 275.2642, +72.7328, 3.57 }, { 6928, 276.9950, +6.1942, 5.73 }, + { 6929, 277.3417, -24.7436, 6.59 }, { 6930, 277.2996, -13.4342, 4.70 }, { 6931, 277.7625, -40.0864, 6.04 }, { 6932, 277.4450, -13.4183, 5.96 }, + { 6933, 277.5496, -17.2711, 5.66 }, { 6934, 277.9392, -44.0850, 4.96 }, { 6935, 277.4208, -0.0147, 5.39 }, { 6936, 277.7700, -31.0108, 5.34 }, + { 6937, 277.9842, -42.4922, 5.72 }, { 6938, 278.0083, -44.2428, 5.07 }, { 6939, 278.3729, -57.2908, 6.44 }, { 6940, 277.5596, -4.2758, 6.28 }, + { 6941, 277.5213, +4.0653, 6.69 }, { 6942, 278.0892, -38.2961, 5.16 }, { 6943, 277.3988, +23.8661, 5.90 }, { 6944, 277.8596, -17.5972, 5.14 }, + { 6945, 276.4962, +65.5636, 4.82 }, { 6946, 277.8571, -9.2042, 5.72 }, { 6947, 277.9721, -18.8750, 6.68 }, { 6948, 278.2538, -38.1078, 6.22 }, + { 6949, 276.9262, +59.5492, 6.43 }, { 6950, 277.6733, +20.8153, 6.50 }, { 6951, 278.3758, -41.6875, 4.64 }, { 6952, 278.3471, -37.2797, 6.32 }, + { 6953, 278.3463, -37.2739, 5.65 }, { 6954, 278.6300, -51.1081, 6.22 }, { 6955, 277.7683, +16.9286, 5.77 }, { 6956, 278.0867, -13.3558, 6.37 }, + { 6957, 277.9875, -0.9969, 5.94 }, { 6958, 278.0292, +3.6597, 6.43 }, { 6959, 278.1804, -13.1344, 5.50 }, { 6960, 278.4908, -32.9833, 5.28 }, + { 6961, 278.4729, -23.9675, 5.49 }, { 6962, 278.4125, -13.1464, 5.76 }, { 6963, 278.3454, -4.0886, 6.36 }, { 6964, 282.9912, -82.6836, 7.16 }, + { 6965, 278.6367, -23.7775, 6.51 }, { 6966, 278.1925, +23.6169, 5.84 }, { 6967, 278.3471, +8.2683, 6.42 }, { 6968, 278.2079, +30.5542, 5.48 }, + { 6969, 278.8388, -19.1592, 6.48 }, { 6970, 278.7600, -9.0228, 5.14 }, { 6971, 278.3463, +30.8925, 6.59 }, { 6972, 278.9987, -28.3008, 6.37 }, + { 6973, 278.8017, -7.7558, 3.85 }, { 6974, 278.0475, +52.1156, 6.56 }, { 6975, 278.5817, +20.4664, 6.57 }, { 6976, 278.6979, +10.8917, 6.40 }, + { 6977, 278.8025, +18.2033, 5.78 }, { 6978, 278.1438, +57.0456, 4.77 }, { 6979, 277.8117, +65.4361, 6.59 }, { 6980, 278.8767, +23.6056, 5.61 }, + { 6981, 278.9717, +16.9756, 6.21 }, { 6982, 280.7588, -70.5719, 4.01 }, { 6983, 278.4862, +52.3536, 5.36 }, { 6984, 278.8062, +34.4578, 6.10 }, + { 6985, 279.1158, +9.1225, 5.39 }, { 6986, 279.8096, -46.0903, 5.86 }, { 6987, 279.1629, +6.6719, 5.45 }, { 6988, 279.4767, -20.6022, 5.94 }, + { 6989, 279.5192, -13.9953, 6.47 }, { 6990, 279.6279, -22.4950, 5.81 }, { 6991, 279.8958, -42.8139, 5.37 }, { 6992, 279.3025, +11.4217, 6.42 }, + { 6993, 279.4000, +0.3094, 5.75 }, { 6994, 281.9558, -76.1328, 6.39 }, { 6995, 279.2875, +16.1983, 6.29 }, { 6996, 280.5938, -63.3569, 6.37 }, + { 6997, 279.1550, +33.4689, 5.42 }, { 6998, 279.7225, -20.9481, 5.86 }, { 6999, 279.5988, -2.8064, 6.49 }, { 7000, 279.5796, -0.8867, 6.66 }, + { 7001, 279.2346, +38.7836, 0.03 }, { 7002, 279.5875, +8.8339, 6.40 }, { 7003, 279.1900, +43.2219, 6.20 }, { 7004, 280.9050, -63.4489, 5.78 }, + { 7005, 280.3775, -47.9050, 6.49 }, { 7006, 277.4371, +77.5469, 5.64 }, { 7007, 280.0021, -6.2094, 5.84 }, { 7008, 279.9038, +5.2642, 6.38 }, + { 7009, 279.5271, +39.6681, 6.04 }, { 7010, 279.9650, +7.3583, 6.28 }, { 7011, 280.4650, -22.1667, 6.23 }, { 7012, 281.3621, -63.1286, 4.79 }, + { 7013, 279.0554, +65.4886, 6.06 }, { 7014, 280.4271, -13.4358, 6.42 }, { 7015, 281.2979, -60.9050, 6.04 }, { 7016, 280.0083, +30.8494, 6.36 }, + { 7017, 279.8879, +40.9350, 6.25 }, { 7018, 279.3896, +62.5267, 5.74 }, { 7019, 280.0508, +38.3672, 6.45 }, { 7020, 280.5683, -8.9475, 4.72 }, + { 7021, 280.9454, -37.6764, 5.13 }, { 7022, 281.3488, -55.1183, 6.22 }, { 7023, 280.7300, -18.7161, 6.35 }, { 7024, 280.6504, -6.9267, 6.15 }, + { 7025, 276.0383, +83.1753, 6.17 }, { 7026, 281.0321, -35.2814, 6.32 }, { 7027, 282.4312, -71.0053, 6.06 }, { 7028, 279.9700, +52.1961, 6.00 }, + { 7029, 281.0808, -34.3581, 4.87 }, { 7030, 280.4221, +31.6178, 6.41 }, { 7031, 281.2383, -38.3136, 5.43 }, { 7032, 280.8804, -7.7247, 4.90 }, + { 7033, 280.5338, +34.7467, 6.47 }, { 7034, 280.9642, -5.1814, 6.31 }, { 7035, 281.2067, -24.9889, 5.83 }, { 7036, 282.1575, -64.9222, 5.73 }, + { 7037, 281.7462, -49.9056, 6.54 }, { 7038, 281.3279, -20.9986, 6.36 }, { 7039, 281.4142, -25.0092, 3.17 }, { 7040, 281.2079, +2.0600, 5.02 }, + { 7041, 280.8196, +39.3003, 6.45 }, { 7042, 280.2346, +62.7497, 6.09 }, { 7043, 280.9004, +36.5567, 6.01 }, { 7044, 280.9650, +31.9267, 5.70 }, + { 7045, 281.5050, -18.3936, 6.42 }, { 7046, 281.5858, -21.6078, 5.37 }, { 7047, 281.1675, +23.5897, 6.31 }, { 7048, 281.3683, +5.4997, 5.83 }, + { 7049, 280.6579, +55.5394, 5.04 }, { 7050, 281.9358, -39.5939, 5.24 }, { 7051, 281.0850, +39.6700, 5.06 }, { 7052, 281.0846, +39.6711, 6.02 }, + { 7053, 281.0954, +39.6131, 5.14 }, { 7054, 281.0954, +39.6128, 5.37 }, { 7055, 281.6804, -9.8750, 5.71 }, { 7056, 281.1933, +37.6050, 4.36 }, + { 7057, 281.2008, +37.5944, 5.73 }, { 7058, 281.3988, +21.9850, 6.51 }, { 7059, 281.6187, +0.9617, 5.90 }, { 7060, 280.8708, +53.8719, 6.11 }, + { 7061, 281.4154, +20.5464, 4.19 }, { 7062, 282.2104, -42.3200, 5.49 }, { 7063, 281.7937, -3.2522, 4.22 }, { 7064, 281.5188, +26.6622, 4.83 }, + { 7065, 282.3642, -44.1897, 5.81 }, { 7066, 281.8708, -4.2950, 5.20 }, { 7067, 281.6725, +18.7058, 6.17 }, { 7068, 282.3958, -42.5661, 5.61 }, + { 7069, 281.7554, +18.1814, 4.36 }, { 7070, 282.3217, -33.2514, 6.62 }, { 7071, 281.2308, +54.8967, 6.23 }, { 7072, 282.1888, -17.3986, 6.47 }, + { 7073, 281.5542, +41.4417, 6.07 }, { 7074, 283.0542, -61.8125, 4.22 }, { 7075, 281.0758, +61.0481, 5.99 }, { 7076, 282.0113, +4.2414, 6.21 }, + { 7077, 282.3979, -18.8578, 6.75 }, { 7078, 282.4171, -19.6753, 5.24 }, { 7079, 282.0683, +23.5142, 6.15 }, { 7080, 281.7458, +46.3150, 6.52 }, + { 7081, 281.9896, +31.7569, 6.06 }, { 7082, 280.7925, +70.7928, 6.44 }, { 7083, 282.4208, -4.0872, 5.99 }, { 7084, 281.6796, +52.9881, 5.88 }, + { 7085, 282.4046, +0.8358, 6.25 }, { 7086, 282.2225, +19.3286, 5.88 }, { 7087, 283.1650, -51.8925, 5.17 }, { 7088, 282.7104, -21.8378, 6.61 }, + { 7089, 282.5833, -6.0925, 6.80 }, { 7090, 281.9167, +49.0750, 6.40 }, { 7091, 282.3100, +25.0464, 6.59 }, { 7092, 283.1129, -45.4047, 5.54 }, + { 7093, 283.3004, -50.0689, 6.31 }, { 7094, 282.7437, -8.2258, 5.83 }, { 7095, 283.2604, -47.6400, 6.19 }, { 7096, 282.0671, +48.7675, 6.12 }, + { 7097, 283.2483, -45.4142, 6.19 }, { 7098, 282.4333, +31.6292, 6.64 }, { 7099, 282.6900, +10.9764, 6.55 }, { 7100, 282.4413, +32.8128, 5.91 }, + { 7101, 282.8421, -2.6822, 6.10 }, { 7102, 282.4704, +32.5508, 5.25 }, { 7103, 283.1187, -25.3497, 6.29 }, { 7104, 283.1542, -28.6206, 6.13 }, + { 7105, 283.1737, -29.2658, 6.63 }, { 7106, 282.5200, +33.3628, 3.45 }, { 7107, 284.2375, -66.7664, 4.44 }, { 7108, 283.6346, -48.1214, 6.60 }, + { 7109, 283.0079, +13.9656, 6.14 }, { 7110, 283.2579, -8.4239, 6.34 }, { 7111, 284.2279, -61.1989, 6.48 }, { 7112, 282.8996, +28.7836, 6.18 }, + { 7113, 283.0683, +21.4253, 5.48 }, { 7114, 283.5004, -20.6403, 5.69 }, { 7115, 282.9021, +36.5386, 6.09 }, { 7116, 283.5425, -21.2550, 4.83 }, + { 7117, 281.4446, +74.0856, 5.27 }, { 7118, 283.0296, +41.3833, 6.28 }, { 7119, 283.6796, -14.3969, 5.10 }, { 7120, 283.7796, -21.3286, 4.99 }, + { 7121, 283.8163, -25.7033, 2.02 }, { 7122, 284.0704, -41.2894, 5.36 }, { 7123, 282.8958, +52.9750, 5.51 }, { 7124, 281.5925, +75.4339, 5.35 }, + { 7125, 282.8004, +59.3883, 4.66 }, { 7126, 283.8792, -15.6233, 5.79 }, { 7127, 284.6517, -59.7994, 5.14 }, { 7128, 284.0025, -22.8264, 5.93 }, + { 7129, 284.1687, -36.6567, 5.38 }, { 7130, 285.0146, -65.3467, 6.01 }, { 7131, 283.4317, +36.9717, 5.58 }, { 7132, 283.5550, +27.9094, 5.62 }, + { 7133, 283.6871, +22.6450, 4.59 }, { 7134, 284.6154, -51.0614, 4.87 }, { 7135, 283.8646, +6.6153, 5.57 }, { 7136, 284.3946, -38.1767, 6.31 }, + { 7137, 283.3067, +50.7083, 4.92 }, { 7138, 283.5596, +41.2256, 7.30 }, { 7139, 283.6258, +36.8989, 4.30 }, { 7140, 283.7188, +33.9686, 6.02 }, + { 7141, 284.0550, +4.2036, 4.62 }, { 7142, 284.0608, +4.2019, 4.98 }, { 7143, 284.0946, -0.2000, 6.22 }, { 7144, 284.1067, +2.4711, 6.15 }, + { 7145, 284.3354, -19.3436, 5.08 }, { 7146, 283.7175, +41.6028, 5.44 }, { 7147, 284.0163, +17.9950, 6.63 }, { 7148, 284.0258, +18.1053, 5.69 }, + { 7149, 284.2654, -4.1539, 4.83 }, { 7150, 284.4325, -20.8933, 3.51 }, { 7151, 284.5888, -30.9639, 6.12 }, { 7152, 284.6808, -36.8925, 4.87 }, + { 7153, 283.4429, +57.4869, 6.22 }, { 7154, 283.6963, +48.8597, 5.77 }, { 7155, 284.5854, -23.1233, 6.62 }, { 7156, 284.7962, -38.4653, 6.49 }, + { 7157, 283.8338, +43.9461, 4.04 }, { 7158, 284.3192, +2.5353, 5.57 }, { 7159, 284.6025, -21.4706, 6.14 }, { 7160, 281.4088, +79.9425, 6.39 }, + { 7161, 285.8737, -67.2447, 5.88 }, { 7162, 284.2567, +32.9014, 5.22 }, { 7163, 284.5992, +6.2403, 6.21 }, { 7164, 284.8617, -17.4331, 6.37 }, + { 7165, 284.5612, +17.3608, 5.38 }, { 7166, 284.8492, -11.1594, 5.53 }, { 7167, 284.6954, +13.9067, 5.89 }, { 7168, 285.1033, -23.0578, 6.36 }, + { 7169, 285.2633, -36.9392, 6.69 }, { 7170, 285.2679, -36.9381, 6.40 }, { 7171, 284.6879, +19.7942, 6.50 }, { 7172, 284.7738, +13.6225, 5.23 }, + { 7173, 284.8229, +10.1408, 6.75 }, { 7174, 284.5079, +38.2661, 5.89 }, { 7175, 284.1875, +57.8150, 5.66 }, { 7176, 284.9058, +15.0683, 4.02 }, + { 7177, 285.5363, -40.0900, 6.23 }, { 7178, 284.7358, +32.6894, 3.24 }, { 7179, 284.6942, +40.6792, 6.22 }, { 7180, 283.5996, +71.2972, 4.82 }, + { 7181, 284.9396, +26.2306, 5.27 }, { 7182, 285.4075, -21.3044, 6.24 }, { 7183, 284.9921, +22.8147, 6.29 }, { 7184, 284.3683, +58.2253, 6.46 }, + { 7185, 284.8012, +39.2178, 6.41 }, { 7186, 285.3896, -14.7175, 6.32 }, { 7187, 284.1067, +65.2581, 5.63 }, { 7188, 285.7788, -41.9047, 4.75 }, + { 7189, 0.0000, +0.0000, 0.00 }, { 7190, 285.9892, -50.9814, 5.93 }, { 7191, 284.3225, +62.3967, 6.45 }, { 7192, 285.0038, +32.1456, 4.93 }, + { 7193, 285.4200, -4.2611, 4.02 }, { 7194, 285.6529, -28.1197, 2.60 }, { 7195, 285.6154, -23.1531, 5.65 }, { 7196, 284.7483, +50.8094, 6.30 }, + { 7197, 285.8238, -37.7467, 5.74 }, { 7198, 285.2729, +19.3097, 6.39 }, { 7199, 283.3883, +75.7875, 6.22 }, { 7200, 285.3442, +20.8336, 6.69 }, + { 7201, 285.0792, +40.6842, 6.65 }, { 7202, 285.3225, +26.2914, 5.69 }, { 7203, 285.7658, -18.7547, 6.05 }, { 7204, 285.2300, +33.8022, 6.01 }, + { 7205, 285.7792, -18.8967, 6.37 }, { 7206, 285.3954, +25.0258, 6.72 }, { 7207, 285.4563, +22.2639, 6.40 }, { 7208, 285.5900, +8.3742, 6.30 }, + { 7209, 285.7271, -2.3011, 5.42 }, { 7210, 285.0571, +50.5336, 5.38 }, { 7211, 286.1046, -30.9531, 5.50 }, { 7212, 285.4513, +33.6214, 6.39 }, + { 7213, 286.5829, -51.6592, 5.16 }, { 7214, 285.8842, +1.8189, 5.83 }, { 7215, 285.3600, +46.9347, 5.01 }, { 7216, 285.7192, +19.6611, 6.09 }, + { 7217, 286.1708, -20.2583, 3.77 }, { 7218, 285.1808, +55.6583, 5.48 }, { 7219, 286.0446, +3.3306, 6.73 }, { 7220, 286.1008, -4.3150, 6.90 }, + { 7221, 287.4696, -67.5753, 5.33 }, { 7222, 285.9271, +21.2678, 6.52 }, { 7223, 286.7317, -47.7008, 5.97 }, { 7224, 284.7192, +69.5311, 6.52 }, + { 7225, 286.2400, -3.9686, 5.42 }, { 7226, 286.6046, -36.9367, 4.93 }, { 7227, 286.6046, -36.9367, 4.99 }, { 7228, 317.1925, -87.0436, 5.47 }, + { 7229, 285.5292, +52.2611, 6.31 }, { 7230, 286.4217, -14.3397, 5.97 }, { 7231, 286.3275, -0.4872, 6.53 }, { 7232, 286.7188, -36.1897, 6.16 }, + { 7233, 287.2171, -54.2797, 6.49 }, { 7234, 286.7350, -26.3294, 3.32 }, { 7235, 286.3525, +13.8633, 2.99 }, { 7236, 286.5621, -3.1175, 3.44 }, + { 7237, 286.2412, +31.7444, 5.56 }, { 7238, 286.2429, +30.7333, 6.06 }, { 7239, 286.7179, -15.7711, 6.03 }, { 7240, 286.8788, -27.3631, 6.04 }, + { 7241, 286.7854, -17.2622, 6.29 }, { 7242, 287.0871, -39.5033, 4.59 }, { 7243, 286.5925, +8.2300, 6.09 }, { 7244, 286.4463, +29.9217, 6.31 }, + { 7245, 286.7879, +0.6417, 6.56 }, { 7246, 287.0608, -23.3431, 6.30 }, { 7247, 284.4883, +77.0508, 6.54 }, { 7248, 286.7442, +11.0714, 5.09 }, + { 7249, 287.0696, -18.7100, 5.54 }, { 7250, 286.6600, +24.2508, 5.77 }, { 7251, 286.2300, +53.3967, 5.38 }, { 7252, 286.2912, +49.9233, 6.43 }, + { 7253, 286.6571, +28.6286, 5.55 }, { 7254, 287.3679, -36.0956, 4.11 }, { 7255, 287.4154, -38.1719, 6.46 }, { 7256, 287.4017, -35.8353, 6.56 }, + { 7257, 287.4908, -40.1075, 5.88 }, { 7258, 286.5708, +41.4139, 6.49 }, { 7259, 287.5071, -38.6592, 4.11 }, { 7260, 286.9887, +16.8533, 6.07 }, + { 7261, 286.8567, +32.5017, 5.23 }, { 7262, 286.8254, +36.1003, 5.28 }, { 7263, 287.0150, +21.6989, 6.23 }, { 7264, 287.4408, -20.9764, 2.89 }, + { 7265, 287.4504, -18.1964, 6.13 }, { 7266, 287.2496, +6.0733, 5.22 }, { 7267, 287.1675, +16.8514, 6.48 }, { 7268, 287.7575, -38.9950, 6.36 }, + { 7269, 287.4650, +0.4281, 6.34 }, { 7270, 287.8288, -28.4978, 6.30 }, { 7271, 288.1921, -49.5136, 6.13 }, { 7272, 287.2683, +34.6006, 6.74 }, + { 7273, 288.0408, -36.4172, 6.57 }, { 7274, 289.1187, -68.8094, 6.27 }, { 7275, 287.1075, +52.4256, 5.81 }, { 7276, 288.1167, -20.3419, 6.41 }, + { 7277, 288.3071, -24.0933, 5.80 }, { 7278, 289.3000, -65.3386, 5.53 }, { 7279, 288.1696, -6.0606, 5.34 }, { 7280, 287.8788, +26.7358, 6.36 }, + { 7281, 288.6654, -44.8067, 5.92 }, { 7282, 288.3146, -11.7175, 5.51 }, { 7283, 287.9417, +31.2833, 5.98 }, { 7284, 287.8463, +40.4292, 6.18 }, + { 7285, 288.1433, +16.8464, 6.73 }, { 7286, 288.1529, +21.5544, 5.93 }, { 7287, 288.4279, +2.2936, 5.15 }, { 7288, 288.4337, +5.5158, 6.49 }, + { 7289, 289.0904, -44.5336, 5.40 }, { 7290, 287.4408, +65.9786, 6.25 }, { 7291, 288.8883, -23.8208, 6.25 }, { 7292, 288.8850, -24.7433, 4.85 }, + { 7293, 288.0192, +49.8542, 6.75 }, { 7294, 288.0208, +49.8561, 6.57 }, { 7295, 287.9187, +56.8592, 5.12 }, { 7296, 289.1367, -32.4783, 6.25 }, + { 7297, 289.5392, -52.6133, 6.38 }, { 7298, 288.4396, +39.1461, 4.39 }, { 7299, 288.7608, +20.2033, 6.00 }, { 7300, 288.8338, +15.0836, 5.57 }, + { 7301, 288.8225, +21.2322, 5.64 }, { 7302, 288.8533, +30.5264, 5.85 }, { 7303, 289.1292, +4.8347, 5.59 }, { 7304, 289.4088, -17.0469, 4.96 }, + { 7305, 288.9875, +27.4556, 6.54 }, { 7306, 289.0542, +21.3903, 4.77 }, { 7307, 289.1117, +14.5447, 5.63 }, { 7308, 288.9975, +27.9269, 6.16 }, + { 7309, 288.4800, +57.7050, 4.99 }, { 7310, 288.1388, +67.6617, 3.07 }, { 7311, 288.8304, +50.0708, 6.27 }, { 7312, 287.2908, +76.5606, 5.13 }, + { 7313, 289.4508, +2.0317, 6.19 }, { 7314, 289.0921, +38.1336, 4.36 }, { 7315, 289.4542, +11.5953, 5.28 }, { 7316, 289.9167, -34.5786, 5.59 }, + { 7317, 289.7504, -14.4636, 6.06 }, { 7318, 289.4317, +23.0256, 5.43 }, { 7319, 289.6354, +1.0853, 5.10 }, { 7320, 291.0225, -67.6289, 6.34 }, + { 7321, 289.7121, +0.3392, 6.41 }, { 7322, 289.2142, +46.9992, 6.00 }, { 7323, 290.1092, -30.1822, 6.58 }, { 7324, 289.5033, +31.0222, 6.68 }, + { 7325, 289.7196, +9.6181, 6.32 }, { 7326, 289.7021, +19.6106, 6.58 }, { 7327, 290.1588, -21.5975, 5.58 }, { 7328, 289.2758, +53.3686, 3.77 }, + { 7329, 290.7129, -53.5764, 5.05 }, { 7330, 290.3746, -33.0161, 6.48 }, { 7331, 289.9137, +12.3747, 5.53 }, { 7332, 289.9708, +11.5350, 6.02 }, + { 7333, 290.1371, -4.5842, 5.01 }, { 7334, 290.5400, -41.9839, 6.34 }, { 7335, 289.7658, +33.3889, 6.60 }, { 7336, 290.1488, +0.8922, 5.49 }, + { 7337, 290.6596, -43.5411, 4.01 }, { 7338, 289.7550, +37.4453, 6.22 }, { 7339, 290.4046, -18.7658, 6.26 }, { 7340, 290.4183, -16.1528, 3.93 }, + { 7341, 289.6571, +49.5697, 6.31 }, { 7342, 290.4317, -14.0450, 4.61 }, { 7343, 290.8050, -43.2003, 4.29 }, { 7344, 290.4621, -17.6917, 5.87 }, + { 7345, 289.9121, +37.3306, 6.31 }, { 7346, 290.1379, +35.1861, 6.31 }, { 7347, 290.5863, -7.7989, 6.31 }, { 7348, 290.9717, -39.3839, 3.97 }, + { 7349, 290.5896, +0.2525, 5.83 }, { 7350, 291.0892, -42.2769, 6.17 }, { 7351, 289.9021, +54.3761, 6.26 }, { 7352, 288.8875, +73.3556, 4.45 }, + { 7353, 290.7692, -6.5997, 6.32 }, { 7354, 290.7017, +9.9131, 6.35 }, { 7355, 291.1254, -26.1344, 6.04 }, { 7356, 290.0671, +57.6453, 5.91 }, + { 7357, 290.7842, +14.9211, 6.64 }, { 7358, 290.7121, +26.2625, 5.18 }, { 7359, 290.6392, +33.5181, 6.06 }, { 7360, 291.2671, -28.6908, 5.93 }, + { 7361, 289.9421, +64.3908, 6.52 }, { 7362, 291.3188, -23.4914, 5.03 }, { 7363, 291.3737, -22.0378, 5.43 }, { 7364, 290.9454, +20.2644, 6.40 }, + { 7365, 290.3558, +57.7669, 6.43 }, { 7366, 291.2567, -3.1158, 6.52 }, { 7367, 291.3400, -12.1031, 5.69 }, { 7368, 290.8917, +33.2222, 6.37 }, + { 7369, 291.0921, +16.9378, 6.25 }, { 7370, 291.9504, -53.6747, 5.69 }, { 7371, 290.1671, +65.7147, 4.59 }, { 7372, 291.0317, +29.6214, 4.97 }, + { 7373, 291.2425, +11.9444, 5.16 }, { 7374, 291.0933, +28.0878, 6.53 }, { 7375, 291.5800, -20.2233, 5.59 }, { 7376, 291.0254, +36.4519, 6.36 }, + { 7377, 291.3746, +3.1147, 3.36 }, { 7378, 291.5462, -14.9469, 5.72 }, { 7379, 291.6025, -13.4489, 6.70 }, { 7380, 291.7354, -28.2567, 5.67 }, + { 7381, 290.8492, +50.2714, 6.51 }, { 7382, 290.9854, +43.3881, 5.84 }, { 7383, 292.7954, -67.5661, 5.96 }, { 7384, 291.3433, +20.2714, 6.31 }, + { 7385, 291.3692, +19.7986, 5.16 }, { 7386, 291.3575, +24.9128, 6.19 }, { 7387, 291.6296, +0.3386, 4.66 }, { 7388, 292.4692, -54.5586, 6.13 }, + { 7389, 291.6004, +13.0239, 5.74 }, { 7390, 291.5550, +20.0978, 5.63 }, { 7391, 291.6196, +19.8914, 5.81 }, { 7392, 292.3496, -42.5542, 5.71 }, + { 7393, 292.6438, -54.8900, 6.30 }, { 7394, 259.2367, +89.0378, 6.38 }, { 7395, 291.5379, +36.3178, 5.15 }, { 7396, 291.8913, +14.2825, 6.32 }, + { 7397, 292.0867, +2.9303, 5.85 }, { 7398, 292.4675, -25.0144, 5.52 }, { 7399, 292.5612, -31.9078, 6.60 }, { 7400, 292.2542, +1.9503, 5.80 }, + { 7401, 291.4446, +58.0272, 6.60 }, { 7402, 292.3396, -6.9561, 6.61 }, { 7403, 291.9021, +37.9411, 6.34 }, { 7404, 292.3250, +0.2461, 6.25 }, + { 7405, 292.1762, +24.6650, 4.44 }, { 7406, 292.2375, +24.7686, 5.81 }, { 7407, 292.3421, +14.5958, 5.56 }, { 7408, 291.8579, +52.3206, 5.75 }, + { 7409, 292.3371, +20.2797, 6.33 }, { 7410, 292.7250, -20.6878, 6.13 }, { 7411, 293.2242, -52.8142, 5.75 }, { 7412, 292.5437, +2.9042, 6.09 }, + { 7413, 291.6104, +62.5572, 6.38 }, { 7414, 292.6658, -1.2111, 5.03 }, { 7415, 292.6379, +3.4444, 6.05 }, { 7416, 293.3400, -44.7281, 5.61 }, + { 7417, 292.6804, +27.9597, 3.08 }, { 7418, 292.6888, +27.9653, 5.11 }, { 7419, 292.6954, +36.2286, 6.25 }, { 7420, 292.4262, +51.7297, 3.79 }, + { 7421, 292.8408, +26.6172, 5.87 }, { 7422, 293.5354, -39.9653, 5.89 }, { 7423, 290.4175, +79.6028, 6.05 }, { 7424, 293.8042, -47.9008, 4.90 }, + { 7425, 288.7825, +83.4628, 6.53 }, { 7426, 292.9429, +34.4531, 4.74 }, { 7427, 292.8304, +50.3067, 5.53 }, { 7428, 292.8067, +55.7319, 6.37 }, + { 7429, 293.5225, +7.3789, 4.45 }, { 7430, 293.7804, -9.4397, 5.12 }, { 7431, 294.0071, -23.2808, 5.65 }, { 7432, 293.8742, -6.5397, 6.34 }, + { 7433, 293.8900, -11.7472, 6.27 }, { 7434, 294.6079, -56.0167, 6.18 }, { 7435, 294.9671, -65.3144, 6.39 }, { 7436, 293.4017, +38.7622, 6.61 }, + { 7437, 293.6454, +19.7733, 5.00 }, { 7438, 293.8550, +2.9133, 6.38 }, { 7439, 294.1087, -17.1472, 6.11 }, { 7440, 294.1767, -23.1164, 4.60 }, + { 7441, 293.7121, +29.4631, 5.38 }, { 7442, 293.4233, +49.2625, 5.96 }, { 7443, 294.2638, -17.7689, 5.64 }, { 7444, 293.6717, +42.4128, 5.35 }, + { 7445, 294.0333, +11.1500, 6.68 }, { 7446, 294.2229, -6.9725, 4.95 }, { 7447, 294.1804, -0.7136, 4.36 }, { 7448, 293.2921, +60.1586, 6.29 }, + { 7449, 294.0658, +14.3917, 6.38 }, { 7450, 292.7508, +70.9894, 6.07 }, { 7451, 293.5825, +51.2367, 5.73 }, { 7452, 294.0346, +22.5858, 6.32 }, + { 7453, 293.6662, +48.1647, 6.67 }, { 7454, 294.3933, -13.6983, 5.47 }, { 7455, 295.4063, -64.1458, 6.09 }, { 7456, 294.2188, +11.2733, 5.98 }, + { 7457, 293.9513, +36.9444, 6.05 }, { 7458, 294.1571, +20.3328, 7.14 }, { 7459, 295.0763, -53.5825, 6.26 }, { 7460, 294.4471, -3.3525, 5.46 }, + { 7461, 294.9250, -44.7219, 6.25 }, { 7462, 293.0900, +69.6611, 4.68 }, { 7463, 294.3225, +16.4628, 5.66 }, { 7464, 294.9821, -38.5667, 6.61 }, + { 7465, 293.9829, +50.2386, 6.52 }, { 7466, 294.2892, +29.3336, 6.43 }, { 7467, 294.2358, +38.3839, 6.50 }, { 7468, 294.1579, +44.6950, 5.17 }, + { 7469, 294.1104, +50.2211, 4.48 }, { 7470, 294.9558, -22.5722, 6.34 }, { 7471, 294.7042, +3.3817, 6.35 }, { 7472, 294.5729, +20.7828, 6.48 }, + { 7473, 295.0296, -22.5714, 5.97 }, { 7474, 294.7983, +5.3978, 5.17 }, { 7475, 294.8558, +16.5714, 6.38 }, { 7476, 295.1808, -15.7067, 6.20 }, + { 7477, 294.4862, +49.2844, 6.47 }, { 7478, 294.8442, +30.1533, 4.69 }, { 7479, 295.0242, +18.0139, 4.37 }, { 7480, 295.1804, +0.6211, 5.67 }, + { 7481, 294.9375, +33.9792, 6.10 }, { 7482, 295.1179, +20.4767, 6.50 }, { 7483, 294.8604, +42.8183, 5.40 }, { 7484, 294.6717, +54.9739, 5.82 }, + { 7485, 295.1654, +23.7175, 6.64 }, { 7486, 295.2729, +13.8156, 6.01 }, { 7487, 294.8933, +45.9581, 6.20 }, { 7488, 295.2621, +17.4761, 4.37 }, + { 7489, 295.6296, -15.8761, 5.06 }, { 7490, 295.3121, +22.4528, 6.36 }, { 7491, 295.9067, -36.4611, 6.16 }, { 7492, 295.1717, +43.0778, 6.16 }, + { 7493, 295.5533, +12.1933, 6.34 }, { 7494, 299.0063, -80.6503, 6.39 }, { 7495, 295.2092, +45.5250, 5.06 }, { 7496, 295.8896, -14.5300, 5.49 }, + { 7497, 295.6417, +11.8267, 5.27 }, { 7498, 297.3554, -71.4967, 5.41 }, { 7499, 295.4896, +40.2539, 6.23 }, { 7500, 295.0542, +60.5072, 6.51 }, + { 7501, 295.7046, +29.3317, 6.49 }, { 7502, 295.6858, +32.4267, 5.94 }, { 7503, 295.4538, +50.5253, 5.96 }, { 7504, 295.4667, +50.5175, 6.20 }, + { 7505, 295.7896, +30.6786, 6.05 }, { 7506, 295.9287, +25.7719, 5.49 }, { 7507, 296.5050, -30.0914, 5.52 }, { 7508, 295.9829, +27.1356, 6.28 }, + { 7509, 295.5171, +55.4633, 6.48 }, { 7510, 297.0050, -55.6375, 5.35 }, { 7511, 296.1421, +13.3028, 6.26 }, { 7512, 295.9642, +34.1625, 6.05 }, + { 7513, 297.4721, -65.1872, 6.45 }, { 7514, 295.9375, +41.7731, 5.84 }, { 7515, 296.5904, -18.2389, 4.86 }, { 7516, 296.4675, -1.1167, 6.48 }, + { 7517, 296.0692, +37.3544, 4.89 }, { 7518, 296.2029, +29.2647, 6.82 }, { 7519, 296.4162, +7.6133, 5.91 }, { 7520, 296.1592, +34.4139, 6.57 }, + { 7521, 297.2296, -51.1119, 6.25 }, { 7522, 295.8108, +58.0164, 6.22 }, { 7523, 296.2042, +40.7167, 6.34 }, { 7524, 297.7554, -64.3950, 6.05 }, + { 7525, 296.5650, +10.6133, 2.72 }, { 7526, 295.9150, +57.0425, 6.27 }, { 7527, 297.5904, -60.9386, 6.21 }, { 7528, 296.2437, +45.1308, 2.87 }, + { 7529, 296.4150, +36.0911, 6.43 }, { 7530, 296.4642, +35.0128, 6.09 }, { 7531, 297.6867, -58.8069, 5.42 }, { 7532, 297.0125, -12.2967, 6.11 }, + { 7533, 296.6646, +25.1339, 6.62 }, { 7534, 296.6067, +33.7278, 4.99 }, { 7535, 296.6458, +32.8886, 6.18 }, { 7536, 296.8471, +18.5342, 3.82 }, + { 7537, 297.5575, -46.4428, 5.94 }, { 7538, 297.2983, -27.2111, 6.05 }, { 7539, 0.0000, +0.0000, 0.00 }, { 7540, 296.9525, +25.3839, 5.95 }, + { 7541, 297.2592, -9.1292, 6.04 }, { 7542, 297.1267, +10.6942, 6.44 }, { 7543, 296.8658, +38.4075, 5.77 }, { 7544, 297.1754, +11.8158, 5.72 }, + { 7545, 296.0771, +69.3369, 5.92 }, { 7546, 297.2446, +19.1422, 5.00 }, { 7547, 296.8617, +47.9078, 6.12 }, { 7548, 298.1567, -53.0289, 5.74 }, + { 7549, 298.1625, -53.0233, 6.50 }, { 7550, 297.1829, +35.3114, 6.53 }, { 7551, 297.2108, +33.4372, 6.44 }, { 7552, 297.9608, -38.1256, 5.33 }, + { 7553, 297.6950, -9.2364, 5.39 }, { 7554, 297.5729, +7.9025, 6.51 }, { 7555, 297.3646, +38.7100, 6.11 }, { 7556, 297.4775, +28.4406, 6.38 }, + { 7557, 297.6958, +8.8683, 0.77 }, { 7558, 298.6683, -60.8292, 6.24 }, { 7559, 297.7962, -1.5392, 6.13 }, { 7560, 297.7567, +10.4156, 5.11 }, + { 7561, 298.0500, -18.9550, 5.92 }, { 7562, 297.8238, +9.6303, 6.25 }, { 7563, 296.6862, +68.4383, 6.34 }, { 7564, 297.6413, +32.9142, 4.23 }, + { 7565, 297.7671, +22.6100, 4.95 }, { 7566, 297.6417, +38.7225, 5.12 }, { 7567, 297.6554, +40.5997, 5.69 }, { 7568, 297.6958, +37.8264, 6.06 }, + { 7569, 298.0146, +11.6289, 6.13 }, { 7570, 298.1183, +1.0056, 3.90 }, { 7571, 298.2767, -13.3969, 6.48 }, { 7572, 298.0650, +10.3514, 6.54 }, + { 7573, 298.0067, +24.9922, 5.57 }, { 7574, 298.0908, +18.6719, 6.23 }, { 7575, 298.3279, -2.8856, 5.65 }, { 7576, 297.6571, +52.9881, 5.03 }, + { 7577, 297.8308, +47.3772, 6.20 }, { 7578, 298.5738, -22.0589, 6.18 }, { 7579, 299.6721, -68.8361, 5.75 }, { 7580, 298.3442, +4.4006, 6.53 }, + { 7581, 298.8154, -40.1317, 4.13 }, { 7582, 297.0433, +70.2678, 3.83 }, { 7583, 298.0679, +36.4322, 6.10 }, { 7584, 298.5342, -7.4258, 5.79 }, + { 7585, 298.7713, -32.9536, 6.46 }, { 7586, 299.2404, -56.0744, 6.53 }, { 7587, 299.2758, -57.0986, 5.26 }, { 7588, 299.7208, -67.2378, 6.39 }, + { 7589, 297.9962, +47.0275, 5.62 }, { 7590, 300.1479, -71.0894, 3.96 }, { 7591, 298.0300, +47.9319, 5.91 }, { 7592, 298.3654, +24.0797, 4.58 }, + { 7593, 298.6567, -7.7728, 5.71 }, { 7594, 298.6588, -7.7628, 6.49 }, { 7595, 298.5621, +8.4614, 4.71 }, { 7596, 298.6867, +0.2736, 5.61 }, + { 7597, 298.9600, -25.7006, 4.70 }, { 7598, 298.6679, +7.1403, 6.15 }, { 7599, 298.8317, -5.2658, 6.51 }, { 7600, 298.2550, +47.8075, 6.29 }, + { 7601, 298.6296, +24.3194, 5.52 }, { 7602, 298.8283, +6.4067, 3.71 }, { 7603, 300.0958, -65.0506, 5.76 }, { 7604, 299.2367, -26.8300, 4.52 }, + { 7605, 299.4221, -37.9417, 6.55 }, { 7606, 298.7013, +36.9961, 5.76 }, { 7607, 298.7771, +30.1953, 6.57 }, { 7608, 298.3225, +57.5236, 5.14 }, + { 7609, 299.0054, +16.6347, 5.36 }, { 7610, 299.0596, +11.4239, 5.28 }, { 7611, 298.3975, +59.7089, 6.06 }, { 7612, 300.4683, -65.0558, 5.31 }, + { 7613, 298.9654, +38.4867, 4.94 }, { 7614, 299.4875, -14.5086, 5.02 }, { 7615, 299.0767, +35.0833, 3.89 }, { 7616, 299.2508, +20.9981, 6.48 }, + { 7617, 299.7350, -29.4619, 6.28 }, { 7618, 299.7383, -25.8044, 4.83 }, { 7619, 298.9075, +52.4389, 4.92 }, { 7620, 299.1842, +36.2508, 6.02 }, + { 7621, 300.1054, -48.6489, 6.17 }, { 7622, 299.4392, +16.7892, 5.53 }, { 7623, 299.9342, -34.7236, 4.37 }, { 7624, 299.9638, -33.3022, 5.30 }, + { 7625, 300.4362, -58.6239, 5.13 }, { 7626, 298.8421, +58.2503, 6.09 }, { 7627, 300.1104, -42.9567, 6.14 }, { 7628, 299.3079, +40.3681, 5.45 }, + { 7629, 300.0663, -36.2978, 5.95 }, { 7630, 300.2013, -44.8869, 5.81 }, { 7631, 300.0846, -32.2961, 5.66 }, { 7632, 299.1879, +50.9025, 6.43 }, + { 7633, 298.9808, +58.8461, 4.96 }, { 7634, 299.0792, +56.6869, 6.12 }, { 7635, 299.6892, +19.4922, 3.47 }, { 7636, 299.8446, +1.3778, 6.17 }, + { 7637, 299.9475, -8.0417, 5.88 }, { 7638, 299.4842, +42.2608, 6.43 }, { 7639, 300.3600, -39.1858, 6.29 }, { 7640, 299.6583, +30.9836, 5.49 }, + { 7641, 299.7937, +23.1014, 5.67 }, { 7642, 299.6433, +38.1056, 6.32 }, { 7643, 300.3496, -21.2628, 6.01 }, { 7644, 301.3867, -66.6792, 6.07 }, + { 7645, 300.0138, +17.5167, 5.37 }, { 7646, 299.8354, +45.7722, 5.92 }, { 7647, 299.9800, +37.0428, 5.19 }, { 7648, 300.2454, +8.5581, 5.91 }, + { 7649, 300.4942, -12.3631, 5.71 }, { 7650, 300.6646, -26.2903, 4.58 }, { 7651, 299.8142, +52.0558, 6.15 }, { 7652, 300.8896, -36.0592, 4.77 }, + { 7653, 300.2754, +27.7536, 4.64 }, { 7654, 299.6196, +63.5342, 5.96 }, { 7655, 300.3138, +37.0989, 6.20 }, { 7656, 300.4362, +24.8003, 5.88 }, + { 7657, 300.5058, +24.9381, 5.22 }, { 7658, 300.9346, -21.4044, 6.45 }, { 7659, 301.0817, -31.9436, 4.99 }, { 7660, 300.3400, +50.1047, 5.05 }, + { 7661, 301.0050, -6.5303, 6.72 }, { 7662, 300.8183, +18.5006, 5.96 }, { 7663, 302.0854, -65.6453, 6.45 }, { 7664, 300.8750, +16.0314, 5.67 }, + { 7665, 302.1817, -65.8181, 3.56 }, { 7666, 299.6746, +70.3669, 6.33 }, { 7667, 301.0967, +0.7094, 5.68 }, { 7668, 301.3838, -33.0000, 6.53 }, + { 7669, 301.0346, +7.2781, 5.52 }, { 7670, 300.9058, +29.8967, 5.71 }, { 7671, 301.2725, -10.4006, 6.34 }, { 7672, 301.0258, +17.0700, 5.80 }, + { 7673, 301.8467, -51.1192, 4.94 }, { 7674, 301.8963, -54.9836, 6.26 }, { 7675, 301.3600, -11.3347, 6.55 }, { 7676, 300.3687, +64.8211, 5.27 }, + { 7677, 301.2442, +23.2103, 6.45 }, { 7678, 301.1504, +32.2186, 5.64 }, { 7679, 301.2896, +19.9911, 5.10 }, { 7680, 301.3604, +15.5003, 6.34 }, + { 7681, 301.5508, -3.9217, 6.47 }, { 7682, 300.5846, +64.6344, 6.57 }, { 7683, 301.2908, +38.4783, 6.19 }, { 7684, 301.1200, +48.2297, 6.16 }, + { 7685, 300.7046, +67.8736, 4.51 }, { 7686, 299.9025, +76.4814, 6.20 }, { 7687, 301.2779, +51.8394, 6.14 }, { 7688, 301.7225, +23.6144, 5.07 }, + { 7689, 301.5908, +35.9725, 5.36 }, { 7690, 302.0075, +0.6783, 5.99 }, { 7691, 302.7800, -56.4761, 6.37 }, { 7692, 301.3396, +56.3414, 6.21 }, + { 7693, 301.9596, +9.3997, 6.43 }, { 7694, 302.1304, -9.9372, 6.18 }, { 7695, 301.1858, +63.8906, 6.26 }, { 7696, 302.0271, +16.6642, 6.42 }, + { 7697, 301.5575, +53.1658, 5.85 }, { 7698, 306.2267, -82.6894, 6.17 }, { 7699, 301.9225, +34.4231, 6.11 }, { 7700, 302.1596, +10.7258, 6.31 }, + { 7701, 301.3867, +61.9956, 5.39 }, { 7702, 301.7979, +50.2292, 6.54 }, { 7703, 302.7996, -35.8989, 5.32 }, { 7704, 301.2221, +68.0272, 6.28 }, + { 7705, 302.4858, +20.9153, 6.48 }, { 7706, 303.0996, -41.2194, 6.22 }, { 7707, 303.6121, -62.5842, 6.09 }, { 7708, 302.3567, +36.8397, 4.93 }, + { 7709, 302.7921, -7.1578, 6.49 }, { 7710, 302.8263, +0.8214, 3.23 }, { 7711, 302.6396, +26.9042, 5.52 }, { 7712, 302.9912, -11.6075, 6.34 }, + { 7713, 302.7646, +21.1347, 6.22 }, { 7714, 303.5792, -51.5544, 5.65 }, { 7715, 303.1079, -11.3825, 5.85 }, { 7716, 302.8379, +21.8756, 6.26 }, + { 7717, 303.1467, +0.8675, 6.27 }, { 7718, 302.9500, +26.8089, 5.49 }, { 7719, 303.0029, +26.4789, 5.92 }, { 7720, 303.3079, -0.9906, 5.47 }, + { 7721, 303.0158, +47.7369, 6.92 }, { 7722, 303.8225, -26.9672, 5.73 }, { 7723, 303.4192, +24.2389, 6.56 }, { 7724, 303.5692, +15.1975, 4.95 }, + { 7725, 303.9608, -29.9947, 6.30 }, { 7726, 303.1325, +51.4636, 6.01 }, { 7727, 302.8954, +62.0786, 5.75 }, { 7728, 304.0988, -35.5456, 6.39 }, + { 7729, 304.1104, -34.8022, 6.53 }, { 7730, 303.3250, +46.8158, 4.83 }, { 7731, 303.5604, +28.6947, 5.18 }, { 7732, 304.7625, -62.7689, 6.27 }, + { 7733, 303.4283, +43.3792, 6.14 }, { 7734, 303.5208, +36.6053, 6.45 }, { 7735, 303.4079, +46.7414, 3.79 }, { 7736, 303.6333, +36.8064, 4.97 }, + { 7737, 303.5900, +42.1036, 6.71 }, { 7738, 304.0950, -11.6631, 6.32 }, { 7739, 303.8163, +25.5919, 4.78 }, { 7740, 303.3496, +56.5678, 4.30 }, + { 7741, 303.8758, +23.5086, 5.15 }, { 7742, 303.3654, +60.6406, 5.79 }, { 7743, 303.8488, +33.7294, 5.66 }, { 7744, 303.9421, +27.8142, 4.52 }, + { 7745, 304.7333, -46.2892, 6.31 }, { 7746, 304.0821, +21.5986, 6.13 }, { 7747, 304.4121, -11.4917, 4.24 }, { 7748, 304.5058, -20.1900, 5.87 }, + { 7749, 304.8246, -46.4197, 6.13 }, { 7750, 302.2221, +77.7114, 4.39 }, { 7751, 303.8679, +47.7144, 3.98 }, { 7752, 304.0142, +38.8978, 6.27 }, + { 7753, 304.1963, +24.6711, 5.32 }, { 7754, 304.5138, -11.4553, 3.57 }, { 7755, 303.9308, +50.2328, 6.31 }, { 7756, 304.0025, +45.5794, 5.91 }, + { 7757, 304.1175, +37.0564, 6.48 }, { 7758, 305.1346, -54.9492, 6.27 }, { 7759, 304.2304, +40.3650, 5.24 }, { 7760, 304.3813, +29.1481, 6.22 }, + { 7761, 304.8483, -18.8814, 5.28 }, { 7762, 304.3712, +42.7219, 6.29 }, { 7763, 304.4467, +38.0331, 4.81 }, { 7764, 305.1171, -28.8028, 6.30 }, + { 7765, 305.2163, -34.3264, 6.46 }, { 7766, 305.4208, -48.0006, 6.27 }, { 7767, 304.5292, +40.7322, 5.84 }, { 7768, 304.9304, -0.9214, 6.06 }, + { 7769, 304.6192, +37.0000, 5.58 }, { 7770, 304.6629, +34.9828, 5.17 }, { 7771, 304.8717, +13.2169, 6.21 }, { 7772, 305.1087, -5.6383, 6.63 }, + { 7773, 305.1658, -11.2408, 4.76 }, { 7774, 305.0008, +13.5481, 5.95 }, { 7775, 305.1942, -13.2150, 6.10 }, { 7776, 305.2529, -13.2186, 3.08 }, + { 7777, 304.7067, +46.3228, 6.45 }, { 7778, 305.0854, +14.5692, 6.13 }, { 7779, 305.6146, -41.9503, 5.59 }, { 7780, 305.0892, +17.7931, 5.80 }, + { 7781, 304.6033, +55.3972, 5.76 }, { 7782, 304.9513, +37.1325, 6.57 }, { 7783, 304.3804, +66.8539, 5.93 }, { 7784, 305.0633, +39.4033, 6.23 }, + { 7785, 308.3229, -79.0350, 5.77 }, { 7786, 304.9837, +46.8375, 6.50 }, { 7787, 305.9717, -41.5772, 5.64 }, { 7788, 305.7533, -8.3453, 6.30 }, + { 7789, 305.5142, +24.4461, 5.54 }, { 7790, 306.4121, -55.2650, 1.94 }, { 7791, 305.1267, +53.5961, 6.18 }, { 7792, 304.9029, +62.2575, 5.72 }, + { 7793, 305.7179, +14.5514, 6.17 }, { 7794, 305.7946, +5.3431, 5.31 }, { 7795, 305.5125, +41.1314, 6.39 }, { 7796, 305.5571, +40.2567, 2.20 }, + { 7797, 305.6558, +31.2650, 6.09 }, { 7798, 305.5225, +45.7950, 5.58 }, { 7799, 306.4496, -39.2036, 6.09 }, { 7800, 305.6888, +41.0261, 5.93 }, + { 7801, 306.3617, -27.3367, 5.85 }, { 7802, 305.7312, +42.9833, 6.20 }, { 7803, 306.1563, +1.0686, 6.15 }, { 7804, 305.0250, +68.8803, 5.55 }, + { 7805, 305.2975, +63.9803, 5.69 }, { 7806, 305.9654, +32.1900, 4.43 }, { 7807, 305.9350, +37.4764, 5.90 }, { 7808, 306.7208, -36.5969, 6.25 }, + { 7809, 306.4271, -1.1997, 6.11 }, { 7810, 306.4333, +10.0564, 6.33 }, { 7811, 306.4187, +21.4097, 5.66 }, { 7812, 309.5775, -80.7111, 5.91 }, + { 7813, 306.5050, +19.8650, 6.41 }, { 7814, 306.8300, -17.7883, 5.25 }, { 7815, 306.1350, +53.5519, 6.51 }, { 7816, 306.5967, +17.3156, 6.22 }, + { 7817, 307.1946, -34.4042, 6.10 }, { 7818, 306.2713, +59.6000, 6.44 }, { 7819, 307.1817, -14.2583, 6.41 }, { 7820, 307.0313, +8.4375, 6.25 }, + { 7821, 307.1037, -2.6422, 6.13 }, { 7822, 307.2150, -16.1864, 4.78 }, { 7823, 306.7821, +34.3289, 6.39 }, { 7824, 307.0700, +2.9369, 6.21 }, + { 7825, 307.3804, -21.6083, 6.16 }, { 7826, 306.8929, +38.4403, 5.62 }, { 7827, 306.5979, +56.6389, 6.36 }, { 7828, 306.7596, +49.3833, 5.69 }, + { 7829, 307.4688, -17.4133, 6.74 }, { 7830, 307.4746, -17.4167, 5.94 }, { 7831, 307.4125, -1.1144, 4.91 }, { 7832, 307.7367, -28.8875, 6.39 }, + { 7833, 307.3379, +20.0878, 6.55 }, { 7834, 307.3488, +30.3686, 4.01 }, { 7835, 307.3350, +36.4547, 5.88 }, { 7836, 307.5750, +10.8958, 6.08 }, + { 7837, 307.7679, -14.9436, 6.12 }, { 7838, 308.9654, -68.3889, 6.11 }, { 7839, 307.7421, +20.6058, 6.18 }, { 7840, 307.8042, +11.2606, 7.11 }, + { 7841, 307.4996, +45.9286, 6.41 }, { 7842, 308.2183, -23.0561, 6.36 }, { 7843, 307.3629, +56.0681, 5.91 }, { 7844, 307.5146, +48.9517, 4.95 }, + { 7845, 308.0988, -8.1467, 5.65 }, { 7846, 308.4796, -43.4839, 5.11 }, { 7847, 307.7467, +36.9358, 6.19 }, { 7848, 308.8950, -59.4183, 4.76 }, + { 7849, 307.9925, +25.8044, 6.34 }, { 7850, 307.3954, +62.9942, 4.22 }, { 7851, 307.8283, +49.2203, 5.44 }, { 7852, 308.3033, +11.3033, 4.03 }, + { 7853, 308.7312, -37.9103, 6.44 }, { 7854, 307.8379, +52.3097, 6.18 }, { 7855, 308.5487, -12.2789, 6.13 }, { 7856, 308.6975, -29.5264, 6.40 }, + { 7857, 308.4733, +10.0597, 6.56 }, { 7858, 308.4875, +13.0272, 5.38 }, { 7859, 309.3971, -60.4700, 4.88 }, { 7860, 307.9438, +56.7800, 6.14 }, + { 7861, 308.2179, +43.1917, 6.60 }, { 7862, 308.5417, +20.9853, 6.48 }, { 7863, 310.5121, -75.8194, 6.00 }, { 7864, 310.4321, -74.6494, 6.55 }, + { 7865, 308.8842, -15.4742, 6.19 }, { 7866, 308.4758, +35.2508, 4.61 }, { 7867, 308.4517, +41.7722, 6.49 }, { 7868, 307.5029, +72.5317, 6.27 }, + { 7869, 309.3917, -46.7086, 3.11 }, { 7870, 308.4787, +46.6939, 5.78 }, { 7871, 308.8271, +14.6742, 4.68 }, { 7872, 309.9642, -61.0922, 6.22 }, + { 7873, 309.1817, -1.4500, 4.89 }, { 7874, 309.0346, +25.8825, 6.41 }, { 7875, 310.0108, -59.4511, 5.12 }, { 7876, 308.7100, +51.8542, 6.11 }, + { 7877, 309.4671, -24.8911, 6.36 }, { 7878, 309.3263, +0.0969, 6.22 }, { 7879, 307.8767, +74.9547, 5.20 }, { 7880, 309.2696, +26.4619, 5.59 }, + { 7881, 310.4879, -65.2392, 5.15 }, { 7882, 309.3875, +14.5953, 3.63 }, { 7883, 309.4546, +11.3778, 5.43 }, { 7884, 309.5846, -0.8947, 4.32 }, + { 7885, 309.3825, +31.5725, 6.32 }, { 7886, 309.4775, +18.2692, 6.25 }, { 7887, 309.3858, +31.5219, 6.49 }, { 7888, 309.3483, +38.3286, 6.20 }, + { 7889, 309.8183, -13.0453, 5.22 }, { 7890, 309.8050, -1.5872, 6.22 }, { 7891, 309.6304, +21.2011, 4.82 }, { 7892, 309.6829, +13.3150, 5.72 }, + { 7893, 310.0825, -32.5681, 5.47 }, { 7894, 309.6329, +24.1161, 5.04 }, { 7895, 309.6463, +23.6806, 5.91 }, { 7896, 309.7825, +10.0861, 5.05 }, + { 7897, 309.8537, +0.4864, 5.16 }, { 7898, 310.0487, -22.2261, 6.37 }, { 7899, 309.7708, +15.8381, 5.97 }, { 7900, 310.0125, -17.8614, 5.10 }, + { 7901, 307.0608, +81.4228, 5.46 }, { 7902, 310.1500, -25.3550, 6.51 }, { 7903, 309.7942, +21.8172, 6.08 }, { 7904, 309.7479, +30.3344, 5.68 }, + { 7905, 310.1354, -15.8758, 5.80 }, { 7906, 309.9096, +15.9119, 3.77 }, { 7907, 309.9658, +11.2497, 6.42 }, { 7908, 307.3646, +81.0914, 5.96 }, + { 7909, 310.3488, -30.4017, 5.76 }, { 7910, 310.3504, -26.0000, 6.28 }, { 7911, 309.8888, +40.5794, 6.06 }, { 7912, 309.8463, +45.6669, 6.58 }, + { 7913, 311.2396, -65.7969, 3.42 }, { 7914, 310.1883, +19.9353, 6.45 }, { 7915, 310.7208, -38.4414, 6.29 }, { 7916, 309.7508, +56.0050, 6.48 }, + { 7917, 310.1508, +29.8053, 6.08 }, { 7918, 310.3175, +14.5831, 5.99 }, { 7919, 310.0129, +43.4586, 5.95 }, { 7920, 311.0096, -50.0789, 4.51 }, + { 7921, 310.2608, +32.3072, 5.51 }, { 7922, 310.2517, +39.0822, 6.51 }, { 7923, 310.4925, +17.5214, 6.22 }, { 7924, 310.3579, +45.2803, 1.25 }, + { 7925, 310.0746, +60.5053, 6.01 }, { 7926, 310.4854, +41.7169, 5.67 }, { 7927, 310.5925, +35.4561, 6.66 }, { 7928, 310.8646, +15.0744, 4.43 }, + { 7929, 310.5525, +50.3400, 5.39 }, { 7930, 307.2629, +83.6256, 6.19 }, { 7931, 311.3050, -26.7528, 6.50 }, { 7932, 310.8508, +35.5878, 6.47 }, + { 7933, 311.5838, -38.8008, 5.50 }, { 7934, 312.3254, -67.2236, 5.41 }, { 7935, 311.5775, -35.8797, 6.49 }, { 7936, 311.5238, -24.7292, 4.14 }, + { 7937, 311.5417, -20.4858, 5.93 }, { 7938, 310.6654, +60.6014, 6.15 }, { 7939, 311.2188, +25.2706, 4.91 }, { 7940, 310.8062, +57.1142, 6.32 }, + { 7941, 311.3675, +18.0903, 6.38 }, { 7942, 311.4154, +30.7197, 4.22 }, { 7943, 312.1217, -42.0114, 5.11 }, { 7944, 311.0917, +56.4881, 5.78 }, + { 7945, 310.7958, +66.6575, 5.58 }, { 7946, 311.7650, -1.5133, 6.27 }, { 7947, 311.6613, +16.1244, 5.14 }, { 7948, 311.6646, +16.1242, 4.27 }, + { 7949, 311.5529, +33.9703, 2.46 }, { 7950, 311.9192, -8.5042, 3.77 }, { 7951, 311.9342, -4.9722, 4.42 }, { 7952, 312.3708, -45.7731, 4.89 }, + { 7953, 311.9513, +6.0083, 5.58 }, { 7954, 311.9492, +3.3067, 6.40 }, { 7955, 311.3379, +57.5797, 4.51 }, { 7956, 311.7950, +34.3742, 4.92 }, + { 7957, 311.3225, +61.8389, 3.43 }, { 7958, 311.6604, +46.5317, 6.30 }, { 7959, 312.9096, -61.5708, 6.28 }, { 7960, 312.9117, -61.5708, 6.59 }, + { 7961, 312.3233, -24.2186, 5.86 }, { 7962, 311.5883, +52.9953, 6.33 }, { 7963, 311.8521, +36.4908, 4.53 }, { 7964, 312.3354, -17.9642, 6.21 }, + { 7965, 312.4921, -32.2203, 4.90 }, { 7966, 311.8367, +45.5797, 6.40 }, { 7967, 311.1379, +69.7519, 6.41 }, { 7968, 312.8754, -50.3917, 5.05 }, + { 7969, 311.9554, +47.8319, 5.57 }, { 7970, 312.6963, -31.9456, 6.36 }, { 7971, 312.7529, -36.0867, 5.52 }, { 7972, 311.9700, +52.4072, 6.27 }, + { 7973, 312.4075, +12.5453, 5.98 }, { 7974, 312.4513, +7.8642, 6.33 }, { 7975, 312.4962, +5.5447, 6.21 }, { 7976, 312.6742, -11.4550, 5.88 }, + { 7977, 312.2346, +46.1142, 4.84 }, { 7978, 312.1779, +51.9106, 6.29 }, { 7979, 312.9950, -32.8228, 6.04 }, { 7980, 312.9554, -25.0808, 4.11 }, + { 7981, 312.6542, +18.0514, 6.52 }, { 7982, 312.8571, -4.3736, 5.99 }, { 7983, 312.4779, +46.6611, 6.33 }, { 7984, 312.5204, +44.0594, 5.04 }, + { 7985, 313.0363, -4.4931, 5.55 }, { 7986, 313.7025, -57.5458, 3.65 }, { 7987, 313.4175, -38.1900, 5.35 }, { 7988, 312.8675, +28.2506, 5.77 }, + { 7989, 313.2550, -22.2169, 6.33 }, { 7990, 313.1633, -7.0167, 4.73 }, { 7991, 313.3542, -29.2814, 6.35 }, { 7992, 313.6458, -49.2722, 6.24 }, + { 7993, 312.3225, +64.0422, 6.45 }, { 7994, 313.2733, -10.4264, 6.38 }, { 7995, 313.0321, +27.0969, 4.59 }, { 7996, 313.0013, +32.8492, 6.44 }, + { 7997, 313.5283, -26.0744, 6.41 }, { 7998, 313.4933, -5.1103, 6.44 }, { 7999, 313.2808, +29.6494, 6.34 }, { 8000, 313.6996, -16.0769, 5.78 }, + { 8001, 313.3117, +44.3872, 4.78 }, { 8002, 310.6467, +82.5311, 5.75 }, { 8003, 313.3275, +45.1819, 5.45 }, { 8004, 313.3600, +42.4103, 6.66 }, + { 8005, 313.4746, +33.4378, 5.47 }, { 8006, 313.7838, -0.6267, 6.55 }, { 8007, 313.5933, +28.5219, 6.56 }, { 8008, 313.6400, +28.0575, 5.01 }, + { 8009, 313.5929, +40.7031, 6.70 }, { 8010, 313.9196, +4.5328, 6.05 }, { 8011, 313.9029, +13.7214, 5.17 }, { 8012, 313.9108, +12.5686, 5.58 }, + { 8013, 314.1971, -25.7036, 5.70 }, { 8014, 314.0763, -2.4386, 6.57 }, { 8015, 314.2250, -8.3025, 5.51 }, { 8016, 311.8892, +80.5522, 5.39 }, + { 8017, 314.2942, +0.4636, 6.05 }, { 8018, 314.4192, -15.9683, 5.87 }, { 8019, 315.3671, -67.7903, 6.37 }, { 8020, 313.9575, +47.4178, 5.67 }, + { 8021, 316.1792, -76.9761, 5.15 }, { 8022, 314.0537, +51.0750, 6.63 }, { 8023, 314.1446, +44.9250, 5.96 }, { 8024, 314.6746, -13.5172, 6.01 }, + { 8025, 314.1062, +50.7286, 5.81 }, { 8026, 314.1079, +49.1958, 5.90 }, { 8027, 315.0896, -50.7347, 5.76 }, { 8028, 314.2933, +41.1672, 3.94 }, + { 8029, 314.0708, +56.8875, 6.23 }, { 8030, 314.6079, +10.8392, 5.48 }, { 8031, 314.9987, -35.8703, 6.11 }, { 8032, 314.5683, +22.3258, 5.31 }, + { 8033, 314.9004, -18.9647, 6.25 }, { 8034, 314.7683, +4.2936, 5.23 }, { 8035, 314.5813, +44.4717, 5.55 }, { 8036, 314.6283, +41.9403, 6.16 }, + { 8037, 314.9617, +16.8242, 6.66 }, { 8038, 315.0163, +7.5164, 5.99 }, { 8039, 315.3229, -31.7422, 4.67 }, { 8040, 314.6254, +50.4622, 5.61 }, + { 8041, 315.1408, -3.2697, 6.21 }, { 8042, 315.5525, -42.9981, 6.64 }, { 8043, 313.6846, +75.9256, 6.05 }, { 8044, 315.1154, +19.3294, 5.65 }, + { 8045, 315.4388, -25.1189, 6.05 }, { 8046, 315.6133, -37.4694, 5.94 }, { 8047, 314.9567, +47.5211, 4.74 }, { 8048, 315.7417, -37.3683, 5.30 }, + { 8049, 314.8558, +59.4386, 5.51 }, { 8050, 315.7925, -26.2681, 6.25 }, { 8051, 315.3037, +36.0261, 5.97 }, { 8052, 317.1996, -75.7875, 6.58 }, + { 8053, 315.2954, +46.1558, 5.37 }, { 8054, 315.7483, +0.9247, 6.50 }, { 8055, 316.3092, -53.2728, 5.16 }, { 8056, 315.7625, +1.5319, 6.25 }, + { 8057, 315.7575, +14.7300, 6.31 }, { 8058, 316.0192, -4.1767, 7.31 }, { 8059, 316.0196, -4.1769, 5.89 }, { 8060, 316.1012, -18.1450, 4.84 }, + { 8061, 317.3429, -72.8269, 5.68 }, { 8062, 315.6004, +44.7911, 6.19 }, { 8063, 315.7700, +38.6575, 6.07 }, { 8064, 315.7021, +45.8489, 6.48 }, + { 8065, 315.5379, +56.6697, 5.83 }, { 8066, 316.1446, +5.5028, 5.61 }, { 8067, 316.1737, +2.9419, 6.42 }, { 8068, 316.1892, +2.2697, 6.33 }, + { 8069, 316.6062, -40.6139, 5.53 }, { 8070, 316.5050, -29.8750, 5.68 }, { 8071, 315.9671, +41.6281, 6.33 }, { 8072, 315.8583, +50.3519, 6.37 }, + { 8073, 317.1371, -62.0711, 5.76 }, { 8074, 315.9304, +46.8619, 6.32 }, { 8075, 316.4867, -16.7672, 4.07 }, { 8076, 316.6029, -31.6583, 5.18 }, + { 8077, 316.3612, +5.9583, 5.94 }, { 8078, 315.9483, +53.2861, 5.90 }, { 8079, 316.2329, +43.9278, 3.72 }, { 8080, 316.7821, -24.9942, 4.50 }, + { 8081, 317.8363, -71.4558, 6.20 }, { 8082, 316.5979, +26.9244, 6.12 }, { 8083, 316.9358, -16.5447, 6.17 }, { 8084, 316.6263, +31.1847, 5.82 }, + { 8085, 316.7275, +38.7458, 5.21 }, { 8086, 316.7304, +38.7433, 6.03 }, { 8087, 317.1400, -20.8064, 5.30 }, { 8088, 316.8900, +15.6586, 6.34 }, + { 8089, 316.6504, +47.6483, 4.55 }, { 8090, 317.1175, +6.9894, 6.15 }, { 8091, 317.3875, -19.4436, 6.25 }, { 8092, 318.3354, -69.8736, 5.02 }, + { 8093, 317.3988, -10.6283, 4.51 }, { 8094, 317.1621, +30.2058, 5.59 }, { 8095, 317.4929, +2.9433, 6.45 }, { 8096, 317.6954, -8.6461, 6.27 }, + { 8097, 317.5854, +10.1317, 4.69 }, { 8098, 317.6300, +10.0489, 6.07 }, { 8099, 316.5971, +71.4319, 5.87 }, { 8100, 318.0567, -39.7306, 5.83 }, + { 8101, 317.6333, +22.4547, 6.68 }, { 8102, 317.9221, -13.5278, 6.48 }, { 8103, 317.4942, +45.5025, 6.63 }, { 8104, 318.2629, -38.5747, 5.26 }, + { 8105, 317.7663, +36.2992, 6.54 }, { 8106, 317.5650, +53.5633, 5.73 }, { 8107, 317.6292, +47.6919, 6.46 }, { 8108, 318.3288, -35.5761, 5.96 }, + { 8109, 317.3704, +63.2956, 6.54 }, { 8110, 318.3221, -26.3806, 5.42 }, { 8111, 319.5671, -74.6533, 6.63 }, { 8112, 316.3721, +78.1264, 5.91 }, + { 8113, 317.3833, +68.4903, 7.33 }, { 8114, 318.9413, -52.7369, 5.75 }, { 8115, 318.2342, +30.2269, 3.20 }, { 8116, 318.3700, +15.9825, 6.27 }, + { 8117, 318.8112, -39.4936, 6.21 }, { 8118, 318.5696, -9.3947, 6.77 }, { 8119, 317.9508, +59.9864, 5.64 }, { 8120, 318.3596, +36.6336, 6.05 }, + { 8121, 318.6542, +0.0922, 6.38 }, { 8122, 318.7775, -16.6550, 6.04 }, { 8123, 318.6204, +10.0069, 4.49 }, { 8124, 318.9450, -35.7892, 6.12 }, + { 8125, 319.5013, -63.3183, 6.31 }, { 8126, 318.5429, +29.9011, 6.17 }, { 8127, 318.9079, -19.3483, 5.24 }, { 8128, 318.9371, -14.8286, 5.28 }, + { 8129, 323.0175, -83.1900, 6.45 }, { 8130, 318.6979, +38.0456, 3.72 }, { 8131, 318.9558, +5.2478, 3.92 }, { 8132, 319.1650, -0.3922, 6.48 }, + { 8133, 318.4275, +64.4039, 6.39 }, { 8134, 319.3062, -12.7211, 6.40 }, { 8135, 319.4846, -31.8275, 4.71 }, { 8136, 318.9033, +47.9736, 6.46 }, + { 8137, 319.4887, -16.0147, 5.43 }, { 8138, 319.1233, +42.2514, 6.43 }, { 8139, 319.5654, -16.5378, 7.05 }, { 8140, 319.9667, -52.5503, 4.39 }, + { 8141, 319.5462, -3.4806, 5.82 }, { 8142, 319.7267, -27.2344, 6.40 }, { 8143, 319.3542, +39.3947, 4.23 }, { 8144, 319.3467, +42.6833, 6.19 }, + { 8145, 320.0396, -44.9778, 6.00 }, { 8146, 319.4796, +34.8969, 4.43 }, { 8147, 319.2583, +53.9975, 6.13 }, { 8148, 319.9408, -25.6469, 6.56 }, + { 8149, 319.7167, +11.2033, 5.96 }, { 8150, 319.3096, +55.7981, 5.98 }, { 8151, 320.1900, -39.1903, 4.82 }, { 8152, 320.3183, -48.0622, 6.38 }, + { 8153, 319.3283, +58.6117, 6.42 }, { 8154, 319.6133, +43.9458, 5.00 }, { 8155, 319.7304, +41.0408, 6.15 }, { 8156, 321.0696, -68.2658, 6.41 }, + { 8157, 319.8425, +38.2375, 5.83 }, { 8158, 320.0583, +22.0264, 6.29 }, { 8159, 321.3254, -70.2006, 6.09 }, { 8160, 320.2679, -3.4400, 5.87 }, + { 8161, 319.8700, +49.5103, 5.76 }, { 8162, 319.6450, +62.5856, 2.44 }, { 8163, 320.2700, +7.3544, 5.82 }, { 8164, 319.8158, +58.6236, 5.66 }, + { 8165, 320.2683, +23.8558, 5.57 }, { 8166, 320.2088, +32.4528, 5.68 }, { 8167, 320.5617, -15.1656, 4.28 }, { 8168, 318.9258, +77.0122, 5.95 }, + { 8169, 320.3417, +32.6128, 6.04 }, { 8170, 320.2558, +40.3456, 6.40 }, { 8171, 319.8425, +64.8719, 5.18 }, { 8172, 320.7521, -21.3311, 5.60 }, + { 8173, 320.5217, +19.8044, 4.08 }, { 8174, 318.3396, +81.2308, 6.15 }, { 8175, 320.7346, -8.6806, 5.99 }, { 8176, 323.4767, -81.3169, 6.38 }, + { 8177, 321.0867, -45.3850, 6.31 }, { 8178, 320.7233, +6.8111, 5.16 }, { 8179, 320.1396, +60.7569, 6.11 }, { 8180, 321.1033, -40.9933, 5.77 }, + { 8181, 321.6108, -64.6339, 4.22 }, { 8182, 320.6746, +30.3097, 6.05 }, { 8183, 321.0400, -19.1481, 5.41 }, { 8184, 321.0329, -21.2531, 6.38 }, + { 8185, 320.5017, +49.3889, 5.69 }, { 8186, 320.6954, +38.6342, 6.63 }, { 8187, 321.0479, -11.1219, 5.49 }, { 8188, 321.5642, -53.3394, 6.12 }, + { 8189, 320.8458, +37.4067, 6.58 }, { 8190, 320.9950, +24.2742, 5.71 }, { 8191, 321.1025, +10.1742, 6.35 }, { 8192, 321.2154, -2.6017, 6.36 }, + { 8193, 320.9513, +37.3514, 6.47 }, { 8194, 321.0308, +25.3122, 6.15 }, { 8195, 321.3046, -8.2514, 5.70 }, { 8196, 322.1871, -68.4947, 5.34 }, + { 8197, 321.0963, +24.5289, 6.32 }, { 8198, 321.1417, +26.1744, 5.68 }, { 8199, 321.3208, -2.4433, 5.49 }, { 8200, 321.5954, -36.1706, 5.63 }, + { 8201, 323.3358, -79.9608, 6.47 }, { 8202, 321.7567, -41.4522, 5.51 }, { 8203, 321.4646, +0.5344, 6.46 }, { 8204, 321.6667, -21.5886, 3.74 }, + { 8205, 321.6171, +1.1033, 6.13 }, { 8206, 321.2312, +49.3233, 6.58 }, { 8207, 321.8117, -20.8039, 5.78 }, { 8208, 321.3317, +46.7144, 5.60 }, + { 8209, 321.4458, +36.6675, 5.94 }, { 8210, 321.6112, +19.3756, 6.07 }, { 8211, 322.2513, -52.2942, 6.39 }, { 8212, 322.0579, -10.4317, 6.61 }, + { 8213, 322.1808, -20.1928, 4.51 }, { 8214, 322.2658, -30.7614, 6.50 }, { 8215, 321.8392, +37.1167, 5.31 }, { 8216, 321.7150, +48.8350, 5.31 }, + { 8217, 321.9171, +27.6086, 5.41 }, { 8218, 321.6875, +52.8986, 6.03 }, { 8219, 322.1033, +8.1956, 6.40 }, { 8220, 322.0346, +32.2253, 5.80 }, + { 8221, 322.2496, +17.9058, 6.44 }, { 8222, 322.4983, -18.8522, 6.57 }, { 8223, 322.2496, +22.1794, 5.93 }, { 8224, 321.8554, +59.7500, 6.10 }, + { 8225, 322.4871, +23.6389, 4.57 }, { 8226, 322.2196, +55.4186, 6.12 }, { 8227, 321.9421, +66.8092, 5.44 }, { 8228, 322.3625, +46.5406, 5.24 }, + { 8229, 323.0246, -40.8208, 5.29 }, { 8230, 323.0608, -32.0553, 5.97 }, { 8231, 322.7900, +12.1375, 6.08 }, { 8232, 322.8896, -4.4289, 2.91 }, + { 8233, 323.3238, -51.2625, 6.41 }, { 8234, 324.7342, -78.5575, 6.18 }, { 8235, 323.1388, -23.4094, 6.43 }, { 8236, 323.3479, -43.1514, 5.57 }, + { 8237, 322.5850, +52.9581, 6.02 }, { 8238, 322.1650, +70.5608, 3.23 }, { 8239, 321.2071, +80.5247, 5.97 }, { 8240, 323.1129, +23.3944, 6.70 }, + { 8241, 323.5708, -41.0750, 6.32 }, { 8242, 322.8646, +52.6200, 6.16 }, { 8243, 322.7471, +60.4594, 5.53 }, { 8244, 323.7208, -28.3039, 6.41 }, + { 8245, 323.7125, -19.9156, 5.69 }, { 8246, 323.2358, +49.9778, 5.75 }, { 8247, 323.8163, -22.5458, 6.40 }, { 8248, 323.3246, +45.8542, 6.25 }, + { 8249, 324.5121, -63.1758, 6.20 }, { 8250, 323.6417, +22.7547, 6.47 }, { 8251, 323.8233, -2.0169, 5.77 }, { 8252, 323.4954, +45.5919, 4.02 }, + { 8253, 324.0458, -25.8286, 5.73 }, { 8254, 325.3687, -76.6100, 3.76 }, { 8255, 323.6942, +38.5342, 4.90 }, { 8256, 324.2038, -32.9519, 6.11 }, + { 8257, 323.8292, +28.1972, 6.31 }, { 8258, 323.8625, +24.4522, 6.11 }, { 8259, 323.6146, +51.6983, 6.15 }, { 8260, 324.2700, -18.5339, 4.68 }, + { 8261, 324.0579, +30.0556, 6.36 }, { 8262, 324.0100, +45.3747, 5.53 }, { 8263, 324.3908, +0.3903, 6.25 }, { 8264, 324.4379, -6.1458, 4.69 }, + { 8265, 324.4321, +6.6183, 6.18 }, { 8266, 324.2375, +40.4136, 5.01 }, { 8267, 324.4392, +19.3186, 5.45 }, { 8268, 324.7754, -32.3208, 6.28 }, + { 8269, 324.9987, -51.6408, 6.21 }, { 8270, 324.6329, +5.7717, 5.67 }, { 8271, 325.1400, -54.2625, 6.33 }, { 8272, 324.3662, +44.6967, 6.20 }, + { 8273, 324.8671, -9.4231, 6.08 }, { 8274, 324.6875, +25.4989, 6.16 }, { 8275, 324.4113, +54.0422, 6.15 }, { 8276, 324.7546, +20.2653, 5.85 }, + { 8277, 324.8888, +2.2436, 5.10 }, { 8278, 325.0229, -15.3378, 3.68 }, { 8279, 324.4800, +62.0819, 4.73 }, { 8280, 327.7262, -81.2808, 5.29 }, + { 8281, 324.7400, +57.4892, 5.62 }, { 8282, 325.4421, -24.8981, 6.49 }, { 8283, 325.3871, -13.9525, 5.18 }, { 8284, 325.0462, +43.2739, 5.11 }, + { 8285, 325.5033, -22.7372, 5.24 }, { 8286, 326.3700, -70.9911, 6.01 }, { 8287, 325.5421, +1.2853, 5.67 }, { 8288, 325.6646, -17.1336, 4.73 }, + { 8289, 325.5646, +5.6800, 5.30 }, { 8290, 325.1804, +54.8722, 6.20 }, { 8291, 325.3929, +40.8053, 6.11 }, { 8292, 325.6375, +10.8247, 6.09 }, + { 8293, 325.8062, -18.3792, 6.22 }, { 8294, 341.3692, -87.1817, 6.57 }, { 8295, 325.7683, -13.6003, 5.88 }, { 8296, 0.0000, +0.0000, 0.00 }, + { 8297, 325.5046, +35.5103, 6.07 }, { 8298, 325.5350, +45.7658, 6.17 }, { 8299, 326.1229, -37.4475, 6.30 }, { 8300, 325.5954, +41.0772, 5.69 }, + { 8301, 325.5238, +51.1897, 4.67 }, { 8302, 326.0042, -13.2506, 5.99 }, { 8303, 326.3292, -48.5014, 6.45 }, { 8304, 325.6621, +49.6003, 6.09 }, + { 8305, 326.2367, -32.9742, 4.34 }, { 8306, 325.7767, +41.1550, 5.49 }, { 8307, 325.8571, +38.2839, 5.65 }, { 8308, 326.0467, +9.8750, 2.39 }, + { 8309, 326.0358, +28.7428, 4.73 }, { 8310, 326.0346, +28.7431, 6.08 }, { 8311, 326.2513, -8.9175, 5.09 }, { 8312, 325.6892, +59.2711, 6.08 }, + { 8313, 326.1279, +17.3500, 4.34 }, { 8314, 326.1304, +14.7719, 5.94 }, { 8315, 326.1613, +25.6450, 4.13 }, { 8316, 325.8767, +58.7800, 4.08 }, + { 8317, 325.4804, +71.3114, 4.56 }, { 8318, 326.5679, -8.7242, 6.00 }, { 8319, 326.6338, -10.6342, 5.58 }, { 8320, 326.4354, +35.8572, 6.40 }, + { 8321, 326.5183, +22.9489, 5.29 }, { 8322, 326.7600, -15.8728, 2.87 }, { 8323, 327.0658, -46.6964, 5.58 }, { 8324, 325.7667, +72.3203, 5.17 }, + { 8325, 326.6000, +25.5633, 6.28 }, { 8326, 326.9342, -29.1017, 5.01 }, { 8327, 326.2221, +62.4606, 5.95 }, { 8328, 326.8083, +2.6861, 5.64 }, + { 8329, 326.5692, +43.0608, 6.54 }, { 8330, 326.7696, +17.1942, 6.21 }, { 8331, 327.5004, -63.2875, 5.62 }, { 8332, 326.9088, -4.0828, 6.17 }, + { 8333, 327.6963, -68.3706, 5.53 }, { 8334, 326.3621, +61.1208, 4.29 }, { 8335, 326.6983, +49.3094, 4.23 }, { 8336, 327.0346, +36.5806, 6.47 }, + { 8337, 327.4212, -11.2769, 6.31 }, { 8338, 327.1225, +38.6486, 6.12 }, { 8339, 326.8554, +60.6928, 5.52 }, { 8340, 327.5546, -15.1553, 6.38 }, + { 8341, 327.3621, +20.4625, 6.29 }, { 8342, 326.7542, +70.1508, 6.29 }, { 8343, 327.4613, +30.1742, 5.04 }, { 8344, 327.5363, +17.2856, 5.29 }, + { 8345, 327.4171, +41.1489, 6.48 }, { 8346, 327.9242, -17.3769, 6.16 }, { 8347, 327.3292, +61.2728, 6.17 }, { 8348, 327.8925, +19.8267, 5.77 }, + { 8349, 327.7704, +39.5367, 6.17 }, { 8350, 328.0758, +21.2731, 6.89 }, { 8351, 328.3242, -12.4483, 5.08 }, { 8352, 328.7979, -60.1136, 5.90 }, + { 8353, 328.4821, -36.6350, 3.01 }, { 8354, 328.1246, +28.7933, 5.53 }, { 8355, 328.4000, -9.6883, 6.59 }, { 8356, 328.2658, +25.9250, 5.08 }, + { 8357, 328.0042, +55.7969, 5.71 }, { 8358, 328.4058, +19.6683, 5.68 }, { 8359, 328.4908, +6.8644, 6.15 }, { 8360, 328.5433, -3.7239, 5.71 }, + { 8361, 327.9054, +65.7528, 6.37 }, { 8362, 329.0583, -56.1006, 6.19 }, { 8363, 328.6496, -2.6989, 6.20 }, { 8364, 328.5725, +19.7183, 6.39 }, + { 8365, 328.9817, -29.3936, 6.41 }, { 8366, 329.0950, -36.7464, 5.46 }, { 8367, 329.2592, -36.2531, 6.18 }, { 8368, 329.4796, -53.0075, 4.40 }, + { 8369, 329.6254, -58.9878, 6.12 }, { 8370, 330.4671, -76.3375, 6.41 }, { 8371, 328.7217, +56.6114, 5.80 }, { 8372, 329.1000, +21.2397, 6.40 }, + { 8373, 329.2350, +12.0764, 5.54 }, { 8374, 328.8363, +61.5419, 6.13 }, { 8375, 328.8796, +65.3208, 5.86 }, { 8376, 329.5554, -4.5753, 6.33 }, + { 8377, 329.2592, +48.6686, 6.42 }, { 8378, 329.6825, -20.8172, 6.12 }, { 8379, 329.8246, -37.6047, 5.50 }, { 8380, 330.7658, -75.8814, 5.95 }, + { 8381, 330.1004, -54.1172, 6.01 }, { 8382, 329.7292, -3.6269, 6.22 }, { 8383, 329.1629, +63.6256, 4.91 }, { 8384, 329.2962, +66.1561, 6.43 }, + { 8385, 330.0329, +6.7175, 6.00 }, { 8386, 330.2092, -27.5464, 5.42 }, { 8387, 330.8400, -55.2139, 4.69 }, { 8388, 329.7225, +62.6983, 5.93 }, + { 8389, 329.8458, +57.6583, 6.59 }, { 8390, 330.2708, +0.6050, 5.58 }, { 8391, 330.1117, +33.0061, 6.46 }, { 8392, 330.2725, +13.1197, 5.60 }, + { 8393, 330.2883, +8.2572, 5.65 }, { 8394, 330.5496, -16.0964, 6.28 }, { 8395, 329.4625, +74.9967, 6.35 }, { 8396, 330.6108, -15.0358, 6.37 }, + { 8397, 330.5058, +10.9739, 6.37 }, { 8398, 330.8217, -28.0958, 7.10 }, { 8399, 330.1637, +62.4881, 6.66 }, { 8400, 329.8125, +73.1800, 5.03 }, + { 8401, 330.8183, -5.4775, 5.54 }, { 8402, 330.8288, -1.8447, 4.69 }, { 8403, 330.4608, +52.8822, 5.78 }, { 8404, 330.8292, +11.3864, 5.80 }, + { 8405, 331.0996, -28.0833, 6.47 }, { 8406, 330.5192, +58.0006, 5.56 }, { 8407, 330.7362, +44.6500, 5.60 }, { 8408, 331.1533, -25.1775, 5.96 }, + { 8409, 331.4621, -58.3639, 5.62 }, { 8410, 331.1975, +0.9067, 5.30 }, { 8411, 331.5288, -38.4567, 4.46 }, { 8412, 331.1433, +32.9419, 6.38 }, + { 8413, 331.4200, +5.0586, 4.84 }, { 8414, 331.4458, +0.3197, 2.96 }, { 8415, 331.2975, +26.6739, 5.78 }, { 8416, 330.9704, +63.1197, 5.29 }, + { 8417, 330.9475, +64.6278, 4.29 }, { 8418, 331.6092, -12.1303, 4.27 }, { 8419, 331.3946, +28.9639, 5.70 }, { 8420, 332.6771, -74.1194, 6.55 }, + { 8421, 331.3183, +46.7447, 6.13 }, { 8422, 331.4608, +45.1122, 6.44 }, { 8423, 329.5529, +82.8697, 6.98 }, { 8424, 331.5083, +45.0144, 5.14 }, + { 8425, 332.0583, -45.0389, 1.74 }, { 8426, 331.2521, +62.7856, 5.27 }, { 8427, 331.4633, +48.2317, 6.27 }, { 8428, 331.2871, +62.2800, 5.11 }, + { 8429, 331.5517, +45.2486, 6.19 }, { 8430, 331.7529, +25.3450, 3.76 }, { 8431, 332.0958, -31.0114, 4.50 }, { 8432, 332.9804, -75.8839, 6.15 }, + { 8433, 332.1083, -33.9561, 4.99 }, { 8434, 331.5562, +56.3431, 6.39 }, { 8435, 331.8692, +19.4756, 5.75 }, { 8436, 331.8750, +18.0006, 6.35 }, + { 8437, 332.1779, -32.8744, 6.37 }, { 8438, 331.9596, +21.7028, 5.78 }, { 8439, 332.2458, -17.4803, 5.81 }, { 8440, 332.4917, -47.8928, 6.43 }, + { 8441, 332.0717, +25.5436, 6.11 }, { 8442, 331.7900, +58.8408, 6.32 }, { 8443, 331.8562, +53.3072, 6.14 }, { 8444, 332.4821, -33.9853, 5.37 }, + { 8445, 332.0688, +49.7964, 6.42 }, { 8446, 332.5004, -27.7075, 6.44 }, { 8447, 332.5367, -31.4517, 4.92 }, { 8448, 332.1708, +45.7419, 6.11 }, + { 8449, 332.3067, +33.1722, 5.58 }, { 8450, 332.5500, +6.1978, 3.53 }, { 8451, 332.5879, -2.1058, 6.27 }, { 8452, 332.6563, -10.4350, 5.46 }, + { 8453, 332.6408, -3.7328, 6.01 }, { 8454, 332.4967, +33.1783, 4.29 }, { 8455, 332.5792, +19.6169, 6.18 }, { 8456, 332.5925, +14.6300, 6.33 }, + { 8457, 332.7600, -20.7675, 6.09 }, { 8458, 332.6558, +11.6244, 5.78 }, { 8459, 332.6258, +20.9781, 6.46 }, { 8460, 332.7150, +30.5531, 6.32 }, + { 8461, 332.9638, +16.0406, 5.95 }, { 8462, 333.1075, -13.8061, 6.03 }, { 8463, 332.7912, +50.8233, 5.40 }, { 8464, 333.2396, -25.6722, 6.17 }, + { 8465, 332.7138, +58.2011, 3.35 }, { 8466, 333.0333, +24.9500, 5.92 }, { 8467, 333.1825, -3.2792, 6.39 }, { 8468, 332.4517, +72.3411, 4.79 }, + { 8469, 332.8779, +59.4144, 5.04 }, { 8470, 333.4350, -24.8192, 5.58 }, { 8471, 334.4604, -76.4883, 5.51 }, { 8472, 332.9533, +56.8394, 5.24 }, + { 8473, 332.5638, +72.1111, 6.37 }, { 8474, 332.6621, +70.1328, 5.50 }, { 8475, 333.1992, +34.6047, 5.33 }, { 8476, 332.9871, +59.0847, 6.30 }, + { 8477, 333.6608, -40.6183, 6.23 }, { 8478, 333.5783, -26.2331, 5.43 }, { 8479, 333.0079, +60.7594, 5.35 }, { 8480, 333.5750, -20.9258, 5.32 }, + { 8481, 335.0063, -79.5603, 5.10 }, { 8482, 333.4108, +28.6083, 5.89 }, { 8483, 333.0929, +63.2914, 5.79 }, { 8484, 333.8963, -43.5481, 6.10 }, + { 8485, 333.4696, +39.7150, 4.49 }, { 8486, 333.9038, -40.6533, 4.79 }, { 8487, 333.4554, +45.4408, 5.53 }, { 8488, 334.1108, -40.3725, 5.10 }, + { 8489, 333.6850, +42.9539, 5.71 }, { 8490, 333.4563, +63.1625, 6.11 }, { 8491, 333.9992, +8.5494, 6.21 }, { 8492, 334.1558, -24.1017, 6.15 }, + { 8493, 333.2204, +73.3072, 6.08 }, { 8494, 333.7583, +57.0436, 4.19 }, { 8495, 334.1400, -0.4036, 6.15 }, { 8496, 334.2004, -11.1686, 5.34 }, + { 8497, 334.2492, -22.8600, 6.17 }, { 8498, 333.9925, +37.7489, 4.13 }, { 8499, 334.2083, -6.2167, 4.16 }, { 8500, 334.2192, -8.9600, 5.79 }, + { 8501, 334.5650, -52.3722, 5.37 }, { 8502, 334.6254, -59.7403, 2.86 }, { 8503, 334.1237, +27.8042, 6.37 }, { 8504, 334.2771, -4.6128, 5.75 }, + { 8505, 337.9058, -84.0328, 5.77 }, { 8506, 334.1104, +57.2203, 5.88 }, { 8507, 334.5179, +0.2378, 6.39 }, { 8508, 334.7533, -12.6950, 5.95 }, + { 8509, 335.1508, -56.4900, 6.34 }, { 8510, 334.7342, +37.7694, 6.17 }, { 8511, 334.5529, +62.8044, 5.75 }, { 8512, 335.0496, -6.1789, 5.37 }, + { 8513, 335.1150, +5.7894, 5.37 }, { 8514, 335.2325, +8.1867, 6.17 }, { 8515, 336.1533, -71.7444, 5.29 }, { 8516, 335.3983, -20.4017, 5.13 }, + { 8517, 335.2504, +26.9353, 6.47 }, { 8518, 335.4142, -0.6128, 3.84 }, { 8519, 335.1650, +50.9808, 6.42 }, { 8520, 335.3796, +12.2053, 5.01 }, + { 8521, 335.6829, -44.0522, 6.62 }, { 8522, 335.3304, +28.3306, 4.81 }, { 8523, 335.2567, +46.5367, 4.57 }, { 8524, 335.7833, -44.0714, 5.62 }, + { 8525, 334.5850, +76.4881, 6.66 }, { 8526, 336.4625, -74.9844, 6.04 }, { 8527, 336.2937, -69.5683, 5.78 }, { 8528, 335.4621, +42.0783, 6.41 }, + { 8529, 335.8788, -23.2375, 5.53 }, { 8530, 335.8838, -6.8056, 5.93 }, { 8531, 336.2350, -56.2028, 5.32 }, { 8532, 335.9150, +20.8483, 6.04 }, + { 8533, 336.0288, -3.1631, 5.78 }, { 8534, 336.1129, -12.4706, 5.76 }, { 8535, 335.7508, +57.2844, 6.16 }, { 8536, 335.9758, +38.5736, 6.22 }, + { 8537, 335.7508, +62.4200, 6.04 }, { 8538, 335.8900, +52.2292, 4.43 }, { 8539, 336.3192, +1.3775, 4.66 }, { 8540, 336.8333, -63.0336, 4.48 }, + { 8541, 336.1292, +49.4764, 4.57 }, { 8542, 336.5446, -22.3175, 6.29 }, { 8543, 336.4196, +18.4444, 6.26 }, { 8544, 336.6425, -15.2586, 6.57 }, + { 8545, 336.6433, -15.2575, 6.35 }, { 8546, 333.2942, +86.1081, 5.27 }, { 8547, 337.1571, -66.5108, 5.55 }, { 8548, 336.6558, +4.3936, 5.75 }, + { 8549, 336.6904, +37.4439, 6.46 }, { 8550, 335.9221, +78.2433, 6.76 }, { 8551, 336.9646, +4.6956, 4.79 }, { 8552, 337.1633, -38.8681, 5.47 }, + { 8553, 336.8604, +39.8097, 6.14 }, { 8554, 336.7467, +56.4333, 6.57 }, { 8555, 336.9425, +31.8403, 5.98 }, { 8556, 337.3175, -42.5044, 3.97 }, + { 8557, 336.5033, +70.7708, 5.47 }, { 8558, 337.2071, +0.0203, 4.59 }, { 8559, 337.2088, +0.0200, 4.42 }, { 8560, 337.4396, -42.2506, 4.11 }, + { 8561, 336.7721, +65.1322, 5.46 }, { 8562, 337.2833, +9.1289, 5.58 }, { 8563, 337.4417, -26.8928, 5.95 }, { 8564, 337.2925, +26.7631, 5.79 }, + { 8565, 337.5063, -11.0850, 6.40 }, { 8566, 337.4917, +4.4317, 5.48 }, { 8567, 337.5725, -13.4142, 6.37 }, { 8568, 337.0821, +64.0856, 6.29 }, + { 8569, 337.4329, +35.7256, 6.56 }, { 8570, 337.7238, -25.9264, 6.43 }, { 8571, 337.2929, +58.4153, 3.75 }, { 8572, 337.3825, +47.7069, 4.36 }, + { 8573, 337.6617, -9.3219, 4.82 }, { 8574, 337.5075, +32.5725, 5.65 }, { 8575, 337.5271, +49.3561, 6.40 }, { 8576, 337.8763, -31.6539, 4.29 }, + { 8577, 338.8600, -77.2283, 6.15 }, { 8578, 336.6771, +78.7858, 5.83 }, { 8579, 337.6221, +43.1233, 4.51 }, { 8580, 337.8267, -1.0889, 6.16 }, + { 8581, 337.8267, -5.4450, 6.14 }, { 8582, 338.2504, -60.0178, 4.81 }, { 8583, 337.9221, -9.0944, 6.38 }, { 8584, 337.8925, +29.5428, 6.35 }, + { 8585, 337.8229, +50.2825, 3.77 }, { 8586, 338.1479, +20.2300, 6.42 }, { 8587, 338.1954, +15.8633, 6.32 }, { 8588, 338.1100, +39.7797, 5.88 }, + { 8589, 338.0783, +54.0375, 6.35 }, { 8590, 338.5121, -0.4258, 5.89 }, { 8591, 337.4704, +78.8242, 5.50 }, { 8592, 338.6733, -19.2917, 5.20 }, + { 8593, 338.9704, -56.1164, 6.23 }, { 8594, 338.4192, +56.6250, 5.71 }, { 8595, 338.2621, +69.9136, 6.60 }, { 8596, 338.9021, -22.0089, 5.97 }, + { 8597, 338.8392, +0.1175, 4.02 }, { 8598, 338.3208, +70.3739, 6.34 }, { 8599, 338.0675, +76.2264, 5.68 }, { 8600, 339.1221, -39.4172, 6.28 }, + { 8601, 339.1475, -30.3361, 5.82 }, { 8602, 339.2450, -39.4089, 5.86 }, { 8603, 338.9679, +39.6342, 5.73 }, { 8604, 339.0329, +35.5772, 6.10 }, + { 8605, 339.1517, +11.6969, 6.40 }, { 8606, 338.9725, +50.0711, 6.29 }, { 8607, 338.9658, +56.0700, 6.38 }, { 8608, 339.2696, +12.5772, 6.30 }, + { 8609, 339.2029, +35.6525, 6.30 }, { 8610, 339.4392, -3.7719, 5.03 }, { 8611, 339.7850, -51.3078, 6.65 }, { 8612, 339.5925, -6.1022, 6.23 }, + { 8613, 339.3433, +51.5453, 4.63 }, { 8614, 339.6862, -27.2522, 6.47 }, { 8615, 338.9421, +73.6431, 5.08 }, { 8616, 339.7146, -32.9186, 5.66 }, + { 8617, 339.5729, +45.1831, 6.40 }, { 8618, 339.7192, +19.5222, 5.82 }, { 8619, 339.9333, -27.6747, 6.31 }, { 8620, 340.2038, -56.5778, 5.97 }, + { 8621, 339.6579, +56.7958, 5.21 }, { 8622, 339.8154, +39.0503, 4.88 }, { 8623, 340.0929, -29.3411, 5.87 }, { 8624, 339.9458, +19.6811, 6.21 }, + { 8625, 339.3042, +75.3717, 5.79 }, { 8626, 339.8929, +37.5928, 6.03 }, { 8627, 339.6625, +63.5844, 5.19 }, { 8628, 340.1642, -26.9564, 4.17 }, + { 8629, 340.2000, -2.4458, 6.31 }, { 8630, 341.5138, -80.6183, 4.15 }, { 8631, 340.2196, +14.5494, 5.71 }, { 8632, 340.1288, +44.2764, 4.46 }, + { 8633, 340.0767, +53.8461, 5.93 }, { 8634, 340.3654, +10.8314, 3.40 }, { 8635, 340.6538, -46.7894, 5.98 }, { 8636, 340.6671, -45.1153, 2.10 }, + { 8637, 340.5921, -28.6392, 6.17 }, { 8638, 340.3808, +30.9658, 6.34 }, { 8639, 340.6796, -43.7522, 6.07 }, { 8640, 340.3692, +40.2256, 5.25 }, + { 8641, 340.4392, +29.3075, 4.79 }, { 8642, 340.4892, +14.5164, 5.90 }, { 8643, 340.4004, +41.5494, 5.94 }, { 8644, 340.8750, -40.5856, 4.85 }, + { 8645, 340.7646, -7.6883, 6.45 }, { 8646, 341.0688, -59.5006, 6.30 }, { 8647, 340.8096, -5.0372, 6.41 }, { 8648, 340.5867, +53.9089, 6.12 }, + { 8649, 340.8971, -17.1697, 4.69 }, { 8650, 340.7504, +30.2214, 2.94 }, { 8651, 340.7312, +37.8028, 6.43 }, { 8652, 340.7688, +47.1686, 6.39 }, + { 8653, 340.9279, +10.9392, 6.51 }, { 8654, 341.0217, +39.4656, 5.95 }, { 8655, 341.4079, -52.4997, 4.85 }, { 8656, 341.0229, +41.8192, 5.08 }, + { 8657, 341.4196, -45.4525, 5.51 }, { 8658, 341.5333, -47.0211, 6.62 }, { 8659, 341.6179, -48.3142, 6.48 }, { 8660, 341.3675, +19.3667, 6.25 }, + { 8661, 341.2050, +52.5172, 6.55 }, { 8662, 341.6821, -45.0606, 6.56 }, { 8663, 342.5954, -79.8758, 5.35 }, { 8664, 342.4204, -76.9494, 6.73 }, + { 8665, 341.6733, +12.1728, 4.19 }, { 8666, 341.5425, +44.5461, 5.76 }, { 8667, 341.6329, +23.5656, 3.95 }, { 8668, 341.8296, -33.8389, 6.28 }, + { 8669, 342.0892, -60.3158, 6.37 }, { 8670, 341.8879, -18.3867, 5.26 }, { 8671, 341.9463, -37.7781, 6.71 }, { 8672, 342.3225, -69.6522, 6.34 }, + { 8673, 341.9283, -13.9436, 5.66 }, { 8674, 341.9842, -24.0881, 6.30 }, { 8675, 342.1388, -50.6831, 3.49 }, { 8676, 342.1258, -9.4444, 6.19 }, + { 8677, 341.8467, +58.4828, 6.36 }, { 8678, 342.0454, +37.4167, 5.90 }, { 8679, 342.3979, -12.4075, 4.01 }, { 8680, 342.4962, -31.1947, 6.33 }, + { 8681, 342.3846, +10.4789, 6.54 }, { 8682, 342.1992, +54.4150, 6.12 }, { 8683, 342.1842, +62.9383, 6.06 }, { 8684, 342.5008, +24.6017, 3.48 }, + { 8685, 342.7592, -38.8431, 5.42 }, { 8686, 342.9371, -58.1186, 6.46 }, { 8687, 342.2529, +68.5703, 6.19 }, { 8688, 342.4425, +55.9028, 5.43 }, + { 8689, 343.0412, -62.8114, 6.12 }, { 8690, 342.5908, +41.9536, 5.92 }, { 8691, 342.6629, +19.1408, 6.40 }, { 8692, 342.5425, +50.6769, 6.21 }, + { 8693, 342.8371, -28.4639, 5.97 }, { 8694, 342.4200, +66.2006, 3.52 }, { 8695, 343.1317, -31.1244, 4.46 }, { 8696, 342.8450, +61.6969, 5.60 }, + { 8697, 343.1004, +9.8356, 5.16 }, { 8698, 343.1538, -6.4203, 3.74 }, { 8699, 343.0083, +43.3125, 4.94 }, { 8700, 343.4079, -47.4019, 6.04 }, + { 8701, 343.6642, -69.9264, 6.05 }, { 8702, 341.8708, +83.1539, 4.74 }, { 8703, 343.2596, +16.8411, 5.64 }, { 8704, 343.3696, -10.3833, 5.80 }, + { 8705, 343.2179, +50.4119, 6.46 }, { 8706, 343.2971, +40.1672, 6.34 }, { 8707, 343.2658, +60.1011, 6.01 }, { 8708, 343.4171, +44.7492, 5.81 }, + { 8709, 343.6625, -14.1792, 3.27 }, { 8710, 343.6421, -6.7953, 6.19 }, { 8711, 343.6896, -15.7281, 5.56 }, { 8712, 343.5292, +40.3769, 5.81 }, + { 8713, 343.8121, -35.6114, 6.40 }, { 8714, 343.6488, +16.9417, 6.12 }, { 8715, 343.7479, +1.0647, 6.11 }, { 8716, 343.7958, -3.0122, 5.72 }, + { 8717, 343.8071, +8.8158, 4.90 }, { 8718, 343.7608, +37.0769, 5.91 }, { 8719, 343.9642, -30.3669, 6.10 }, { 8720, 343.9871, -31.4603, 4.21 }, + { 8721, 344.1000, -30.4344, 6.48 }, { 8722, 344.1992, -46.0308, 5.70 }, { 8723, 343.9354, +36.3517, 5.74 }, { 8724, 344.2146, +11.8483, 6.51 }, + { 8725, 344.0983, +41.6039, 5.59 }, { 8726, 344.1083, +49.7336, 4.95 }, { 8727, 344.3217, -3.1900, 6.31 }, { 8728, 344.4129, -28.3778, 1.16 }, + { 8729, 344.3662, +20.7689, 5.49 }, { 8730, 344.3867, +3.8103, 6.28 }, { 8731, 344.2688, +48.6842, 5.43 }, { 8732, 344.6458, -34.4769, 6.13 }, + { 8733, 344.4196, +39.3089, 6.18 }, { 8734, 344.5646, -1.6047, 6.16 }, { 8735, 344.5988, -0.5897, 6.37 }, { 8736, 342.7592, +85.3736, 5.90 }, + { 8737, 344.6463, +9.3569, 6.43 }, { 8738, 344.6775, +7.3397, 6.33 }, { 8739, 344.7992, +11.7289, 5.75 }, { 8740, 344.8992, -28.5378, 5.51 }, + { 8741, 344.8988, -12.9292, 6.07 }, { 8742, 344.8642, +0.9628, 5.43 }, { 8743, 345.0242, -24.8358, 5.65 }, { 8744, 344.7929, +52.6544, 6.29 }, + { 8745, 344.7875, +59.8147, 6.43 }, { 8746, 345.1025, -24.3733, 6.29 }, { 8747, 345.2200, -51.2458, 4.12 }, { 8748, 343.6033, +84.3461, 4.71 }, + { 8749, 345.2813, -49.0500, 5.68 }, { 8750, 345.1579, +0.1858, 6.21 }, { 8751, 345.1787, +3.0117, 5.83 }, { 8752, 345.0213, +56.9453, 5.00 }, + { 8753, 345.1771, +31.0831, 6.60 }, { 8754, 345.3308, -27.1464, 5.55 }, { 8755, 345.1433, +45.3750, 6.50 }, { 8756, 345.3458, -21.2092, 6.28 }, + { 8757, 345.3483, -6.9389, 6.21 }, { 8758, 345.2279, +38.7081, 6.54 }, { 8759, 345.3821, -3.2886, 5.94 }, { 8760, 345.6417, -35.5792, 6.47 }, + { 8761, 345.3779, +57.1056, 6.20 }, { 8762, 345.4804, +42.3261, 3.62 }, { 8763, 345.6358, -5.4258, 6.15 }, { 8764, 345.6846, -19.1294, 5.97 }, + { 8765, 345.6379, +31.7806, 6.57 }, { 8766, 345.6513, +42.7578, 5.10 }, { 8767, 345.8742, -33.2506, 5.11 }, { 8768, 345.6883, +44.0589, 6.39 }, + { 8769, 346.2175, -67.1797, 5.52 }, { 8770, 345.6825, +55.2364, 6.50 }, { 8771, 345.9979, -40.5217, 5.79 }, { 8772, 345.9887, -3.2047, 6.68 }, + { 8773, 345.9692, +3.8200, 4.53 }, { 8774, 346.1650, -52.0350, 5.37 }, { 8775, 345.9438, +28.0828, 2.42 }, { 8776, 346.0042, +6.6167, 6.41 }, + { 8777, 345.8488, +60.4453, 6.74 }, { 8778, 345.8400, +58.5647, 6.43 }, { 8779, 345.8871, +67.2092, 5.24 }, { 8780, 346.0458, +50.0522, 4.65 }, + { 8781, 346.1904, +15.2053, 2.49 }, { 8782, 346.2908, -6.3064, 5.43 }, { 8783, 346.3033, -16.9208, 6.14 }, { 8784, 346.2763, +16.5631, 6.44 }, + { 8785, 346.3233, +1.3069, 6.39 }, { 8786, 347.0988, -78.5192, 6.12 }, { 8787, 346.7200, -42.4794, 4.28 }, { 8788, 346.5758, +18.5175, 6.13 }, + { 8789, 346.6704, -22.2569, 4.47 }, { 8790, 346.7233, -37.1078, 5.61 }, { 8791, 346.7896, -48.3933, 6.33 }, { 8792, 346.6329, +19.9108, 6.30 }, + { 8793, 346.8112, -49.3136, 5.83 }, { 8794, 347.1488, -72.4136, 6.15 }, { 8795, 346.7513, +9.4094, 4.52 }, { 8796, 346.7783, +25.4683, 4.76 }, + { 8797, 346.6538, +59.4197, 4.85 }, { 8798, 346.8654, +32.8258, 6.02 }, { 8799, 346.8696, +21.1342, 5.99 }, { 8800, 346.8254, +46.0681, 6.66 }, + { 8801, 346.7921, +52.8164, 6.11 }, { 8802, 347.0875, -27.1767, 5.60 }, { 8803, 346.7933, +59.7275, 6.40 }, { 8804, 346.9137, +46.3872, 5.33 }, + { 8805, 346.9392, +49.2958, 5.70 }, { 8806, 347.0512, +44.5617, 6.56 }, { 8807, 347.1704, +2.1278, 5.40 }, { 8808, 346.9488, +63.6333, 6.26 }, + { 8809, 347.5487, -65.1425, 6.47 }, { 8810, 348.0500, -79.0872, 6.41 }, { 8811, 346.9883, +64.2225, 6.21 }, { 8812, 347.3617, -20.8275, 3.66 }, + { 8813, 347.4358, -27.9114, 5.87 }, { 8814, 347.4887, -41.1394, 5.81 }, { 8815, 347.3813, +8.6772, 5.12 }, { 8816, 347.4567, -13.4894, 6.42 }, + { 8817, 347.4783, -21.5425, 4.69 }, { 8818, 347.5408, -39.4083, 5.83 }, { 8819, 346.9746, +75.3875, 4.41 }, { 8820, 347.5900, -44.7533, 3.90 }, + { 8821, 347.5063, +9.8219, 5.39 }, { 8822, 347.4337, +59.3331, 5.70 }, { 8823, 347.6942, -28.4750, 6.51 }, { 8824, 347.6775, +17.5944, 5.71 }, + { 8825, 347.6133, +43.5442, 5.94 }, { 8826, 347.9342, +8.7200, 5.16 }, { 8827, 347.9550, +26.8472, 6.17 }, { 8828, 348.3125, -48.3811, 6.80 }, + { 8829, 348.5275, -61.3000, 6.12 }, { 8830, 348.1375, +49.4064, 4.52 }, { 8831, 348.2667, +29.4417, 6.35 }, { 8832, 348.3208, +57.1683, 5.56 }, + { 8833, 348.3604, +11.0650, 5.82 }, { 8834, 348.5808, -5.9511, 4.22 }, { 8835, 348.7442, -40.8944, 5.77 }, { 8836, 348.6675, -9.3114, 6.12 }, + { 8837, 348.5596, +50.6178, 6.31 }, { 8838, 348.5904, +29.7717, 6.41 }, { 8839, 348.6521, +24.1031, 6.36 }, { 8840, 348.8929, -2.5036, 5.55 }, + { 8841, 348.9729, -8.9122, 4.21 }, { 8842, 348.9429, +28.2478, 6.49 }, { 8843, 349.2404, -61.9989, 5.66 }, { 8844, 348.6554, +74.2311, 5.84 }, + { 8845, 348.9912, +24.7711, 6.60 }, { 8846, 349.1654, -43.5108, 5.92 }, { 8847, 349.2075, -40.8056, 6.47 }, { 8848, 349.3575, -57.7642, 3.99 }, + { 8849, 349.7838, -78.5272, 6.33 }, { 8850, 349.2121, -6.2733, 5.06 }, { 8851, 348.9075, +70.8881, 5.56 }, { 8852, 349.2912, +3.2822, 3.69 }, + { 8853, 349.1762, +53.2136, 5.54 }, { 8854, 349.1117, +61.9631, 6.53 }, { 8855, 349.5833, -66.5289, 6.13 }, { 8856, 349.4167, -10.2869, 6.34 }, + { 8857, 349.3192, +45.1642, 6.43 }, { 8858, 349.4758, -8.8175, 4.39 }, { 8859, 349.5412, -39.1756, 5.53 }, { 8860, 349.4362, +49.0153, 4.85 }, + { 8861, 349.4837, +45.4889, 6.48 }, { 8862, 352.0154, -86.5178, 5.49 }, { 8863, 349.7058, -31.4681, 4.41 }, { 8864, 349.5975, +41.7736, 6.02 }, + { 8865, 349.7404, -8.3892, 4.98 }, { 8866, 349.7779, -12.5411, 5.08 }, { 8867, 349.3288, +75.2992, 6.38 }, { 8868, 349.8500, -4.8756, 5.55 }, + { 8869, 349.8504, -17.9247, 5.93 }, { 8870, 349.7600, +45.1372, 6.50 }, { 8871, 349.9300, -32.2919, 6.37 }, { 8872, 349.6563, +68.1117, 4.75 }, + { 8873, 349.8642, +34.7933, 6.32 }, { 8874, 349.8742, +48.6253, 5.44 }, { 8875, 349.9233, +48.3808, 6.32 }, { 8876, 349.9683, +42.0781, 5.79 }, + { 8877, 350.2083, -49.6933, 6.05 }, { 8878, 350.0858, +5.3814, 5.05 }, { 8879, 350.1704, -4.0919, 6.17 }, { 8880, 350.1592, +23.7403, 4.60 }, + { 8881, 350.0596, +61.9700, 6.45 }, { 8882, 350.2067, +30.4150, 5.59 }, { 8883, 350.3146, -25.0133, 5.64 }, { 8884, 350.1833, +44.1164, 6.13 }, + { 8885, 350.2221, +38.1822, 5.77 }, { 8886, 350.1442, +62.2131, 6.39 }, { 8887, 350.4787, +31.8125, 5.32 }, { 8888, 350.4925, +26.6089, 6.62 }, + { 8889, 350.7371, -59.9442, 6.09 }, { 8890, 350.6633, -14.9608, 5.20 }, { 8891, 350.6687, +20.8286, 6.29 }, { 8892, 350.7425, -19.8994, 3.97 }, + { 8893, 350.7692, +12.3139, 5.08 }, { 8894, 350.6354, +60.1336, 5.56 }, { 8895, 350.9762, -52.1917, 6.15 }, { 8896, 350.9392, -42.8756, 6.10 }, + { 8897, 350.8829, +0.2914, 6.31 }, { 8898, 351.0546, -50.1086, 5.75 }, { 8899, 350.9479, +32.5314, 6.69 }, { 8900, 351.0325, -17.3125, 6.19 }, + { 8901, 351.3308, -55.1508, 5.59 }, { 8902, 351.1458, +41.1128, 6.72 }, { 8903, 351.2117, +32.3850, 5.57 }, { 8904, 351.2096, +62.2828, 4.98 }, + { 8905, 351.3450, +23.4042, 4.40 }, { 8906, 351.5117, -19.3581, 4.39 }, { 8907, 351.6525, -51.2783, 5.52 }, { 8908, 351.7800, -65.4189, 6.45 }, + { 8909, 351.8125, -57.5239, 5.63 }, { 8910, 351.7879, -49.8428, 6.20 }, { 8911, 351.7333, +1.2556, 4.94 }, { 8912, 351.8117, +1.1225, 6.25 }, + { 8913, 351.7808, +42.9119, 5.75 }, { 8914, 352.0029, -34.4556, 6.32 }, { 8915, 351.9183, +25.1672, 5.98 }, { 8916, 351.9921, +6.3789, 4.28 }, + { 8917, 352.0217, -10.5503, 6.37 }, { 8918, 351.8192, +70.3597, 5.60 }, { 8919, 352.2542, -62.8892, 5.68 }, { 8920, 352.2533, -43.5022, 6.43 }, + { 8921, 352.2525, -8.7339, 6.18 }, { 8922, 352.2733, +23.0478, 6.35 }, { 8923, 352.2887, +12.7606, 4.55 }, { 8924, 352.3838, -3.4672, 6.25 }, + { 8925, 352.5308, +49.1331, 6.17 }, { 8926, 352.5083, +58.5489, 4.91 }, { 8927, 352.6654, +38.6619, 6.05 }, { 8928, 352.7546, -5.7117, 6.39 }, + { 8929, 352.8625, -43.1564, 6.02 }, { 8930, 352.8225, +39.2364, 5.22 }, { 8931, 352.8813, -3.9128, 6.49 }, { 8932, 352.9254, -20.6306, 6.29 }, + { 8933, 352.9296, +28.4036, 6.41 }, { 8934, 352.9900, -0.9142, 6.38 }, { 8935, 353.3313, -76.6147, 5.81 }, { 8936, 353.1025, +34.9525, 6.65 }, + { 8937, 353.2429, -36.1817, 4.37 }, { 8938, 351.7533, +87.3075, 5.58 }, { 8939, 353.3192, -19.0856, 4.71 }, { 8940, 353.3671, +22.4989, 5.32 }, + { 8941, 353.4279, +45.0581, 6.24 }, { 8942, 353.4812, +20.8408, 6.06 }, { 8943, 353.4883, +31.3253, 4.98 }, { 8944, 353.5375, -0.7525, 5.87 }, + { 8945, 353.8029, -63.3106, 7.40 }, { 8946, 353.7058, -14.7542, 5.96 }, { 8947, 353.6563, +40.2364, 5.59 }, { 8948, 353.6592, +33.4972, 5.63 }, + { 8949, 353.7692, -41.3850, 4.71 }, { 8950, 353.6946, +38.0239, 6.18 }, { 8951, 353.8838, -6.5356, 6.39 }, { 8952, 353.7458, +71.6422, 5.84 }, + { 8953, 353.9829, +24.5611, 6.45 }, { 8954, 354.0971, +2.1022, 5.68 }, { 8955, 354.1271, +32.9042, 6.35 }, { 8956, 354.2725, -30.1292, 6.52 }, + { 8957, 354.6004, -75.1300, 6.00 }, { 8958, 354.4150, -12.9397, 5.65 }, { 8959, 354.4625, -44.5075, 4.74 }, { 8960, 354.4158, +16.8256, 6.26 }, + { 8961, 354.3913, +46.4581, 3.82 }, { 8962, 354.3833, +44.4292, 5.80 }, { 8963, 354.4867, +18.4006, 5.53 }, { 8964, 354.4942, +46.1997, 6.58 }, + { 8965, 354.5342, +43.2681, 4.29 }, { 8966, 354.8667, -45.3622, 6.09 }, { 8967, 354.7846, +50.4717, 5.30 }, { 8968, 354.9463, -13.7783, 5.00 }, + { 8969, 354.9875, +5.6264, 4.13 }, { 8970, 354.9796, +9.6772, 5.97 }, { 8971, 354.7933, +75.2928, 5.95 }, { 8972, 354.8379, +74.0028, 5.98 }, + { 8973, 355.0117, +37.6525, 6.53 }, { 8974, 354.8367, +77.6325, 3.21 }, { 8975, 355.1592, -31.9269, 5.31 }, { 8976, 355.1021, +44.3339, 4.14 }, + { 8977, 355.1692, +36.7208, 6.23 }, { 8978, 355.2792, -23.8397, 6.60 }, { 8979, 355.2871, -10.3194, 5.89 }, { 8980, 355.3938, -17.9728, 5.34 }, + { 8981, 355.3621, +49.5122, 6.26 }, { 8982, 355.4408, -16.1836, 4.82 }, { 8983, 355.4862, +7.2506, 5.89 }, { 8984, 355.5117, +1.7800, 4.50 }, + { 8985, 355.4771, +57.2600, 6.24 }, { 8986, 355.5617, +44.9919, 6.57 }, { 8987, 355.6162, -14.5522, 5.28 }, { 8988, 355.6804, -13.4550, 4.49 }, + { 8989, 355.5867, +64.5156, 6.56 }, { 8990, 355.6313, +61.6794, 6.40 }, { 8991, 355.8433, +10.3314, 5.06 }, { 8992, 355.9563, -14.7156, 6.36 }, + { 8993, 356.0058, -44.9167, 6.09 }, { 8994, 356.1058, -69.5097, 6.07 }, { 8995, 356.1696, -77.2086, 5.75 }, { 8996, 356.0500, -63.5956, 5.72 }, + { 8997, 355.9979, +29.3617, 4.93 }, { 8998, 356.0504, -17.7231, 5.24 }, { 8999, 356.1204, -25.7536, 6.17 }, { 9000, 356.2013, +55.7997, 6.51 }, + { 9001, 356.5050, -39.8175, 6.31 }, { 9002, 356.5038, -17.3219, 5.29 }, { 9003, 356.5088, +46.4203, 4.95 }, { 9004, 356.5979, +3.4867, 5.04 }, + { 9005, 356.6529, +66.7822, 5.95 }, { 9006, 356.8167, -49.7733, 5.18 }, { 9007, 356.8471, -67.6058, 6.89 }, { 9008, 356.7646, +58.6519, 4.87 }, + { 9009, 356.8163, -10.0892, 5.73 }, { 9010, 356.7579, +57.4514, 5.51 }, { 9011, 356.8883, +46.8325, 6.07 }, { 9012, 356.9854, -1.2383, 5.49 }, + { 9013, 356.9783, +67.8069, 5.04 }, { 9014, 357.1354, -5.6194, 6.07 }, { 9015, 357.2054, +2.2142, 6.46 }, { 9016, 357.2317, -27.8697, 4.57 }, + { 9017, 357.1625, +64.8764, 6.41 }, { 9018, 357.2092, +62.2144, 5.43 }, { 9019, 357.2246, +59.9789, 6.34 }, { 9020, 357.3000, +58.9631, 6.33 }, + { 9021, 357.3817, -14.1389, 6.24 }, { 9022, 357.3646, +1.0761, 5.77 }, { 9023, 357.4362, -61.1606, 6.59 }, { 9024, 357.4208, +36.4253, 5.90 }, + { 9025, 357.4142, +28.8425, 5.97 }, { 9026, 357.4567, -24.6686, 6.42 }, { 9027, 357.5612, -8.0258, 5.94 }, { 9028, 357.5929, +51.6217, 6.44 }, + { 9029, 357.6388, -13.5981, 5.72 }, { 9030, 357.8383, +9.3133, 5.79 }, { 9031, 357.8388, -17.0911, 5.18 }, { 9032, 358.0267, -81.9811, 5.11 }, + { 9033, 357.9912, +2.9303, 5.55 }, { 9034, 357.9900, +77.5994, 6.55 }, { 9035, 358.0975, +21.6708, 6.11 }, { 9036, 358.1221, +19.1203, 5.08 }, + { 9037, 358.1250, -13.7489, 5.87 }, { 9038, 358.1046, +75.5447, 6.39 }, { 9039, 358.1546, +10.9475, 5.30 }, { 9040, 358.2104, -7.0033, 5.75 }, + { 9041, 358.2317, -2.8444, 5.93 }, { 9042, 358.2700, +2.0906, 6.28 }, { 9043, 358.3367, -23.7708, 6.24 }, { 9044, 358.5892, -26.9578, 6.35 }, + { 9045, 358.5958, +57.4994, 4.54 }, { 9046, 358.6608, -39.7000, 6.03 }, { 9047, 358.6942, +0.1092, 5.61 }, { 9048, 358.7825, +7.0711, 6.21 }, + { 9049, 358.8192, -30.0783, 6.10 }, { 9050, 358.8192, -30.1158, 6.83 }, { 9051, 358.8458, +25.9550, 6.54 }, { 9052, 358.8904, +57.4122, 6.00 }, + { 9053, 358.8900, +47.3558, 6.00 }, { 9054, 359.1246, -23.2628, 6.31 }, { 9055, 359.1729, +22.6481, 6.15 }, { 9056, 359.1154, +83.1911, 6.59 }, + { 9057, 359.2650, +42.6583, 5.97 }, { 9058, 359.2846, -25.3764, 6.26 }, { 9059, 359.2854, +55.7058, 5.55 }, { 9060, 359.3329, -61.0436, 5.97 }, + { 9061, 359.3863, -81.8300, 5.73 }, { 9062, 359.3967, -63.7017, 5.00 }, { 9063, 359.3896, +60.0236, 6.47 }, { 9064, 359.4396, +25.1414, 4.66 }, + { 9065, 359.5883, -14.1525, 6.26 }, { 9066, 359.6033, +51.3886, 4.80 }, { 9067, 359.6683, -2.4439, 4.86 }, { 9068, 359.7050, +32.3817, 6.52 }, + { 9069, 359.7325, -51.2542, 5.13 }, { 9070, 359.6938, +46.4131, 6.54 }, { 9071, 359.7521, +55.7550, 4.88 }, { 9072, 359.8279, +6.8633, 4.01 }, + { 9073, 359.8662, -28.5150, 5.62 }, { 9074, 359.8717, +33.7244, 6.58 }, { 9075, 359.8717, +33.7244, 6.58 }, { 9076, 359.9792, -64.4228, 4.50 }, + { 9077, 0.0800, -43.7094, 6.29 }, { 9078, 0.0996, +26.9183, 6.46 }, { 9079, 0.1288, +59.5597, 6.19 }, { 9080, 0.1821, +45.2533, 6.38 }, + { 9081, 0.2687, -47.1900, 5.71 }, { 9082, 0.3333, -49.6628, 5.53 }, { 9083, 0.3304, +49.9817, 6.22 }, { 9084, 0.3987, -76.9342, 4.78 }, + { 9085, 0.4038, +61.2231, 5.55 }, { 9086, 0.4325, +42.3672, 6.25 }, { 9087, 0.4558, -2.9725, 5.10 }, { 9088, 0.5425, +27.0819, 5.75 }, + { 9089, 0.4900, -5.9858, 4.41 }, { 9090, 0.5304, -13.3239, 7.10 }, { 9091, 0.5829, -28.2797, 5.01 }, { 9092, 0.6008, +8.9569, 6.32 }, + { 9093, 0.6238, +8.4856, 5.63 }, { 9094, 0.6504, +66.0989, 5.86 }, { 9095, 0.7400, -19.9539, 6.25 }, { 9096, 0.7821, -23.8547, 6.44 }, + { 9097, 0.8571, +63.6419, 6.24 }, { 9098, 0.9350, -16.6639, 4.55 }, { 9099, 0.9662, +66.7122, 6.29 }, { 9100, 1.0567, +62.2878, 5.88 }, + { 9101, 1.0821, -15.4711, 5.78 }, { 9102, 1.0846, -28.7314, 6.40 }, { 9103, 1.1254, -9.4906, 4.94 }, { 9104, 1.1750, +67.1667, 5.67 }, + { 9105, 1.1529, +42.0922, 6.01 }, { 9106, 1.1279, -71.1022, 7.31 }, { 9107, 1.2242, +34.6597, 6.12 }, { 9108, 1.1721, -70.5631, 5.59 }, + { 9109, 1.2333, +26.6489, 6.25 }, { 9110, 1.2758, +61.3142, 5.80 }, { 9110, 1.2758, +61.3142, 5.80 }, { 0, 0.0, 0.0, 0.0 }, +}; + +const basicStarData * get_bright_star(int index) { + return &brightstars[index]; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utils/star.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,39 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef STAR_H +#define STAR_H + +#define SEARCH_BOX 3.0 + +typedef struct _basicStarData { + uint16_t hr; + float ra; + float dec; + float mag; +} basicStarData; + +const basicStarData * get_bright_star(int index); +basicStarData * star_closest(RaDec *radec, basicStarData *star); + + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utils/stations.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,116 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#include "stations.h" + +/** COSPAR observing stations around the World. + */ +const STATION_t stations[] = { + + { 2010, "MM", 30.3340, -97.7610, 160., "5105 Crestway Dr." }, + { 2011, "MM", 30.3150, -97.8661, 300., "Bee Caves Rsrch Ctr" }, + { 2420, "RE", 55.9486, -3.1386, 40., "Russell Eberst" }, + { 2675, "DB", 52.1358, -2.3264, 70., "David Brierley" }, + { 2676, "DB", 52.1273, -2.3365, 107., "David Brierley" }, + { 2018, "PW", 51.0945, -1.1188, 150., "Peter Wakelin" }, + { 2701, "TM", 43.6876, -79.3924, 230., "Ted Molczan" }, + { 3022, "JC", 48.7389, 3.4589, 52., "Jean-Paul Cornec" }, + { 5917, "BG", 59.3418, 18.0545, 33., "Bjorn Gimle" }, + { 5918, "BG", 59.2985, 18.1045, 44., "Bjorn Gimle" }, + { 5919, "BG", 59.2615, 18.6206, 33., "Bjorn Gimle" }, + { 9987, "BF", 59.3418, 18.0545, 30., "Bjorn Gimle" }, + { 100, "SG", 59.4628, 17.9137, 30., "Sven Grahn" }, + { 8305, "PG", 26.2431, -98.2163, 30., "Paul Gabriel" }, + { 2563, "PN", 51.0524, 2.4043, 10., "Pierre Nierinck" }, + { 6226, "SC", 28.4861, -97.8194, 110., "Scott Campbell" }, + { 8539, "SN", 39.4707, -79.3388, 839., "Steve Newcomb" }, + { 2751, "BM", 51.3440, -1.9849, 125., "Bruce MacDonald" }, + { 2756, "AK", 56.0907, -3.1623, 25., "Andy Kirkham" }, /* wow, that's me! Shame I no longer live there. */ + { 433, "GR", -33.9406, 18.5129, 10., "Greg Roberts" }, + { 4541, "AR", 41.9639, 12.4531, 80., "Alberto Rango" }, + { 4542, "AR", 41.9683, 12.4545, 80., "Alberto Rango" }, + { 4641, "AR", 41.1060, 16.9010, 70., "Alberto Rango" }, + { 2115, "MW", 51.3286, 0.7950, 75., "Mike Waterman" }, + { 1775, "KF", 44.6062, -75.6910, 200., "Kevin Fettner" }, + { 1747, "DD", 45.7275, -72.3526, 191., "Daniel Deak" }, + { 8597, "TB", -34.9638, 138.6333, 100., "Tony Beresford" }, + { 8730, "EC", 30.3086, -97.7279, 150., "Ed Cannon" }, + { 9730, "MM", 30.3150, -97.8660, 280., "BCRC (0002)" }, + { 4353, "ML", 52.1541, 4.4908, 0., "Marco Langbroek" }, + { 4354, "ML", 52.1168, 4.5602, -2., "Marco Langbroek" }, + { 710, "LS", 52.3261, 10.6756, 85., "Lutz Schindler" }, + { 1056, "MK", 57.0122, 23.9833, 4., "Martins Keruss" }, + { 110, "LK", 32.5408, -96.8906, 200., "Lyn Kennedy" }, + { 11, "VA", 44.7269, 34.0167, 580., "Crimea Astrophysical Observ." }, + { 70, "BC", 53.2233, -0.6003, 30., "Bob Christy" }, + { 8335, "BY", 35.8311, -96.1471, 335., "Brad Young" }, + { 8336, "BY", 36.1397, -95.9838, 205., "Brad Young" }, + { 8337, "BY", 36.9557, -96.5518, 395., "Brad Young" }, + { 4160, "BD", 51.2793, 5.4768, 35., "Bram Dorreman" }, + { 9011, "RM", 50.9310, 2.4053, 72., "Richard Miles" }, + { 20, "PM", 50.7453, 2.1107, 70., "Paul Marsh" }, + { 40, "IR", 50.7453, 2.1107, 70., "Ian Roberts" }, + { 90, "RF", 50.7453, 2.1107, 70., "Richard Flagg" }, + { 1, "AK", 56.1923, -3.0340, 53., "SOWB Test Station" }, /* Used for testing the SOWB. */ + { 0, "uk", 0.0000, 0.0000, 0., "Unknown station location" } /* Always the last entry. */ +}; + +/** cospar_station_at + * + * Given a latitude and longitude is the point within a +/-0.0005 degree + * box of a given station? If so, return a handle (array index) for that + * station. + * + * @param double latitude + * @param double longitude + * @return int index + */ +int cospar_station_at(double latitude, double longitude) { + int i; + double high, low; + + for (i = 0; stations[i].cospar != 0; i++) { + high = stations[i].latitude + 0.0005; + low = stations[i].latitude - 0.0005; + if (latitude <= high && latitude >= low) { + high = stations[i].longitude + 0.0005; + low = stations[i].longitude - 0.0005; + if (longitude <= high && longitude >= low) { + return i; + } + } + } + + return i; +} + +/** station + * + * Given an array index value, return a pointer to the station information structure. + * The proceedure is basically a look-up opertaion. + * + * @param int index + * @return STATION_t * + */ +const STATION_t * cospar_station(int index) { + return &stations[index]; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utils/stations.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,39 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef STATION_H +#define STATION_H + +typedef struct _station_t { + int cospar; + char short_name[3]; + double latitude; + double longitude; + double hasl; + char long_name[32]; +} STATION_t; + + +int cospar_station_at(double latitude, double longitude); +const STATION_t * cospar_station(int index); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utils/utils.c Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,321 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + + +#include "sowb.h" +#include "ctype.h" +#include "utils.h" +#include "gps.h" +#include "debug.h" + +/** ascii2bin + * + * Converts an ascii char to binary nibble. + * + * @param char The character to convert [0-9][a-f][A-F] + * @return char the bin value or -1 on invalid hex char. + */ +char ascii2bin(char c) { + if (c >= '0' && c <= '9') return (c - '0') & 0xF; + if (c >= 'A' && c <= 'F') return (c - 'A' + 10) & 0xF; + if (c >= 'a' && c <= 'f') return (c - 'a' + 10) & 0xF; + return (char)0xFF; +} + +/** hex2bin + * + * Converts a hex ascii string to binary int. + * + * Note, no error checking, assume string is valid hex chars [0-9][a-f][A-F] + * + * @param char *s The string to convert. + * @param int len The length of the string to convert. + * @return uint32_t the converted value. + */ +uint32_t hex2bin(char *s, int len) { + int i; + uint32_t rval; + + for (rval = 0, i = 0; i < len; i++) rval = rval | (ascii2bin(*(s + i)) << ((len - i - 1) * 4)); + + return rval; +} + +/** bin2ascii + * + * Convert a nibble to an ASCII character + * + * @param char c The nibble to convert + * @return char The character representation of the nibble. + */ +char bin2ascii(char c) { + c &= 0xF; + if (c < 0xA) return c + '0'; + return c + 'A' - 10; +} + +/** bin2hex + * + * Convert a binary to a hex string representation. + * The caller should allocate a buffer for *s before + * calling this function. The allocation should be + * len + 1 in length to hold the string and the + * terminating null character. + * + * @param uint32_t d The value to convert. + * @param int len The string length. + * @param char *s Where to put the string. + * @return char * Returns *s passed in. + */ + // 238E,238E + // O832,O832 + +char * bin2hex(uint32_t d, int len, char *s) { + char c, i = 0; + *(s + len) = '\0'; + while (len) { + c = (d >> (4 * (len - 1))) & 0xF; + *(s + i) = bin2ascii(c); + len--; i++; + } + return s; +} + +/** dec2bin + * + * Converts a decimal ascii string to binary int. + * + * Note, no error checking, assume string is valid hex chars [0-9] + * + * @param char *s The string to convert. + * @param int len The length of the string to convert. + * @return uint32_t the converted value. + */ +uint32_t dec2bin(char *s, int len) { + int i, mul; + uint32_t rval = 0; + + for (mul = 1, i = len; i; i--, mul *= 10) rval += (ascii2bin(*(s + i - 1)) * mul); + + return rval; +} + +/** strcsuml + * + * Return a two's compliment checksum char for th esupplied string. + * + * @param char * s The string to sum + * @param int len The length of the string. + * @return The two's compliment char. + */ +char strcsuml(char *s, int len) { + char sum = 0; + while (len) { + sum += *(s +len - 1); + } + return (~sum) + 1; +} + +/** strcsum + * + * Return a two's compliment checksum char for the null terminated supplied string. + * + * @param char * s The string to sum + * @return The two's compliment char. + */ +char strcsum(char *s) { + return strcsuml(s, strlen(s)); +} + +/** strsuml + * + * Return the 8bit sum char for the supplied string. + * + * @param char * s The string to sum + * @param int len The length of the string. + * @return The sum + */ +char strsuml(char *s, int len) { + char sum = 0; + while (len) { + sum += *(s +len - 1); + } + return sum; +} + +/** strsum + * + * Return the 8bit sum of all the characters of the supplied string. + * + * @param char * s The string to sum + * @return The sum + */ +char strsum(char *s) { + return strsuml(s, strlen(s)); +} + +/* Used for the date_AsString function. */ +const char month_abv[][4] = { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","Wtf" }; + +/** date_AsString + * + * Used to get the current date and return a formatted string. + * Note, the caller must have a 12byte buffer in place, pointed + * to by s to accept the string. + * + * @param GPS_TIME *t A pointer to the time data struct to "print as" + * @param char *s A pointer to a buffer to hold the formatted string. + */ +void date_AsString(GPS_TIME *t, char *s) { + int month = t->month - 1; if (month > 11 || month < 0) month = 12; /* Ensure in range. */ + sprintf(s, "%4.4d/%s/%2.2d", t->year, month_abv[month], t->day); +} + +/** time_AsString + * + * Used to get the current time and return a formatted string. + * Note, the caller must have a 12byte buffer in place, pointed + * to by s to accept the string. + * + * @param GPS_TIME *t A pointer to the time data struct to "print as" + * @param char *s A pointer to a buffer to hold the formatted string. + */ +void time_AsString(GPS_TIME *t, char *s) { + sprintf(s, "%2.2d:%2.2d:%2.2d.%1.1d%1.1d", t->hour, t->minute, t->second, t->tenth, t->hundreth); +} + +/** double2dms + * + * Takes double and converts it to a printable display string of + * degrees, minutes and seconds. + * The caller is responsible for allocating the buffer *s before + * calling this function. + * + * @param char *s A pointer to the buffer to print to. + * @param double d The value to print. + */ +void double2dms(char *s, double d) { + int degrees, minutes; + double seconds, t; + + degrees = (int)d; t = (d - (double)degrees) * 60.; + minutes = (int)t; + seconds = (t - (double)minutes) * 60.; + + sprintf(s, "%03d\xb0%02d\x27%02d\x22", degrees, minutes, (int)seconds); +} + +/** printDouble + * + * Print a double to a string buffer with correct leading zero(s). + * The caller is responsible for allocating the buffer *s before + * calling this function. + * + * @param char *s A pointer to the buffer to print to. + * @param double d The value to print. + */ +void printDouble(char *s, double d) { + if (isnan(d)) sprintf(s, "---.----"); + else if (d > 100.) sprintf(s, "%.4f", d); + else if (d > 10.) sprintf(s, "0%.4f", d); + else sprintf(s, "00%.4f", d); +} + +/** printDouble_3_1 + * + * Print a double to a string buffer with correct leading zero(s). + * The caller is responsible for allocating the buffer *s before + * calling this function. + * + * @param char *s A pointer to the buffer to print to. + * @param double d The value to print. + */ +char * printDouble_3_1(char *s, double d) { + char temp[16]; + if (isnan(d)) sprintf(temp, "---.-"); + else if (d > 100.) sprintf(temp, "%.6f", d); + else if (d > 10.) sprintf(temp, "0%.6f", d); + else sprintf(temp, "00%.6f", d); + memcpy(s, temp, 5); + *(s+5) = '\0'; + return s; +} + +/** printDouble_3_2 + * + * Print a double to a string buffer with correct leading zero(s). + * The caller is responsible for allocating the buffer *s before + * calling this function. + * + * @param char *s A pointer to the buffer to print to. + * @param double d The value to print. + */ +char * printDouble_3_2(char *s, double d) { + char temp[16]; + if (isnan(d)) sprintf(temp, "---.--"); + else if (d > 100.) sprintf(temp, "%.6f", d); + else if (d > 10.) sprintf(temp, "0%.6f", d); + else sprintf(temp, "00%.6f", d); + memcpy(s, temp, 6); + *(s+6) = '\0'; + return s; +} + +void printBuffer(char *s, int len) { + #ifdef DEBUG_ON + for (int i = 0; i < len / 0x10; i++) { + debug_printf("%02X: ", i); + for (int j = 0; j < 0x10; j++) { + debug_printf("%02X ", s[(i * 0x10) + j]); + if (j == 7) debug_printf(" "); + } + for (int j = 0; j < 0x10; j++) { + if (isprint(s[(i * 0x10) + j])) { + debug_printf("%c", s[(i * 0x10) + j]); + } + else { + debug_printf("."); + } + if (j == 7) debug_printf(" "); + } + debug_printf("\r\n"); + } + #endif +} + +inline void disable_irqs(void) { + NVIC_DisableIRQ(EINT3_IRQn); + NVIC_DisableIRQ(RIT_IRQn); + NVIC_DisableIRQ(UART0_IRQn); + NVIC_DisableIRQ(UART1_IRQn); + NVIC_DisableIRQ(UART2_IRQn); + NVIC_DisableIRQ(USB_IRQn); +} + +inline void enable_irqs(void) { + NVIC_EnableIRQ(USB_IRQn); + NVIC_EnableIRQ(EINT3_IRQn); + NVIC_EnableIRQ(RIT_IRQn); + NVIC_EnableIRQ(UART0_IRQn); + NVIC_EnableIRQ(UART1_IRQn); + NVIC_EnableIRQ(UART2_IRQn); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utils/utils.h Mon Oct 11 10:34:55 2010 +0000 @@ -0,0 +1,52 @@ +/**************************************************************************** + * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd + * + * This file is part of the Satellite Observers Workbench (SOWB). + * + * SOWB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * SOWB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with SOWB. If not, see <http://www.gnu.org/licenses/>. + * + * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ + * + ***************************************************************************/ + +#ifndef UTILS_H +#define UTILS_H + +#include "gps.h" + +char ascii2bin(char c); +uint32_t hex2bin(char *s, int len); +uint32_t dec2bin(char *s, int len); + +char bin2ascii(char c); +char * bin2hex(uint32_t d, int len, char *s); + +char strcsum(char *s); +char strcsuml(char *s, int len); + +char strsum(char *s); +char strsuml(char *s, int len); + +void date_AsString(GPS_TIME *t, char *s); +void time_AsString(GPS_TIME *t, char *s); + +void gps_get_coord_AsString(char *s, int type); + +void double2dms(char *s, double d); +void printDouble(char *s, double d); +char * printDouble_3_1(char *s, double d); +char * printDouble_3_2(char *s, double d); + +void printBuffer(char *s, int len); +#endif