From 4ae540b6366d124272a9aef6ac10fbd3ba029356 Mon Sep 17 00:00:00 2001 From: losehu Date: Tue, 28 Jan 2025 22:15:40 +0800 Subject: [PATCH] new --- .idea/.gitignore | 8 + .idea/editor.xml | 588 ++++++++++++++++++++++++++++++++++++++++ .idea/misc.xml | 18 ++ .idea/vcs.xml | 6 + Makefile | 65 +++-- app/spectrum.c | 12 +- board.c | 10 +- bsp/dp32g030/rtc.h | 2 +- compile-with-docker.bat | 1 - del_linux.sh | 2 +- driver/rtc.c | 4 +- main.c | 255 ++++++----------- tle/astrotime.c | 35 +++ tle/astrotime.h | 45 +++ tle/eci.c | 117 ++++++++ tle/eci.h | 58 ++++ tle/sgp.c | 207 ++++++++++++++ tle/sgp.h | 18 ++ tle/tle.c | 358 ++++++++++++++++++++++++ tle/tle.h | 75 +++++ tle/util.c | 84 ++++++ tle/util.h | 92 +++++++ tle/vec.c | 16 ++ tle/vec.h | 32 +++ ui/main.c | 2 +- win_make.bat | 6 +- 26 files changed, 1889 insertions(+), 227 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/editor.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/vcs.xml create mode 100644 tle/astrotime.c create mode 100644 tle/astrotime.h create mode 100644 tle/eci.c create mode 100644 tle/eci.h create mode 100644 tle/sgp.c create mode 100644 tle/sgp.h create mode 100644 tle/tle.c create mode 100644 tle/tle.h create mode 100644 tle/util.c create mode 100644 tle/util.h create mode 100644 tle/vec.c create mode 100644 tle/vec.h diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 00000000..35410cac --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/editor.xml b/.idea/editor.xml new file mode 100644 index 00000000..7b63cd04 --- /dev/null +++ b/.idea/editor.xml @@ -0,0 +1,588 @@ + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..53624c9e --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,18 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..35eb1ddf --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Makefile b/Makefile index 2893ef52..f72a5403 100644 --- a/Makefile +++ b/Makefile @@ -9,40 +9,40 @@ ENABLE_SWD ?= 1 ENABLE_OVERLAY ?= 0 ENABLE_LTO ?= 1 -# ---- STOCK QUANSHENG FERATURES ---- +# ---- STOCK QUANSHENG FERATURfvzES ---- ENABLE_UART ?= 1 ENABLE_AIRCOPY ?= 0 ENABLE_FMRADIO = 0 ENABLE_NOAA ?= 0 ENABLE_VOICE ?= 0 -ENABLE_VOX ?= 1 +ENABLE_VOX ?= 0 ENABLE_ALARM ?= 0 ENABLE_TX1750 ?= 0 ENABLE_PWRON_PASSWORD ?= 0 ENABLE_DTMF_CALLING ?= 1 -ENABLE_FLASHLIGHT ?= 1 +ENABLE_FLASHLIGHT ?= 0 ENABLE_BOOTLOADER ?= 0 # ---- CUSTOM MODS ---- ENABLE_BIG_FREQ ?= 1 -ENABLE_KEEP_MEM_NAME ?= 1 -ENABLE_WIDE_RX ?= 1 +ENABLE_KEEP_MEM_NAME ?= 0 +ENABLE_WIDE_RX ?= 0 ENABLE_TX_WHEN_AM ?= 0 ENABLE_F_CAL_MENU ?= 0 ENABLE_CTCSS_TAIL_PHASE_SHIFT ?= 0 ENABLE_BOOT_BEEPS ?= 0 ENABLE_SHOW_CHARGE_LEVEL ?= 0 ENABLE_REVERSE_BAT_SYMBOL ?= 0 -ENABLE_NO_CODE_SCAN_TIMEOUT ?= 1 -ENABLE_AM_FIX ?= 1 -ENABLE_SQUELCH_MORE_SENSITIVE ?= 1 -ENABLE_FASTER_CHANNEL_SCAN ?= 1 -ENABLE_RSSI_BAR ?= 1 -ENABLE_COPY_CHAN_TO_VFO ?= 1 +ENABLE_NO_CODE_SCAN_TIMEOUT ?= 0 +ENABLE_AM_FIX ?= 0 +ENABLE_SQUELCH_MORE_SENSITIVE ?= 0 +ENABLE_FASTER_CHANNEL_SCAN ?= 0 +ENABLE_RSSI_BAR ?= 0 +ENABLE_COPY_CHAN_TO_VFO ?= 0 ENABLE_SPECTRUM = 0 ENABLE_REDUCE_LOW_MID_TX_POWER?= 0 ENABLE_BYP_RAW_DEMODULATORS ?= 0 ENABLE_BLMIN_TMP_OFF ?= 0 -ENABLE_SCAN_RANGES ?= 1 +ENABLE_SCAN_RANGES ?= 0 ENABLE_MDC1200 = 0 ENABLE_MDC1200_SHOW_OP_ARG = 0 ENABLE_MDC1200_SIDE_BEEP = 0 @@ -54,8 +54,8 @@ ENABLE_EEPROM_TYPE = 0 ENABLE_CHINESE_FULL = 0 ENABLE_ENGLISH =0 ENABLE_DOCK ?= 0 -ENABLE_CUSTOM_SIDEFUNCTIONS ?= 1 -ENABLE_SIDEFUNCTIONS_SEND ?= 1 +ENABLE_CUSTOM_SIDEFUNCTIONS ?= 0 +ENABLE_SIDEFUNCTIONS_SEND ?= 0 ENABLE_BLOCK ?= 0 ENABLE_PINYIN =0 ENABLE_TURN ?=1 @@ -64,7 +64,7 @@ ENABLE_AM_FIX_SHOW_DATA ?= 0 ENABLE_AGC_SHOW_DATA ?= 0 ENABLE_TIMER ?= 0 -ENABLE_WARNING ?= 1 +ENABLE_WARNING ?= 0 ENABLE_MESSENGER = 0 ENABLE_MESSENGER_DELIVERY_NOTIFICATION = 0 ENABLE_MESSENGER_NOTIFICATION = 0 @@ -72,6 +72,7 @@ ENABLE_4732 =0 ENABLE_4732SSB =0 ENABLE_DOPPLER =0 +ENABLE_TLE = 1 ############################################################# PACKED_FILE_SUFFIX = LOSEHU132 ifeq ($(ENABLE_PINYIN),1) @@ -166,7 +167,15 @@ endif ifeq ($(ENABLE_DOPPLER),1) OBJS += driver/rtc.o endif +ifeq ($(ENABLE_TLE),1) + OBJS += tle/eci.o + OBJS += tle/sgp.o + OBJS += tle/vec.o + OBJS += tle/tle.o + OBJS += tle/astrotime.o + OBJS += tle/util.o +endif ifeq ($(ENABLE_MDC1200),1) OBJS += app/mdc1200.o endif @@ -288,7 +297,7 @@ AS = arm-none-eabi-gcc LD = arm-none-eabi-gcc ifeq ($(ENABLE_CLANG),0) - CC = arm-none-eabi-gcc + CC =arm-none-eabi-gcc # Use GCC's linker to avoid undefined symbol errors # LD += arm-none-eabi-gcc else @@ -298,7 +307,7 @@ else # LD = ld.lld endif -OBJCOPY = arm-none-eabi-objcopy +OBJCOPY =arm-none-eabi-objcopy SIZE = arm-none-eabi-size AUTHOR_STRING ?= LOSEHU @@ -345,7 +354,7 @@ endif #CFLAGS += -Wpadded # catch any and all warnings -CFLAGS += -Wextra +CFLAGS += -Wextra -fno-strict-aliasing #CFLAGS += -Wpedantic # 设置PACKED_FILE_SUFFIX,根据ENABLE_CHINESE_FULL的值设置不同的后缀 @@ -397,6 +406,10 @@ endif ifeq ($(ENABLE_DOPPLER),1) CFLAGS += -DENABLE_DOPPLER endif +ifeq ($(ENABLE_TLE),1) + CFLAGS += -DENABLE_TLE + +endif ifeq ($(ENABLE_4732),1) CFLAGS += -DENABLE_4732 endif @@ -596,12 +609,7 @@ endif full: $(RM) *.bin - $(MAKE) build ENABLE_CHINESE_FULL=0 ENABLE_ENGLISH=1 ENABLE_FMRADIO=1 ENABLE_MESSENGER=1 ENABLE_MESSENGER_DELIVERY_NOTIFICATION=1 ENABLE_MESSENGER_NOTIFICATION=1 ENABLE_SPECTRUM=1 ENABLE_MDC1200=1 ENABLE_MDC1200_EDIT=1 ENABLE_MDC1200_CONTACT=1 - $(MAKE) build ENABLE_CHINESE_FULL=4 ENABLE_ENGLISH=1 ENABLE_DOPPLER=1 ENABLE_SPECTRUM=1 ENABLE_FMRADIO=1 ENABLE_MDC1200=1 ENABLE_MDC1200_EDIT=1 ENABLE_MDC1200_CONTACT=1 - $(MAKE) build ENABLE_CHINESE_FULL=0 ENABLE_SPECTRUM=1 ENABLE_FMRADIO=1 ENABLE_MDC1200=1 ENABLE_MDC1200_EDIT=1 ENABLE_MDC1200_CONTACT=1 - $(MAKE) build ENABLE_CHINESE_FULL=4 ENABLE_DOPPLER=1 ENABLE_SPECTRUM=1 ENABLE_FMRADIO=1 ENABLE_MDC1200=1 ENABLE_MDC1200_EDIT=1 ENABLE_MDC1200_CONTACT=1 - $(MAKE) build ENABLE_CHINESE_FULL=4 ENABLE_DOPPLER=1 ENABLE_PINYIN=1 ENABLE_SPECTRUM=1 ENABLE_FMRADIO=1 - $(MAKE) build ENABLE_CHINESE_FULL=4 ENABLE_PINYIN=1 ENABLE_4732=1 ENABLE_4732SSB=1 ENABLE_SPECTRUM=1 + $(MAKE) build ENABLE_CHINESE_FULL=4 ENABLE_DOPPLER=0 ENABLE_PINYIN=0 ENABLE_SPECTRUM=0 ENABLE_FMRADIO=0 test: $(RM) *.bin @@ -640,15 +648,18 @@ flash: version.o: .FORCE $(TARGET): $(OBJS) - @$(LD) $(LDFLAGS) $^ -o $@ $(LIBS) + @$(LD) $(LDFLAGS) $^ -o $@ $(LIBS) -lc -g -lm + bsp/dp32g030/%.h: hardware/dp32g030/%.def %.o: %.c | $(BSP_HEADERS) - @$(CC) $(CFLAGS) $(INC) -c $< -o $@ + @$(CC) $(CFLAGS) $(INC) -c $< -o $@ -lc -g -lm + %.o: %.S - @$(AS) $(ASFLAGS) $< -o $@ + @$(AS) $(ASFLAGS) $< -o $@ -lc -g -lm + .FORCE: diff --git a/app/spectrum.c b/app/spectrum.c index b0ef09a1..1cf6bce3 100644 --- a/app/spectrum.c +++ b/app/spectrum.c @@ -1077,9 +1077,9 @@ static void OnKeyDownFreqInput(uint8_t key) { { - time[3]=tempFreq/100000; - time[4]=(tempFreq/1000)%100; - time[5]=(tempFreq/10)%100; + my_time[3]=tempFreq/100000; + my_time[4]=(tempFreq/1000)%100; + my_time[5]=(tempFreq/10)%100; RTC_Set(); SetState(previousState); @@ -1278,7 +1278,7 @@ static void Draw_DOPPLER_Process(uint8_t DATA_LINE) { else gFrameBuffer[6][i + 80] = 0b00100010; } - sprintf(String, "20%02d-%02d-%02d %02d:%02d:%02d", time[0], time[1], time[2], time[3], time[4], time[5]); + sprintf(String, "20%02d-%02d-%02d %02d:%02d:%02d", my_time[0], my_time[1], my_time[2], my_time[3], my_time[4], my_time[5]); GUI_DisplaySmallest(String, 1, DATA_LINE + 23, false, true); } @@ -1530,7 +1530,7 @@ static void Tick() { if (gNextTimeslice_500ms) { gNextTimeslice_500ms = false; - // if a lot of steps then it takes long time + // if a lot of steps then it takes long my_time // we don't want to wait for whole scan // listening has it's own timer if(GetStepsCount()>128 && !isListening) { @@ -1660,7 +1660,7 @@ void RTCHandler(void) { RTC_Get(); - int32_t NOW_UNIX_TIME = UNIX_TIME(time); + int32_t NOW_UNIX_TIME = UNIX_TIME(my_time); time_diff = satellite.START_TIME_UNIX - NOW_UNIX_TIME; //卫星开始时间-现在时间 time_diff1 = satellite.sum_time + time_diff;//结束-开始+开始-现在 diff --git a/board.c b/board.c index 8329d870..0c0abdc3 100644 --- a/board.c +++ b/board.c @@ -466,9 +466,7 @@ void BOARD_Init(void) { BACKLIGHT_InitHardware(); BOARD_ADC_Init(); ST7565_Init(); -#ifdef ENABLE_FMRADIO - BK1080_Init(0, false); -#endif + #if defined(ENABLE_UART) || defined(ENABLED_AIRCOPY) CRC_Init(); @@ -477,11 +475,11 @@ void BOARD_Init(void) { } void write_to_memory(uint32_t address, uint32_t data) { - // ֵַתΪָ + // ����ַ��ֵת��Ϊָ�� uint32_t *target_address = (uint32_t *) address; - // Ŀַд + // ��Ŀ���ַд������ *target_address = data; - // Ϊ˱Żȷ벻ᱻŻ + // Ϊ�˱����Ż���ȷ�����벻�ᱻ�Ż��� volatile uint32_t read_back = *target_address; } //JUMP_TO_FLASH(0xa10A,0x20003ff0); diff --git a/bsp/dp32g030/rtc.h b/bsp/dp32g030/rtc.h index 9975d54d..656a0045 100644 --- a/bsp/dp32g030/rtc.h +++ b/bsp/dp32g030/rtc.h @@ -39,6 +39,6 @@ void RTC_INIT(void); void RTC_Set( ); void RTC_Get(); -extern uint8_t time[6]; +extern uint8_t my_time[6]; #endif \ No newline at end of file diff --git a/compile-with-docker.bat b/compile-with-docker.bat index f9ef2742..5887156e 100644 --- a/compile-with-docker.bat +++ b/compile-with-docker.bat @@ -1,5 +1,4 @@ @echo on -make clean docker build -t uvk5 . docker run --rm -v %CD%\compiled-firmware:/app/compiled-firmware uvk5 /bin/bash -c "cd /app &&rm -rf compiled&& make clean && make full&& cp *.bin compiled-firmware/" pause diff --git a/del_linux.sh b/del_linux.sh index 09e59bde..bd163a6d 100644 --- a/del_linux.sh +++ b/del_linux.sh @@ -1,4 +1,4 @@ #!/bin/bash target_directory="./" -find "$target_directory" -type f \( -name "*.o" -o -name "*.d" \) -delete +find "$target_directory" -type f \( -name "*.o" -o -name "*.d" \) echo "Deletion complete." diff --git a/driver/rtc.c b/driver/rtc.c index 63946b81..2a2ef8b4 100644 --- a/driver/rtc.c +++ b/driver/rtc.c @@ -7,7 +7,7 @@ #include "driver/system.h" #include "ui/helper.h" -uint8_t time[6]; +uint8_t my_time[6]; void RTC_INIT() { @@ -19,7 +19,7 @@ void RTC_INIT() { | (0 << 24);//PRE_PERIOD=8s - EEPROM_ReadBuffer(0X2BC0, time, 6); + EEPROM_ReadBuffer(0X2BC0, my_time, 6); RTC_Set(); diff --git a/main.c b/main.c index bb34b348..31a9a0a5 100644 --- a/main.c +++ b/main.c @@ -13,7 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +#include +#include +#include +#include +#include +#include +#include "tle/eci.h" #include "bsp/dp32g030/gpio.h" #include "driver/gpio.h" #include "app/si.h" @@ -39,9 +45,8 @@ #include "app/uart.h" #include "string.h" #include "app/messenger.h" - +#include "time.h" #ifdef ENABLE_DOPPLER - #include "app/doppler.h" #endif @@ -94,7 +99,12 @@ #include "ui/menu.h" #include "driver/eeprom.h" #include "driver/st7565.h" - +#include +#include +#include +#include +#include +#include "tle/eci.h" void _putchar(__attribute__((unused)) char c) { #ifdef ENABLE_UART @@ -105,9 +115,8 @@ void _putchar(__attribute__((unused)) char c) { void Main(void) { - //BOOT_Mode_t BootMode; - // Enable clock gating of blocks we need + SYSCON_DEV_CLK_GATE = 0 | SYSCON_DEV_CLK_GATE_GPIOA_BITS_ENABLE | SYSCON_DEV_CLK_GATE_GPIOB_BITS_ENABLE @@ -117,197 +126,85 @@ void Main(void) { | SYSCON_DEV_CLK_GATE_SARADC_BITS_ENABLE | SYSCON_DEV_CLK_GATE_CRC_BITS_ENABLE | SYSCON_DEV_CLK_GATE_AES_BITS_ENABLE - | SYSCON_DEV_CLK_GATE_PWM_PLUS0_BITS_ENABLE - // | (1 << 12) -#ifdef ENABLE_DOPPLER - - | (1 << 22) -#endif - ; - + | SYSCON_DEV_CLK_GATE_PWM_PLUS0_BITS_ENABLE; SYSTICK_Init(); - BOARD_Init(); - - - -#ifdef ENABLE_UART UART_Init(); -#endif - - - memset(gDTMF_String, '-', sizeof(gDTMF_String)); - gDTMF_String[sizeof(gDTMF_String) - 1] = 0; - - BK4819_Init(); - - - BOARD_ADC_GetBatteryInfo(&gBatteryCurrentVoltage, &gBatteryCurrent); - - - SETTINGS_InitEEPROM(); - - - SETTINGS_LoadCalibration(); -#ifdef ENABLE_MESSENGER - MSG_Init(); -#endif -#ifdef ENABLE_MDC1200 - MDC1200_init(); -#endif -// char name[10]="START6789"; -// EEPROM_WriteBuffer(0x02BA0,name,10); -#ifdef ENABLE_DOPPLER - - RTC_INIT(); - INIT_DOPPLER_DATA(); -#endif - - RADIO_ConfigureChannel(0, VFO_CONFIGURE_RELOAD); - RADIO_ConfigureChannel(1, VFO_CONFIGURE_RELOAD); - - - RADIO_SelectVfos(); - - RADIO_SetupRegisters(true); - - for (uint32_t i = 0; i < ARRAY_SIZE(gBatteryVoltages); i++) { - BOARD_ADC_GetBatteryInfo(&gBatteryVoltages[i], &gBatteryCurrent); - } - BATTERY_GetReadings(false); -#ifdef ENABLE_AM_FIX - AM_fix_init(); -#endif - -#if ENABLE_CHINESE_FULL == 0 - gMenuListCount = 52; -#else - gMenuListCount = 53; -#endif - gKeyReading0 = KEY_INVALID; - gKeyReading1 = KEY_INVALID; - gDebounceCounter = 0; -//#ifdef ENABLE_4732 -// -// -// memset(gStatusLine, 0, sizeof(gStatusLine)); -// UI_DisplayClear(); -// ST7565_BlitStatusLine(); // blank status line -// ST7565_BlitFullScreen(); -//SI4732_Main(); -//#endif -#ifdef ENABLE_TIMER - - - BOARD_PORTCON_Init(); - BOARD_GPIO_Init(); - ST7565_Init(); - TIM0_INIT(); memset(gStatusLine, 0, sizeof(gStatusLine)); - UI_DisplayClear(); - ST7565_BlitStatusLine(); // blank status line + memset(gFrameBuffer, 0, sizeof(gFrameBuffer)); + ST7565_BlitStatusLine(); ST7565_BlitFullScreen(); - char str[20]={0}; // 分配一个足够大的字符串数组来存储转换后的字符串 - while(1) - { - char str[6]; - show_uint32(TIM0_CNT,0); - show_uint32(TIMERBASE0_LOW_CNT,1); - show_uint32(TIMERBASE0_HIGH_CNT,2); - show_uint32(TIMERBASE0_IF,3); - show_uint32(TIMERBASE0_IE,4); - } -#endif - UI_DisplayWelcome(); - -#ifdef ENABLE_BOOTLOADER - - - if(KEYBOARD_Poll() == KEY_MENU) -{ - for (int i = 0; i < 10*1024; i += 4) { - uint32_t c; - EEPROM_ReadBuffer(0x41000 + i, (uint8_t *) &c, 4); - write_to_memory(0x20001000 + i, c); - } - JUMP_TO_FLASH(0x2000110a, 0x20003ff0); -} -#endif - boot_counter_10ms = 250; - while (boot_counter_10ms > 0 || (KEYBOARD_Poll() != KEY_INVALID)) { - if (KEYBOARD_Poll() == KEY_EXIT -#if ENABLE_CHINESE_FULL == 4 - || gEeprom.POWER_ON_DISPLAY_MODE == POWER_ON_DISPLAY_MODE_NONE -#endif - ) { // halt boot beeps - boot_counter_10ms = 0; - break; - } -#ifdef ENABLE_BOOT_BEEPS - - if ((boot_counter_10ms % 25) == 0) - AUDIO_PlayBeep(BEEP_880HZ_40MS_OPTIONAL); -#endif - - } + GPIO_SetBit(&GPIOB->DATA, GPIOB_PIN_BACKLIGHT); + UI_PrintStringSmall("Boot OK", 0, 127, 2); + UI_PrintStringSmall("Release Key", 0, 127, 6); + ST7565_BlitStatusLine(); + ST7565_BlitFullScreen(); -#ifdef ENABLE_PWRON_PASSWORD - if (gEeprom.POWER_ON_PASSWORD < 1000000) - { - bIsInLockScreen = true; - UI_DisplayLock(); - bIsInLockScreen = false; - } -#endif - - // BOOT_ProcessMode(); - GUI_SelectNextDisplay(DISPLAY_MAIN); - - GPIO_ClearBit(&GPIOA->DATA, GPIOA_PIN_VOICE_0); - - gUpdateStatus = true; - -#ifdef ENABLE_VOICE - { - uint8_t Channel; - - AUDIO_SetVoiceID(0, VOICE_ID_WELCOME); - - Channel = gEeprom.ScreenChannel[gEeprom.TX_VFO]; - if (IS_MR_CHANNEL(Channel)) - { - AUDIO_SetVoiceID(1, VOICE_ID_CHANNEL_MODE); - AUDIO_SetDigitVoice(2, Channel + 1); - } - else if (IS_FREQ_CHANNEL(Channel)) - AUDIO_SetVoiceID(1, VOICE_ID_FREQUENCY_MODE); - - AUDIO_PlaySingleVoice(0); - } -#endif - -#ifdef ENABLE_NOAA - RADIO_ConfigureNOAA(); -#endif + const char *line0 = "ISS (ZARYA)"; + const char *line1 = "1 25544U 98067A 25026.23381182 .00024447 00000+0 42619-3 0 9998"; + const char *line2 = "2 25544 51.6395 290.1622 0002159 133.7357 10.9595 15.50580823493146"; + // 解析TLE数据 +tle_data data; // 直接在栈上创建一个tle_data + struct tm utc ; + utc.tm_isdst=0; + utc.tm_yday=26; + utc.tm_wday=1; + utc.tm_year=125; + utc.tm_mon =0; + utc.tm_mday=27; + utc.tm_hour=8; + utc.tm_min=28; + utc.tm_sec=42; + memset(gFrameBuffer,0,sizeof(gFrameBuffer)); + ST7565_BlitFullScreen(); + show_uint32(456,3) ; + SYSTEM_DelayMs(3000); while (1) { - APP_Update(); +//125 0 27 7 39 3Look: 57.454126 -18.469256 +//Pos: 51.546400, 125.533706 +// +//125 0 27 7 39 4Look: 57.403762 -18.499665 +//Pos: 51.553088, 125.632517 +// +//125 0 27 7 39 5Look: 57.353492 -18.530080 +//Pos: 51.559686, 125.731359 - if (gNextTimeslice) { - APP_TimeSlice10ms(); - } + if (tle_parse(line0, line1, line2, &data) == 0) { // 修改为传递指针 + } else { + lat_lon observer = { 50, 50, 50 }; // 设定观察者的经纬度和海拔 - if (gNextTimeslice_500ms) { - APP_TimeSlice500ms(); - } + jd target = to_jd(utc.tm_year + 1900, utc.tm_mon + 1, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec); + look_result look = eci_to_look(&data, observer, target); +int line=0; + memset(gFrameBuffer[line],0,256); + char str[20] = {0}; + sprintf(str, "%d.%d", (int)(look.azimuth), (int)(look.azimuth*100)%100); + UI_PrintStringSmall(str, 0, 127, line); + sprintf(str, "%d.%d", (int)(look.altitude), (int)(-look.altitude*100)%100); + UI_PrintStringSmall(str, 1, 127, line); + ST7565_BlitFullScreen(); + SYSTEM_DelayMs(1000); + utc.tm_sec+=1; + if(utc.tm_sec >= 60) { + utc.tm_sec=0; + utc.tm_min+=1; + + } + if(utc.tm_min >= 60) { + utc.tm_min=0; + utc.tm_hour+=1; + } + } } } + diff --git a/tle/astrotime.c b/tle/astrotime.c new file mode 100644 index 00000000..d4f32800 --- /dev/null +++ b/tle/astrotime.c @@ -0,0 +1,35 @@ +#include "astrotime.h" +#include "util.h" + +jd jd_year_begin(int year) { + year -= 1; + long a = year / 100; + long b = 2 - a + (a / 4); + return (long) (365.25 * year) + (long) (30.6001 * 14) + 1720994.5 + b; +} + +jd to_jd(int year, int month, int day, int hour, int minute, int second) { + double jd_start_day = jd_year_begin(year); + + static const int day_accum[2][13] = { + {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}, + {0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335} + }; + int leap = (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; + int jd_day = day_accum[leap][month] + day; + + static const int seconds_per_day = 24 * 3600; + int total_offset_seconds = hour * 3600 + minute * 60 + second; + double jd_off = (double) total_offset_seconds / seconds_per_day; + + return jd_start_day + jd_day + jd_off; +} + +gmst to_gmst(jd jd) { + double time = frac(jd + 0.5); + jd = jd - time; + double rel_date = (jd - 2451545.0) / 36525; + double gmst = 24110.54841 + rel_date * (8640184.812866 + rel_date * (0.093104 - rel_date * 6.2E-6)); + gmst = fmod(gmst + 86400.0 * 1.00273790934 * time, 86400.0); + return 2 * M_PI * gmst / 86400.0; +} diff --git a/tle/astrotime.h b/tle/astrotime.h new file mode 100644 index 00000000..dfb1df64 --- /dev/null +++ b/tle/astrotime.h @@ -0,0 +1,45 @@ +#ifndef FATE_ASTROTIME_H +#define FATE_ASTROTIME_H + +/** + * Julian Date represented as a double value + */ +typedef double jd; + +/** + * GMST represented as a radian measure in a double + */ +typedef double gmst; + +/** + * Obtains the Julian Date at the beginning of the given + * year. + * + * @param year the year which to find the julian date + */ +jd jd_year_begin(int year); + +/** + * Converts the given Gregorian time measurements (i.e. + * standard calendar measurements) into Julian Days. + * + * @param year the year which to convert + * @param month the month + * @param day the day + * @param hour the hour in UTC + * @param minute the minute in UTC + * @param second the second in UTC + * @return the Julian Date + */ +jd to_jd(int year, int month, int day, int hour, int minute, int second); + +/** + * Converts the given Julian Date into GMST. + * + * @param jd the Julian Date + * @return the GMST time, in radians + */ +gmst to_gmst(jd jd); +#include + +#endif /* FATE_ASTROTIME_H */ diff --git a/tle/eci.c b/tle/eci.c new file mode 100644 index 00000000..bd1df3a1 --- /dev/null +++ b/tle/eci.c @@ -0,0 +1,117 @@ +#include +#include "eci.h" +#include "vec.h" +#include "sgp.h" +#include "util.h" + +const double f = 0.003352810665; +const double esq = 0.006694379991; +const double a = 6378.137; + +vec lat_lon_to_eci(double lat, gmst theta,double h) { + double C = 1 / sqrt(1 + f * (f - 2) * square(sin(lat))); + double S = square(1 - f) * C; + double r = a * C + h / 1000.0; // 调整半径,考虑高度 + + double x = r * cos(lat) * cos(theta); + double y = r * cos(lat) * sin(theta); + double z = (a * S + h / 1000.0) * sin(lat); + + vec result = {x, y, z}; + return result; +} + +int tle_to_eci(sgp_result *result, tle_data *tle, jd time) { + // Convert TLE epoch into jd so we can figure out the + // minutes elapsed since the epoch until the target + // time + long epoch_yr; + if (strl(tle->epoch_yr, &epoch_yr) == 0) { + return 0; + } + static const int current_millenium = 2000; + double tle_jd = jd_year_begin(current_millenium + epoch_yr) + tle->epoch_day; + double minute_diff = (time - tle_jd) * 1440; + if (minute_diff < 0) { + return 0; + } + + *result = sgp4(tle, minute_diff); + return 1; +} + +double clamp(double lat, double max) { + double deg = to_degrees(lat); + if (deg > max) { + return -(max * 2 - deg); + } + + if (deg < -max) { + return deg + (max * 2); + } + + return deg; +} + +look_result eci_to_look(tle_data *tle, lat_lon observer, jd time) { + double lat = to_radians(observer.lat); + double lon = to_radians(observer.lon); + gmst gmst = to_gmst(time); + double theta = fmod(gmst + lon, 2 * M_PI); + + vec observer_eci = lat_lon_to_eci(lat, theta,observer.height); + sgp_result sgp_eci; + if (tle_to_eci(&sgp_eci, tle, time) == 0) { + look_result fail = { 0 }; + return fail; + } + + double rx = sgp_eci.r.x - observer_eci.x; + double ry = sgp_eci.r.y - observer_eci.y; + double rz = sgp_eci.r.z - observer_eci.z; + double top_s = sin(lat) * cos(theta) * rx + + sin(lat) * sin(theta) * ry + - cos(lat) * rz; + double top_e = -sin(theta) * rx + cos(theta) * ry; + double top_z = cos(lat) * cos(theta) * rx + + cos(lat) * sin(theta) * ry + + sin(lat) * rz; + double az = atan(-top_e / top_s); + if (top_s > 0) { + az = az + M_PI; + } + if (az < 0) { + az = az + 2 * M_PI; + } + double rg = sqrt(rx * rx + ry * ry + rz * rz); + double el = asin(top_z / rg); + + look_result result = {to_degrees(az), to_degrees(el), rg}; + return result; +} + +lat_lon eci_to_lat_lon(tle_data *tle, gmst time) { + gmst gmst = to_gmst(time); + double theta = fmod(gmst, 2 * M_PI); + + sgp_result sgp_eci; + if (tle_to_eci(&sgp_eci, tle, time) == 0) { + lat_lon fail = { 0 }; + return fail; + } + + double r = sqrt(square(sgp_eci.r.x) + square(sgp_eci.r.y)); + int rounds = 10; + double dphi; + double phi = atan2(sgp_eci.r.z, r); + do { + double phi_i = phi; + double C = 1 / sqrt(1 - esq * square(sin(phi_i))); + phi = atan2(sgp_eci.r.z + a * C * esq * sin(phi_i), r); + dphi = fabs(phi - phi_i); + } while (dphi > 1E-6 && --rounds > 0); + double lon = atan2(sgp_eci.r.y, sgp_eci.r.x) - theta; + + lat_lon result = { clamp(phi, 90), clamp(lon, 180) }; + return result; +} diff --git a/tle/eci.h b/tle/eci.h new file mode 100644 index 00000000..b37bb8e4 --- /dev/null +++ b/tle/eci.h @@ -0,0 +1,58 @@ +#ifndef FATE_ECI_H +#define FATE_ECI_H + +#include "tle.h" +#include "astrotime.h" +#include + +/** + * Represents the result of calculating the look position + * for an observer to a satellite, where azimuth is the + * clockwise rotation from true north and the altitude is + * the degrees inclination above the observation plane. + * Units are in degrees. + */ +typedef struct { + double azimuth; + double altitude; + double range; +} look_result; + +/** + * Represents a location on the Earth with latitude and + * longitude coordinates. Positive north and east. Units + * are in degrees. + */ +typedef struct { + double lat; + double lon; + double height; +} lat_lon; + +/** + * Calculates the look position of the satellite from its + * SGP data, the observer position, and the time. + * + * @param tle the TLE data that will be used + * @param observer the observer location on the Earth + * @param time the time which to determine the look + * location + * @return the look location expressed as an azimuth and + * altitude + */ +look_result eci_to_look(tle_data *tle, lat_lon observer, gmst time); + +/** + * Calculates the sub-point (i.e. the point below the + * satellite formed by a line from the satellite + * intersecting at a right angle with a line tangent to the + * surface of the Earth) from the given SGP data and time. + * + * @param tle the TLE data that will be used + * @param time the time which to calculate the satellite + * position on the Earth + * @return a set of latitude and longitude coordinates + */ +lat_lon eci_to_lat_lon(tle_data *tle, gmst time); + +#endif /* FATE_ECI_H */ diff --git a/tle/sgp.c b/tle/sgp.c new file mode 100644 index 00000000..3fd3098f --- /dev/null +++ b/tle/sgp.c @@ -0,0 +1,207 @@ +#include +#include "sgp.h" +#include "util.h" +#include "vec.h" + +static const double SDP_THRESH_FREQ = 1440.0 / 225.0; +static const double XKMPER = 6378.135; +static const double ONE_HALF = 1.0 / 2.0; +static const double THREE_HALVES = 3.0 / 2.0; +static const double TWO_THIRDS = 2.0 / 3.0; + +static const double a_E = 1.0; +static const double Q_0 = 1.88027916E-9; + +static const double k_e = 0.0743669161; +static const double k_2 = 5.413080E-4; +static const double k_4 = 0.62098875E-6; +static const double S = 1.0122292801892716; +static const double A_3_COMMA_0 = 2.53881E-06; + +sgp_result sgp4(tle_data *data, double minutes_since_epoch) { + if (data->rev_per_day < SDP_THRESH_FREQ) { + sgp_result fail = { {0}, {0}, {0}, {0} }; + return fail; + } + + double i_0 = to_radians(data->inclination); + double OMEGA_0 = to_radians(data->r_node_ascension); + double M_0 = to_radians(data->mean_anomaly); + double omega_0 = to_radians(data->perigee_arg); + double xno = data->rev_per_day * 2 * M_PI / 1440.0; + double delta_multiplier = ((3 * square(cos(i_0)) - 1) / + pow(1 - square(data->eccentricity), THREE_HALVES)); + + double a_1 = pow(k_e / xno, TWO_THIRDS); + double delta_1 = THREE_HALVES * (k_2 / square(a_1)) * delta_multiplier; + double a_0 = a_1 * (1 - ((1.0 / 3.0) * delta_1) - square(delta_1) - ((134.0 / 81.0) * cube(delta_1))); + double delta_0 = THREE_HALVES * (k_2 / square(a_0)) * delta_multiplier; + double d_d_n_0 = xno / (1 + delta_0); /* original mean motion */ + double d_d_a_0 = a_0 / (1 - delta_0); /* semimajor axis */ + + unsigned int simple = 0; + if ((d_d_a_0 * (1.0 - data->eccentricity) / a_E) < (220.0 / XKMPER + a_E)) { + simple = 1; + } + + double perigee = (d_d_a_0 * (1 - data->eccentricity) - a_E) * XKMPER; + double s = S; + double q_0_minus_s_pow_4 = Q_0; + if (perigee >= 98 && perigee <= 156) { + s = (d_d_a_0 * (1 - data->eccentricity)) - S + a_E; /* s_star */ + q_0_minus_s_pow_4 = pow(Q_0 - s, 4.0); + } else if (perigee < 98) { + s = 20.0 / XKMPER + a_E; /* s_star */ + q_0_minus_s_pow_4 = pow(Q_0 - s, 4.0); + } + + double theta = cos(i_0); + double xi = 1 / (d_d_a_0 - s); + double beta_0 = sqrt(1 - square(data->eccentricity)); + double eta = d_d_a_0 * data->eccentricity * xi; + double C_2 = + q_0_minus_s_pow_4 * pow(xi, 4.0) * d_d_n_0 * pow(1 - square(eta), -7.0 / 2.0) * + (d_d_a_0 * (1 + THREE_HALVES * square(eta) + 4 * data->eccentricity * eta + data->eccentricity * cube(eta)) + + (THREE_HALVES * ((k_2 * xi) / (1 - square(eta)))) * + (-ONE_HALF + THREE_HALVES * square(theta)) * + (8 + 24 * square(eta) + 3 * pow(eta, 4.0))); + double C_1 = data->drag * C_2; + double C_3 = (q_0_minus_s_pow_4 * pow(xi, 5.0) * A_3_COMMA_0 * d_d_n_0 * a_E * sin(i_0)) / + (k_2 / data->eccentricity); + double C_4 = 2 * d_d_n_0 * q_0_minus_s_pow_4 * pow(xi, 4.0) * d_d_a_0 * square(beta_0) * pow(1 - square(eta), -7.0 / 2.0) * + ((2 * eta * (1 + data->eccentricity * eta) + ONE_HALF * data->eccentricity + ONE_HALF * cube(eta)) - + ((2 * k_2 * xi) / (d_d_a_0 * (1 - square(eta)))) * + ( + 3 * (1 - 3 * square(theta)) * + (1 + THREE_HALVES * square(eta) - 2 * data->eccentricity * eta - ONE_HALF * data->eccentricity * cube(eta)) + + (3.0 / 4.0) * (1 - square(theta)) * (2 * square(eta) - data->eccentricity * eta - data->eccentricity * cube(eta)) * cos(2 * omega_0)) + ); + double C_5 = 2 * q_0_minus_s_pow_4 * pow(xi, 4.0) * d_d_a_0 * square(beta_0) * + pow(1 - square(eta), -7.0 / 2.0) * + (1 + (11.0 / 4.0) * eta * (eta + data->eccentricity) + data->eccentricity * cube(eta)); + + double M_DF = M_0 + + (1 + ((3 * k_2 * (-1 + 3 * square(theta))) / (2 * square(d_d_a_0) * cube(beta_0))) + + ((3 * square(k_2) * (13 - 78 * square(theta) + 137 * pow(theta, 4.0))) / + (16 * pow(d_d_a_0, 4.0) * pow(beta_0, 7.0)))) * + d_d_n_0 * minutes_since_epoch; + double omega_DF = omega_0 + + (-((3 * k_2 * (1 - 5 * square(theta))) / (2 * square(d_d_a_0) * pow(beta_0, 4.0))) + + ((3 * square(k_2) * (7 - 114 * square(theta) + 395 * pow(theta, 4.0))) / + (16 * pow(d_d_a_0, 4.0) * pow(beta_0, 8.0))) + + ((5 * k_4 * (3 - 36 * square(theta) + 49 * pow(theta, 4.0))) / + (4.0 * pow(d_d_a_0, 4.0) * pow(beta_0, 8.0)))) * + d_d_n_0 * minutes_since_epoch; + double OMEGA_DF = OMEGA_0 + + ((-(3 * k_2 * theta) / (square(d_d_a_0) * pow(beta_0, 4.0))) + + ((3 * square(k_2) * (4 * theta - 19 * cube(theta))) / + (2 * pow(d_d_a_0, 4.0) * pow(beta_0, 8.0))) + + ((5 * k_4 * theta * (3 - 7 * square(theta))) / (2 * pow(d_d_a_0, 4.0) * pow(beta_0, 8.0)))) * + d_d_n_0 * minutes_since_epoch; + double delta_omega = data->drag * C_3 * cos(omega_0) * minutes_since_epoch; + double delta_M = -TWO_THIRDS * q_0_minus_s_pow_4 * data->drag * pow(xi, 4.0) * + (a_E / (data->eccentricity * eta)) * + (pow(1 + eta * cos(M_DF), 3.0) - pow(1 + eta * cos(M_0), 3.0)); + double M_p = M_DF; + double omega = omega_DF; + double OMEGA = OMEGA_DF - + (21.0 / 2.0) * ((d_d_n_0 * k_2 * theta) / (square(d_d_a_0) * square(beta_0))) * + C_1 * square(minutes_since_epoch); + + double e; + double a; + double L; + if (simple == 0) { + M_p += delta_omega + delta_M; + omega -= delta_omega - delta_M; + e = data->eccentricity - data->drag * C_4 * minutes_since_epoch - + data->drag * C_5 * (sin(M_p) - sin(M_0)); + + double D_2 = 4 * d_d_a_0 * xi * square(C_1); + double D_3 = (4.0 / 3.0) * d_d_a_0 * square(xi) * (17 * d_d_a_0 + s) * cube(C_1); + double D_4 = TWO_THIRDS * d_d_a_0 * cube(xi) * (221 * d_d_a_0 + 31 * s) * pow(C_1, 4.0); + a = d_d_a_0 * + square(1 - C_1 * minutes_since_epoch - + D_2 * square(minutes_since_epoch) - + D_3 * cube(minutes_since_epoch) - + D_4 * pow(minutes_since_epoch, 4.0)); + L = M_p + omega + OMEGA + d_d_n_0 * (THREE_HALVES * C_1 * square(minutes_since_epoch) + + (D_2 + 2 * square(C_1)) * cube(minutes_since_epoch) + + (1.0 / 4.0) * (3 * D_3 + 12 * C_1 * D_2 + 10 * cube(C_1) * pow(minutes_since_epoch, 4.0)) + + ((1.0 / 5.0) * + (3 * D_4 + 12 * C_1 * D_3 + 6 * square(D_2) + 30 * square(C_1) * D_2 + + 15 * pow(C_1, 4.0) * pow(minutes_since_epoch, 5.0)))); + } else { + e = data->eccentricity - data->drag * C_4 * minutes_since_epoch; + a = d_d_a_0 * square(1 - C_1 * minutes_since_epoch); + L = M_p + omega + OMEGA + d_d_n_0 * (THREE_HALVES * C_1 * square(minutes_since_epoch)); + } + double beta = sqrt(1 - square(e)); + double n = k_e / sqrt(cube(a)); + + double a_xN = e * cos(omega); + double L_L = ((A_3_COMMA_0 * sin(i_0)) / (8 * k_2 * a * square(beta))) * + (e * cos(omega)) * ((3 + 5 * theta) / (1 + theta)); + double a_yNL = (A_3_COMMA_0 * sin(i_0)) / (4 * k_2 * a * square(beta)); + double L_T = L + L_L; + double a_yN = e * sin(omega) + a_yNL; + + double AXN_SIN; + double AYN_COS; + double AXN_COS; + double AYN_SIN; + double U = fmod(L_T - OMEGA, 2 * M_PI); + double E_w_i = U; + for (int i = 1; i <= 10; ++i) { + double sinpw = sin(E_w_i); + double cospw = cos(E_w_i); + + AXN_SIN = a_xN * sinpw; + AYN_COS = a_yN * cospw; + AXN_COS = a_xN * cospw; + AYN_SIN = a_yN * sinpw; + + double dE_w_i = (U - AYN_COS + AXN_SIN - E_w_i) / + (-AYN_SIN - AXN_COS + 1) + E_w_i; + if (fabs(dE_w_i - E_w_i) <= 1.0E-6) { + break; + } + + E_w_i = dE_w_i; + } + + double e_cos_E = AXN_COS + AYN_SIN; + double e_sin_E = AXN_SIN - AYN_COS; + double e_L = sqrt(square(a_xN) + square(a_yN)); + double p_L = a * (1 - square(e_L)); + double r = a * (1 - e_cos_E); + double r_dot = k_e * (sqrt(a) / r) * e_sin_E; + double r_f_dot = k_e * (sqrt(p_L) / r); + double cos_u = (a / r) * (cos(E_w_i) - a_xN + ((a_yN * e_sin_E) / (1 + sqrt(1 - square(e_L))))); + double sin_u = (a / r) * (sin(E_w_i) - a_yN - ((a_xN * e_sin_E) / (1 + sqrt(1 - square(e_L))))); + double u = atan2(sin_u, cos_u); + double dr = (k_2 / (2 * p_L)) * (1 - square(theta)) * cos(2 * u); + double du = (-k_2 / (4 * square(p_L))) * (7 * square(theta) - 1) * sin(2 * u); + double dOMEGA = ((3 * k_2 * theta) / (2 * square(p_L))) * sin(2 * u); + double di = ((3 * k_2 * theta) / (2 * square(p_L))) * sin(i_0) * cos(2 * u); + double dr_dot = (-(k_2 * n) / p_L) * (1 - square(theta)) * sin(2 * u); + double dr_f_dot = ((k_2 * n) / p_L) * ((1 - square(theta)) * cos(2 * u) - THREE_HALVES * (1 - 3 * square(theta))); + double r_k = r * (1 - THREE_HALVES * k_2 * (sqrt(1 - square(e_L)) / square(p_L)) * (3 * square(theta) - 1)) + dr; + double u_k = u + du; + double OMEGA_k = OMEGA + dOMEGA; + double i_k = i_0 + di; + double r_dot_k = r_dot + dr_dot; + double r_f_dot_k = r_f_dot + dr_f_dot; + + vec M = {-sin(OMEGA_k) * cos(i_k), cos(OMEGA_k) * cos(i_k), sin(i_k)}; + vec N = {cos(OMEGA_k), sin(OMEGA_k), 0}; + + vec result_U = vec_add(vec_mul(sin(u_k), M), vec_mul(cos(u_k), N)); + vec result_V = vec_add(vec_mul(cos(u_k), M), vec_mul(-sin(u_k), N)); + + vec result_r = vec_mul(XKMPER, vec_mul(r_k, result_U)); + vec result_r_dot = vec_mul(XKMPER / 60, vec_add(vec_mul(r_dot_k, result_U), vec_mul(r_f_dot_k, result_V))); + + sgp_result result = {result_U, result_V, result_r, result_r_dot}; + return result; +} \ No newline at end of file diff --git a/tle/sgp.h b/tle/sgp.h new file mode 100644 index 00000000..5fbf9bd1 --- /dev/null +++ b/tle/sgp.h @@ -0,0 +1,18 @@ +#include "tle.h" +#include "vec.h" +#include + +#ifndef FATE_SGP_H +#define FATE_SGP_H + +typedef struct { + vec u; /* orientation */ + vec v; + + vec r; /* position */ + vec r_dot; /* velocity */ +} sgp_result; + +sgp_result sgp4(tle_data *data, double minutes_since_epoch); + +#endif /* FATE_SGP_H */ diff --git a/tle/tle.c b/tle/tle.c new file mode 100644 index 00000000..0828fa3d --- /dev/null +++ b/tle/tle.c @@ -0,0 +1,358 @@ +#include +#include +#include +#include "tle.h" +#include "util.h" + +/** + * Designed to parse space-track.org title lines, they are + * prefixed with "0 " so the max len would be 26 and not 24 + * + * @param data the data to fill + * @param title the title line + * @return 0 if invalid length + */ +static int parse_title(tle_data *data, const char *title) { + unsigned char len = (unsigned char) strlen(title); + if (len > 26) { + return 0; + } + + /* Cut the beginning "0 " and the newline */ + len -= 3; + + data->title_len = len; + substr(title, 2, len,data->title); + if (data->title == NULL) { + return 0; + } + + return 1; +} + +static int compute_checksum(const char *str) { + int total = 0; + for (int i = 0; i < 68; i++) { + char c = str[i]; + if (c == '-') { + total += 1; + } else if (c >= '0' && c <= '9') { + total += c - '0'; + } + } + + return total % 10; +} + +static int parse_line1(tle_data *data, const char *line1) { + int checksum = line1[68] - '0'; + if (compute_checksum(line1) != checksum) { + // puts("Checksum failed"); + return 0; + } + + /* sat_num */ + char sat_num_str[8]; + substr(line1, 2, 5,sat_num_str); + + + if (strl(sat_num_str, (long *) &data->sat_num) == 0) { + //free(sat_num_str); + return 0; + } + + + /* class */ + data->class = line1[7]; + + /* launch_yr */ + substr(line1, 9, 2,data->launch_yr ); + + /* launch_num */ + char launch_num_str[5] ; + substr(line1, 11, 3,launch_num_str); + + + if (strl(launch_num_str, (long *) &data->launch_num) == 0) { + //free(launch_num_str); + return 0; + } + + //free(launch_num_str); + + /* launch_piece */ + substr(line1, 14, 3, data->launch_piece ); + if (data->launch_piece == NULL) { + return 0; + } + data->launch_piece_len = (unsigned char) strlen(data->launch_piece); + + /* epoch_yr */ + substr(line1, 18, 2,data->epoch_yr); + if (data->epoch_yr == NULL) { + return 0; + } + + /* epoch_day */ + char epoch_day_str[20]; + substr(line1, 20, 12,epoch_day_str); + if (epoch_day_str == NULL) { + return 0; + } + + if (strd(epoch_day_str, &data->epoch_day) == 0) { + //free(epoch_day_str); + return 0; + } + + //free(epoch_day_str); + + /* d_mean_motion */ + char d_mean_motion_str[20]; + substr(line1, 33, 10,d_mean_motion_str); + + if (strd(d_mean_motion_str, &data->d_mean_motion) == 0) { + //free(d_mean_motion_str); + return 0; + } + + //free(d_mean_motion_str); + + /* dd_mean_motion */ + double dd_mean_motion_mul = 0; + char dd_mean_motion_mul_str[20] ; + substr(line1, 44, 6,dd_mean_motion_mul_str); + if (dd_mean_motion_mul_str == NULL) { + return 0; + } + + if (strd(dd_mean_motion_mul_str, &dd_mean_motion_mul) == 0) { + //free(dd_mean_motion_mul_str); + return 0; + } + + //free(dd_mean_motion_mul_str); + dd_mean_motion_mul /= 100000; + + int dd_mean_motion_exp = 0; + char dd_mean_motion_exp_str[20] ; + substr(line1, 50, 2,dd_mean_motion_exp_str); + if (dd_mean_motion_exp_str == NULL) { + return 0; + } + + if (strl(dd_mean_motion_exp_str, (long *) &dd_mean_motion_exp) == 0) { + //free(dd_mean_motion_exp_str); + return 0; + } + + //free(dd_mean_motion_exp_str); + data->dd_mean_motion = dd_mean_motion_mul * pow(10, dd_mean_motion_exp); + + /* drag */ + double drag_mul = 0; + char drag_mul_str[20] ; substr(line1, 53, 6,drag_mul_str); + if (drag_mul_str == NULL) { + return 0; + } + + if (strd(drag_mul_str, &drag_mul) == 0) { + //free(drag_mul_str); + return 0; + } + + //free(drag_mul_str); + drag_mul /= 100000; + + int drag_exp = 0; + char drag_exp_str[20] ; substr(line1, 59, 2,drag_exp_str); + if (drag_exp_str == NULL) { + return 0; + } + + if (strl(drag_exp_str, (long *) &drag_exp) == 0) { + //free(drag_exp_str); + return 0; + } + + //free(drag_exp_str); + data->drag = drag_mul * pow(10, drag_exp); + + /* ephemeris */ + data->ephemeris = (unsigned char) line1[62]; + + /* element_num */ + char element_num_str[20] ; + substr(line1, 64, 4,element_num_str); + if (element_num_str == NULL) { + return 0; + } + + if (strl(element_num_str, (long *) &data->element_num) == 0) { + //free(element_num_str); + return 0; + } + + //free(element_num_str); + + return 1; +} + +static int parse_line2(tle_data *data, const char *line2) { + int checksum = line2[68] - '0'; + if (compute_checksum(line2) != checksum) { + // puts("Checksum failed"); + return 0; + } + + /* ignore satellite number */ + + /* inclination */ + char inclination_str[20]; + substr(line2, 8, 8,inclination_str); + if (inclination_str == NULL) { + return 0; + } + + if (strd(inclination_str, &data->inclination) == 0) { + //free(inclination_str); + return 0; + } + + //free(inclination_str); + + /* r_node_ascension */ + char r_node_ascension_str[20] ; + substr(line2, 17, 8,r_node_ascension_str); + if (r_node_ascension_str == NULL) { + return 0; + } + + if (strd(r_node_ascension_str, &data->r_node_ascension) == 0) { + //free(r_node_ascension_str); + return 0; + } + + //free(r_node_ascension_str); + + /* eccentricity */ + double eccentricity = 0; + char eccentricity_str[20] ; + substr(line2, 26, 7,eccentricity_str); + if (eccentricity_str == NULL) { + return 0; + } + + if (strd(eccentricity_str, &eccentricity) == 0) { + //free(eccentricity_str); + return 0; + } + + //free(eccentricity_str); + data->eccentricity = eccentricity /= 10000000; + + /* perigee_arg */ + char perigee_arg_str[20] ; + substr(line2, 34, 8,perigee_arg_str); + if (perigee_arg_str == NULL) { + return 0; + } + + if (strd(perigee_arg_str, &data->perigee_arg) == 0) { + //free(perigee_arg_str); + return 0; + } + + //free(perigee_arg_str); + + /* mean_anomaly */ + char mean_anomaly_str[20] ; + substr(line2, 43, 8,mean_anomaly_str); + if (mean_anomaly_str == NULL) { + return 0; + } + + if (strd(mean_anomaly_str, &data->mean_anomaly) == 0) { + //free(mean_anomaly_str); + return 0; + } + + //free(mean_anomaly_str); + + /* rev_per_day */ + char rev_per_day_str[20] ; + substr(line2, 52, 11,rev_per_day_str); + if (rev_per_day_str == NULL) { + return 0; + } + + if (strd(rev_per_day_str, &data->rev_per_day) == 0) { + //free(rev_per_day_str); + return 0; + } + + //free(rev_per_day_str); + + /* rev_num */ + char rev_num_str[20]; + substr(line2, 63, 5,rev_num_str); + if (rev_num_str == NULL) { + return 0; + } + + if (strl(rev_num_str, (long *) &data->rev_num) == 0) { + //free(rev_num_str); + return 0; + } + + //free(rev_num_str); + + return 1; +} + +int tle_parse(const char *title, const char *line1, const char *line2, tle_data *data) { + if (parse_title(data, title) == 0) { + return 0; // 解析失败 + } + + if (parse_line1(data, line1) == 0) { + return 0; // 解析失败 + } + + if (parse_line2(data, line2) == 0) { + return 0; // 解析失败 + } + + return 1; // 成功解析 +} + +void tle_print(FILE *stream, tle_data *data) { + fprintf(stream, "Title: %s\n", data->title); + fprintf(stream, "Satellite Number: %d\n", data->sat_num); + fprintf(stream, "Classifier: %c\n", data->class); + fprintf(stream, "Launch Year: %s\n", data->launch_yr); + fprintf(stream, "Launch Number: %d\n", data->launch_num); + fprintf(stream, "Launch Piece: %s\n", data->launch_piece); + fprintf(stream, "Epoch Year: %s\n", data->epoch_yr); + fprintf(stream, "Epoch Day: %f\n", data->epoch_day); + fprintf(stream, "Derivative of Mean Motion / 2: %f\n", data->d_mean_motion); + fprintf(stream, "2nd Derivative of Mean Motion / 6: %f\n", data->dd_mean_motion); + fprintf(stream, "B* Drag Term: %f\n", data->drag); + fprintf(stream, "Ephemeris Type: %c\n", data->ephemeris); + fprintf(stream, "Element Number: %d\n", data->element_num); + fprintf(stream, "Inclination: %f\n", data->inclination); + fprintf(stream, "Right Node Ascension: %f\n", data->r_node_ascension); + fprintf(stream, "Eccentricity: %f\n", data->eccentricity); + fprintf(stream, "Argument of Perigee: %f\n", data->perigee_arg); + fprintf(stream, "Mean Anomaly: %f\n", data->mean_anomaly); + fprintf(stream, "Revolutions Per Day: %f\n", data->rev_per_day); + fprintf(stream, "Revolutions: %d\n", data->rev_num); +} + +void tle_free(tle_data *data) { + //free(data->title); + //free(data->launch_yr); + //free(data->launch_piece); + //free(data->epoch_yr); + //free(data); +} \ No newline at end of file diff --git a/tle/tle.h b/tle/tle.h new file mode 100644 index 00000000..d4f282d7 --- /dev/null +++ b/tle/tle.h @@ -0,0 +1,75 @@ +#ifndef FATE_TLE_H +#define FATE_TLE_H + +#include + +/** + * A year represented as a 2-digit number + */ +typedef char *year; + +typedef struct { + /* TITLE LINE */ + char title[20]; + unsigned char title_len; + + /* LINE 1 */ + + int sat_num; + char class; + + char launch_yr[40]; + short launch_num; + char launch_piece[20]; + unsigned char launch_piece_len; + + char epoch_yr[40]; + double epoch_day; + + double d_mean_motion; /* n_0_dot / 2 */ + double dd_mean_motion; /* n_0_dot_dot / 6 */ + + double drag; + + unsigned char ephemeris; + short element_num; + /* checksum */ + + /* LINE 2 */ + + double inclination; /* i_0 */ + double r_node_ascension; /* omega_0 */ + double eccentricity; /* e_0 */ + double perigee_arg; /* omega_0 */ + double mean_anomaly; /* M_0 */ + double rev_per_day; /* n_0 */ + int rev_num; + /* checksum */ +} tle_data; + +/** + * Parses and TLE-formatted data using the 3 line format + * that includes the title line. + * + * @param title the title + * @param line1 the first line + * @param line2 the second line + * @return the TLE parsed data, or NULL on failure + */ +int tle_parse(const char *title, const char *line1, const char *line2, tle_data *data) ; +/** + * Prints the given TLE data to the given stream. + * + * @param data the data to print + */ +void tle_print(FILE *stream, tle_data *data); + +/** + * Relinquishes memory allocated to hold the tle_data + * struct. + * + * @param data the data struct to free + */ +void tle_free(tle_data *data); + +#endif /* FATE_TLE_H */ diff --git a/tle/util.c b/tle/util.c new file mode 100644 index 00000000..a47d955c --- /dev/null +++ b/tle/util.c @@ -0,0 +1,84 @@ +#include +#include +#include + +char substr(const char *str, int start, int len, char *buf) { + + + // 复制子串到缓冲区 + memcpy(buf, str + start, len); + buf[len] = '\0'; // 添加字符串结束符 + +} + +int strl(const char *str, long *value) { + char *end_ptr = NULL; + long result = strtol(str, &end_ptr, 10); + if (result == 0 && str == end_ptr) { + return 0; + } + + *value = result; + return 1; +} + + +int strd(const char *str, double *value) { + if (!str || !value) { + return 0; // 输入无效 + } + + double result = 0.0; + bool is_negative = false; + bool is_fraction = false; + double fraction_divisor = 1.0; + + // 跳过前导空格 + while (*str == ' ') { + str++; + } + + // 处理正负号 + if (*str == '-') { + is_negative = true; + str++; + } else if (*str == '+') { + str++; + } + + // 检查第一个字符是否是数字或小数点 + if ((*str < '0' || *str > '9') && *str != '.') { + return 0; // 非法输入 + } + + // 处理数字部分 + while ((*str >= '0' && *str <= '9') || *str == '.') { + if (*str == '.') { + if (is_fraction) { + return 0; // 多个小数点,非法输入 + } + is_fraction = true; + } else { + if (is_fraction) { + fraction_divisor *= 10.0; + result += (*str - '0') / fraction_divisor; + } else { + result = result * 10.0 + (*str - '0'); + } + } + str++; + } + + // 处理负号 + if (is_negative) { + result = -result; + } + + // 检查是否还有多余字符 + if (*str != '\0') { + return 0; // 非法输入 + } + + *value = result; + return 1; // 成功解析 +} diff --git a/tle/util.h b/tle/util.h new file mode 100644 index 00000000..fa86426f --- /dev/null +++ b/tle/util.h @@ -0,0 +1,92 @@ +#ifndef FATE_UTIL_H +#define FATE_UTIL_H +#define M_PI 3.14159265358979323846 +#include +#include +#include + +/** + * Multiplies the given number by itself. + * + * CONSTRAINT: x <= 1.34E154 + */ +static inline double square(double x) { + return x * x; +} + +/** + * Multiplies the given number times itself 3 times. + * + * CONSTRAINT: x <= 5.64E102 + */ +static inline double cube(double x) { + return x * x * x; +} + +/** + * Obtains the fractional portion of a double value. + * + * @param x the value which to obtain the fraction + * @return the fractional portion + */ +static inline double frac(double x) { + return x - (long) x; +} + +/** + * Converts the given number to radians. + * + * CONSTRAINT: x is in degrees + * CONSTRAINT: x <= 1.14E306 + */ +static inline double to_radians(double x) { + static const double MULTIPLIER = M_PI / 180; + + return x * MULTIPLIER; +} + +/** + * Converts the given number to degrees. + * + * CONSTRAINT: x is in radians + * CONSTRAINT: x <= 9.98E305 + */ +static inline double to_degrees(double x) { + static const double MULTIPLIER = 180 / M_PI; + + return x * MULTIPLIER; +} + +/** + * Takes the substring of the given string, starting from + * start and ending len characters later. + * + * CONSTRAINT: start >= 0 + * CONSTRAINT: start + len <= strlen(str) + * + * @param str the string to obtain the substring + * @param start the beginning index, inclusive + * @param len the number of characters to copy + * @return the new substring, or NULL on failure + */ +char substr(const char *str, int start, int len, char *buf); + +/** + * Converts a given string into a long value. + * + * @param str the string to convert + * @param value the pointer at which to store the result + * @return 0 on failure + */ +int strl(const char *str, long *value); + +/** + * Converts a given string into a double value. + * + * @param str the string to convert + * @param value the pointer at which to store the result + * @return 0 on failure + */ +int strd(const char *str, double *value); + +#endif /* FATE_UTIL_H */ diff --git a/tle/vec.c b/tle/vec.c new file mode 100644 index 00000000..2f666901 --- /dev/null +++ b/tle/vec.c @@ -0,0 +1,16 @@ +#include +#include "vec.h" + +vec vec_mul(double scalar, vec vector) { + vec result = {vector.x * scalar, vector.y * scalar, vector.z * scalar}; + return result; +} + +vec vec_add(vec vector1, vec vector2) { + vec result = {vector1.x + vector2.x, vector1.y + vector2.y, vector1.z + vector2.z}; + return result; +} + +void vec_print(FILE *stream, vec vector) { + fprintf(stream, "{ %f, %f, %f }\n", vector.x, vector.y, vector.z); +} diff --git a/tle/vec.h b/tle/vec.h new file mode 100644 index 00000000..fb5bc311 --- /dev/null +++ b/tle/vec.h @@ -0,0 +1,32 @@ +#ifndef FATE_VEC_H +#define FATE_VEC_H +#include + +#include + +typedef struct { + double x; + double y; + double z; +} vec; + +/** + * Performs a scalar multiplication on the given vector. + * + * @return a new vector containing the multiplied values + */ +vec vec_mul(double, vec); + +/** + * Adds the values of two vectors together. + * + * @return a new vector containing the added values + */ +vec vec_add(vec, vec); + +/** + * Prints the given vector to the given stream. + */ +void vec_print(FILE *stream, vec); + +#endif /* FATE_VEC_H */ diff --git a/ui/main.c b/ui/main.c index 0dfcfbfd..2d68e9ef 100644 --- a/ui/main.c +++ b/ui/main.c @@ -21,7 +21,7 @@ #include "app/dtmf.h" #include "font.h" #include "app/chFrScanner.h" - +int vfo_num=0; #ifdef ENABLE_AM_FIX #include "am_fix.h" #endif diff --git a/win_make.bat b/win_make.bat index 426a9be3..950bd31d 100644 --- a/win_make.bat +++ b/win_make.bat @@ -22,9 +22,9 @@ :: :: Temporarily add the compiler and make program directories to the system PATH .. :: -@set PATH="C:\Program Files (x86)\GNU Arm Embedded Toolchain\10 2021.10\bin";%PATH% -@set PATH="C:\Program Files (x86)\GNU Arm Embedded Toolchain\10 2021.10\arm-none-eabi\bin";%PATH% -@set PATH="C:\Program Files (x86)\GnuWin32\bin\";%PATH% +@set PATH="C:\gcc-arm-none-eabi-10.3-2021.10\bin";%PATH% +@set PATH="C:\gcc-arm-none-eabi-10.3-2021.10\arm-none-eabi\bin";%PATH% +@set PATH="D:\Program Files (x86)\GnuWin32\bin\";%PATH% :: Do the compile ::