diff --git a/.config b/.config index f938fc5..24323d8 100644 --- a/.config +++ b/.config @@ -270,10 +270,14 @@ CONFIG_RT_USING_ULOG=y # CONFIG_ULOG_OUTPUT_LVL_I is not set CONFIG_ULOG_OUTPUT_LVL_D=y CONFIG_ULOG_OUTPUT_LVL=7 -# CONFIG_ULOG_USING_ISR_LOG is not set +CONFIG_ULOG_USING_ISR_LOG=y CONFIG_ULOG_ASSERT_ENABLE=y CONFIG_ULOG_LINE_BUF_SIZE=128 -# CONFIG_ULOG_USING_ASYNC_OUTPUT is not set +CONFIG_ULOG_USING_ASYNC_OUTPUT=y +CONFIG_ULOG_ASYNC_OUTPUT_BUF_SIZE=2048 +CONFIG_ULOG_ASYNC_OUTPUT_BY_THREAD=y +CONFIG_ULOG_ASYNC_OUTPUT_THREAD_STACK=1024 +CONFIG_ULOG_ASYNC_OUTPUT_THREAD_PRIORITY=30 # # log format @@ -499,7 +503,15 @@ CONFIG_ULOG_BACKEND_USING_CONSOLE=y # CONFIG_PKG_USING_SEGGER_RTT is not set # CONFIG_PKG_USING_RDB is not set # CONFIG_PKG_USING_ULOG_EASYFLASH is not set -# CONFIG_PKG_USING_ULOG_FILE is not set +CONFIG_PKG_USING_ULOG_FILE=y +CONFIG_PKG_ULOG_FILE_PATH="/packages/tools/ulog_file" +CONFIG_ULOG_FILE_ROOT_PATH="/logs" +CONFIG_ULOG_FILE_NAME_BASE="ulog.log" +CONFIG_ULOG_FILE_MAX_NUM=5 +CONFIG_ULOG_FILE_MAX_SIZE=524288 +CONFIG_PKG_USING_ULOG_FILE_V100=y +# CONFIG_PKG_USING_ULOG_FILE_LATEST_VERSION is not set +CONFIG_PKG_ULOG_FILE_VER="v1.0.0" # CONFIG_PKG_USING_LOGMGR is not set # CONFIG_PKG_USING_ADBD is not set # CONFIG_PKG_USING_COREMARK is not set @@ -589,6 +601,7 @@ CONFIG_ULOG_BACKEND_USING_CONSOLE=y # CONFIG_PKG_USING_CAIRO is not set # CONFIG_PKG_USING_PIXMAN is not set # CONFIG_PKG_USING_PARTITION is not set +# CONFIG_PKG_USING_PERF_COUNTER is not set # CONFIG_PKG_USING_FAL is not set # CONFIG_PKG_USING_FLASHDB is not set # CONFIG_PKG_USING_SQLITE is not set @@ -798,7 +811,7 @@ CONFIG_SOC_STM32F407ZG=y # CONFIG_BSP_USING_USB_TO_USART=y # CONFIG_BSP_USING_COM2 is not set -# CONFIG_BSP_USING_COM3 is not set +CONFIG_BSP_USING_COM3=y CONFIG_BSP_USING_SRAM=y # CONFIG_BSP_USING_SPI_FLASH is not set # CONFIG_BSP_USING_EEPROM is not set @@ -823,7 +836,9 @@ CONFIG_BSP_USING_UART1=y # CONFIG_BSP_UART1_RX_USING_DMA is not set # CONFIG_BSP_UART1_TX_USING_DMA is not set # CONFIG_BSP_USING_UART2 is not set -# CONFIG_BSP_USING_UART3 is not set +CONFIG_BSP_USING_UART3=y +CONFIG_BSP_UART3_RX_USING_DMA=y +# CONFIG_BSP_UART3_TX_USING_DMA is not set # CONFIG_BSP_USING_UART4 is not set # CONFIG_BSP_USING_UART5 is not set # CONFIG_BSP_USING_UART6 is not set diff --git a/.cproject b/.cproject index 48dea24..98091bd 100644 --- a/.cproject +++ b/.cproject @@ -1,218 +1,425 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore index f17985e..4dd406c 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,4 @@ RTE/ settings/ *.uvguix* +/Release/ diff --git a/.settings/.rtmenus b/.settings/.rtmenus index 2d162b2..e49cb42 100644 Binary files a/.settings/.rtmenus and b/.settings/.rtmenus differ diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml index 3480932..8e61900 100644 --- a/.settings/language.settings.xml +++ b/.settings/language.settings.xml @@ -5,7 +5,18 @@ - + + + + + + + + + + + + diff --git a/.settings/org.eclipse.cdt.core.prefs b/.settings/org.eclipse.cdt.core.prefs new file mode 100644 index 0000000..6b0f247 --- /dev/null +++ b/.settings/org.eclipse.cdt.core.prefs @@ -0,0 +1,164 @@ +eclipse.preferences.version=1 +org.eclipse.cdt.core.formatter.alignment_for_arguments_in_method_invocation=16 +org.eclipse.cdt.core.formatter.alignment_for_assignment=16 +org.eclipse.cdt.core.formatter.alignment_for_base_clause_in_type_declaration=80 +org.eclipse.cdt.core.formatter.alignment_for_binary_expression=16 +org.eclipse.cdt.core.formatter.alignment_for_compact_if=16 +org.eclipse.cdt.core.formatter.alignment_for_conditional_expression=34 +org.eclipse.cdt.core.formatter.alignment_for_conditional_expression_chain=18 +org.eclipse.cdt.core.formatter.alignment_for_constructor_initializer_list=0 +org.eclipse.cdt.core.formatter.alignment_for_declarator_list=16 +org.eclipse.cdt.core.formatter.alignment_for_enumerator_list=48 +org.eclipse.cdt.core.formatter.alignment_for_expression_list=0 +org.eclipse.cdt.core.formatter.alignment_for_expressions_in_array_initializer=16 +org.eclipse.cdt.core.formatter.alignment_for_member_access=0 +org.eclipse.cdt.core.formatter.alignment_for_overloaded_left_shift_chain=16 +org.eclipse.cdt.core.formatter.alignment_for_parameters_in_method_declaration=16 +org.eclipse.cdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 +org.eclipse.cdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.cdt.core.formatter.brace_position_for_block=next_line +org.eclipse.cdt.core.formatter.brace_position_for_block_in_case=next_line +org.eclipse.cdt.core.formatter.brace_position_for_method_declaration=next_line +org.eclipse.cdt.core.formatter.brace_position_for_namespace_declaration=next_line +org.eclipse.cdt.core.formatter.brace_position_for_switch=next_line +org.eclipse.cdt.core.formatter.brace_position_for_type_declaration=next_line +org.eclipse.cdt.core.formatter.comment.line_up_line_comment_in_blocks_on_first_column=false +org.eclipse.cdt.core.formatter.comment.min_distance_between_code_and_line_comment=1 +org.eclipse.cdt.core.formatter.comment.never_indent_line_comments_on_first_column=true +org.eclipse.cdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=true +org.eclipse.cdt.core.formatter.compact_else_if=true +org.eclipse.cdt.core.formatter.continuation_indentation=2 +org.eclipse.cdt.core.formatter.continuation_indentation_for_array_initializer=2 +org.eclipse.cdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.cdt.core.formatter.indent_access_specifier_compare_to_type_header=false +org.eclipse.cdt.core.formatter.indent_access_specifier_extra_spaces=0 +org.eclipse.cdt.core.formatter.indent_body_declarations_compare_to_access_specifier=true +org.eclipse.cdt.core.formatter.indent_body_declarations_compare_to_namespace_header=false +org.eclipse.cdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.cdt.core.formatter.indent_declaration_compare_to_template_header=false +org.eclipse.cdt.core.formatter.indent_empty_lines=false +org.eclipse.cdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.cdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.cdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.cdt.core.formatter.indent_switchstatements_compare_to_switch=false +org.eclipse.cdt.core.formatter.indentation.size=4 +org.eclipse.cdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.cdt.core.formatter.insert_new_line_after_template_declaration=do not insert +org.eclipse.cdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert +org.eclipse.cdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert +org.eclipse.cdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +org.eclipse.cdt.core.formatter.insert_new_line_before_colon_in_constructor_initializer_list=do not insert +org.eclipse.cdt.core.formatter.insert_new_line_before_else_in_if_statement=insert +org.eclipse.cdt.core.formatter.insert_new_line_before_identifier_in_function_declaration=do not insert +org.eclipse.cdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert +org.eclipse.cdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.cdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.cdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.cdt.core.formatter.insert_space_after_closing_angle_bracket_in_template_arguments=insert +org.eclipse.cdt.core.formatter.insert_space_after_closing_angle_bracket_in_template_parameters=insert +org.eclipse.cdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.cdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.cdt.core.formatter.insert_space_after_colon_in_base_clause=insert +org.eclipse.cdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.cdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.cdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.cdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.cdt.core.formatter.insert_space_after_comma_in_base_types=insert +org.eclipse.cdt.core.formatter.insert_space_after_comma_in_declarator_list=insert +org.eclipse.cdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.cdt.core.formatter.insert_space_after_comma_in_expression_list=insert +org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.cdt.core.formatter.insert_space_after_comma_in_template_arguments=insert +org.eclipse.cdt.core.formatter.insert_space_after_comma_in_template_parameters=insert +org.eclipse.cdt.core.formatter.insert_space_after_opening_angle_bracket_in_template_arguments=do not insert +org.eclipse.cdt.core.formatter.insert_space_after_opening_angle_bracket_in_template_parameters=do not insert +org.eclipse.cdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert +org.eclipse.cdt.core.formatter.insert_space_after_opening_bracket=do not insert +org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_exception_specification=do not insert +org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.cdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.cdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.cdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.cdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.cdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.cdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.cdt.core.formatter.insert_space_before_closing_angle_bracket_in_template_arguments=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_closing_angle_bracket_in_template_parameters=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert +org.eclipse.cdt.core.formatter.insert_space_before_closing_bracket=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_exception_specification=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_colon_in_base_clause=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_colon_in_case=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.cdt.core.formatter.insert_space_before_colon_in_default=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_comma_in_base_types=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_comma_in_declarator_list=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_comma_in_expression_list=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_comma_in_template_arguments=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_comma_in_template_parameters=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_opening_angle_bracket_in_template_arguments=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_opening_angle_bracket_in_template_parameters=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_namespace_declaration=insert +org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.cdt.core.formatter.insert_space_before_opening_bracket=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_exception_specification=insert +org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.cdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.cdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.cdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.cdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.cdt.core.formatter.insert_space_between_empty_brackets=do not insert +org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_exception_specification=do not insert +org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.cdt.core.formatter.join_wrapped_lines=true +org.eclipse.cdt.core.formatter.keep_else_statement_on_same_line=false +org.eclipse.cdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.cdt.core.formatter.keep_imple_if_on_one_line=false +org.eclipse.cdt.core.formatter.keep_then_statement_on_same_line=false +org.eclipse.cdt.core.formatter.lineSplit=120 +org.eclipse.cdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.cdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.cdt.core.formatter.tabulation.char=space +org.eclipse.cdt.core.formatter.tabulation.size=4 +org.eclipse.cdt.core.formatter.use_tabs_only_for_leading_indentations=false diff --git a/.settings/org.eclipse.cdt.ui.prefs b/.settings/org.eclipse.cdt.ui.prefs new file mode 100644 index 0000000..f2ed7a2 --- /dev/null +++ b/.settings/org.eclipse.cdt.ui.prefs @@ -0,0 +1,3 @@ +eclipse.preferences.version=1 +formatter_profile=org.eclipse.cdt.ui.default.rtt_profile +formatter_settings_version=1 diff --git a/RTK/rtcm.c b/RTK/rtcm.c new file mode 100644 index 0000000..e882794 --- /dev/null +++ b/RTK/rtcm.c @@ -0,0 +1,345 @@ +#include "rtklib.h" + +/* function prototypes -------------------------------------------------------*/ +extern int decode_rtcm3(rtcm_t *rtcm); +/* 徲̬滻̬ */ +#ifdef STATIC +#define RTCM_STATIC +#endif + + +/* 徲̬滻̬ */ +/* constants -----------------------------------------------------------------*/ +#define RTCM3PREAMB 0xD3 /* rtcm ver.3 frame preamble */ + +/* initialize rtcm control ----------------------------------------------------- + * initialize rtcm control struct and reallocate memory for observation and + * ephemeris buffer in rtcm control struct + * args : rtcm_t *raw IO rtcm control struct + * return : status (1:ok,0:memory allocation error) + *-----------------------------------------------------------------------------*/ +extern int init_rtcm(rtcm_t *rtcm) +{ + gtime_t time0 = {0}; + obsd_t data0 = {{0}}; + eph_t eph0 = {0, -1, -1}; +#ifdef ENAGLO + geph_t geph0 = {0, -1}; +#endif + // ssr_t ssr0={{{0}}}; + + int i, j; + + trace(4, "init_rtcm:\n"); + + rtcm->staid = rtcm->stah = rtcm->seqno = 0; + // rtcm->outtype = 0; + rtcm->time = rtcm->time_s = time0; + rtcm->sta.name[0] = rtcm->sta.marker[0] = '\0'; + rtcm->sta.antdes[0] = rtcm->sta.antsno[0] = '\0'; + rtcm->sta.rectype[0] = rtcm->sta.recver[0] = rtcm->sta.recsno[0] = '\0'; + rtcm->sta.antsetup = rtcm->sta.itrf = rtcm->sta.deltype = 0; + for (i = 0; i < 3; i++) + { + rtcm->sta.pos[i] = rtcm->sta.del[i] = 0.0; + } + rtcm->sta.hgt = 0.0; + //rtcm->dgps = NULL; + // for (i=0;issr[i]=ssr0; + // } + // rtcm->msg[0]=rtcm->msgtype[0]=rtcm->opt[0]='\0'; + for (i = 0; i < 6; i++) + rtcm->msmtype[i][0] = '\0'; + rtcm->obsflag = rtcm->ephsat = 0; + for (i = 0; i < MAXSAT; i++) + for (j = 0; j < NFREQ + NEXOBS; j++) + { + rtcm->cp[i][j] = 0.0; + rtcm->lock[i][j] = rtcm->loss[i][j] = 0; + rtcm->lltime[i][j] = time0; + } + rtcm->nbit = rtcm->len = 0; + rtcm->nbyte = 0; + // rtcm->word=0; + // for (i=0;i<100;i++) rtcm->nmsg2[i]=0; + for (i = 0; i < 400; i++) + rtcm->nmsg3[i] = 0; + + rtcm->obs.data = NULL; + rtcm->nav.eph = NULL; + rtcm->nav.geph = NULL; + + /* reallocate memory for observation and ephemeris buffer */ + +#ifndef ENAGLO + if (!(rtcm->obs.data = (obsd_t *)malloc(sizeof(obsd_t) * MAXOBS)) || + !(rtcm->nav.eph = (eph_t *)malloc(sizeof(eph_t) * MAXSAT * 1))) +#else + if (!(rtcm->obs.data = (obsd_t *)malloc(sizeof(obsd_t) * MAXOBS)) || + !(rtcm->nav.eph = (eph_t *)malloc(sizeof(eph_t) * MAXSAT)) || + !(rtcm->nav.geph = (geph_t *)malloc(sizeof(geph_t) * MAXPRNGLO))) +#endif + { + free_rtcm(rtcm); + return 0; + } + rtcm->obs.n = 0; + rtcm->nav.n = MAXSAT * 1; /* ջ (ǰ) */ + rtcm->nav.ng = MAXPRNGLO; + for (i = 0; i < MAXOBS; i++) + rtcm->obs.data[i] = data0; + for (i = 0; i < MAXSAT * 1; i++) + rtcm->nav.eph[i] = eph0; +#ifdef ENAGLO + for (i = 0; i < MAXPRNGLO; i++) + rtcm->nav.geph[i] = geph0; +#endif + return 1; +} +/* initialize rtcm control ----------------------------------------------------- + * initialize rtcm control struct and reallocate memory for observation and + * ephemeris buffer in rtcm control struct + * args : rtcm_t *raw IO rtcm control struct + * return : status (1:ok,0:memory allocation error) + *-----------------------------------------------------------------------------*/ +extern int init_rtcm_static(rtcm_t *rtcm, char index) +{ + gtime_t time0 = {0}; + obsd_t data0 = {{0}}; + eph_t eph0 = {0, -1, -1}; + extern obsd_t RTCM_obsd_r[MAXOBS]; + extern obsd_t RTCM_obsd_b[MAXOBS]; + extern eph_t RTCM_eph_r[MAXSAT]; +#ifdef ENAGLO + extern eph_t RTCM_geph[MAXPRNGLO]; + geph_t geph0 = {0, -1}; +#endif + // ssr_t ssr0={{{0}}}; + + int i, j; + + trace(4, "init_rtcm:\n"); + + rtcm->staid = rtcm->stah = rtcm->seqno = 0; + // rtcm->outtype = 0; + rtcm->time = rtcm->time_s = time0; + rtcm->sta.name[0] = rtcm->sta.marker[0] = '\0'; + rtcm->sta.antdes[0] = rtcm->sta.antsno[0] = '\0'; + rtcm->sta.rectype[0] = rtcm->sta.recver[0] = rtcm->sta.recsno[0] = '\0'; + rtcm->sta.antsetup = rtcm->sta.itrf = rtcm->sta.deltype = 0; + for (i = 0; i < 3; i++) + { + rtcm->sta.pos[i] = rtcm->sta.del[i] = 0.0; + } + rtcm->sta.hgt = 0.0; + //rtcm->dgps = NULL; + // for (i=0;issr[i]=ssr0; + // } + // rtcm->msg[0]=rtcm->msgtype[0]=rtcm->opt[0]='\0'; + for (i = 0; i < 6; i++) + rtcm->msmtype[i][0] = '\0'; + rtcm->obsflag = rtcm->ephsat = 0; + for (i = 0; i < MAXSAT; i++) + for (j = 0; j < NFREQ + NEXOBS; j++) + { + rtcm->cp[i][j] = 0.0; + rtcm->lock[i][j] = rtcm->loss[i][j] = 0; + rtcm->lltime[i][j] = time0; + } + rtcm->nbit = rtcm->len = 0; + rtcm->nbyte = 0; + // rtcm->word=0; + // for (i=0;i<100;i++) rtcm->nmsg2[i]=0; + for (i = 0; i < 400; i++) + rtcm->nmsg3[i] = 0; + + rtcm->obs.data = NULL; + rtcm->nav.eph = NULL; + rtcm->nav.geph = NULL; + + /* reallocate memory for observation and ephemeris buffer */ + if (index == 0) /* ջ̬ */ + { + memset(RTCM_obsd_r,0,MAXOBS); + memset(RTCM_eph_r,0,MAXSAT); + rtcm->obs.data = RTCM_obsd_r; + rtcm->nav.eph = RTCM_eph_r; + rtcm->obs.n = 0; + rtcm->nav.n = MAXSAT * 1; /* ջ (ǰ) */ + rtcm->nav.ng = MAXPRNGLO; + for (i = 0; i < MAXOBS; i++) + rtcm->obs.data[i] = data0; + for (i = 0; i < MAXSAT * 1; i++) + rtcm->nav.eph[i] = eph0; + } + else /* ׼վ̬ */ + { + memset(RTCM_obsd_b,0,MAXOBS); + rtcm->obs.data = RTCM_obsd_b; + rtcm->obs.n = 0; + rtcm->nav.n = 0; /* ׼վ */ + rtcm->nav.ng = 0; + for (i = 0; i < MAXOBS; i++) + rtcm->obs.data[i] = data0; + } +#ifdef ENAGLO + if (index == 0) + { + memset(RTCM_geph_r,0,MAXPRNGLO); + rtcm->nav.geph = RTCM_geph_r; + for (i = 0; i < MAXPRNGLO; i++) + rtcm->nav.geph[i] = geph0; + } +#endif + + return 1; +} +/* free rtcm control ---------------------------------------------------------- + * free observation and ephemeris buffer in rtcm control struct + * args : rtcm_t *raw IO rtcm control struct + * return : none + *-----------------------------------------------------------------------------*/ +extern void free_rtcm(rtcm_t *rtcm) +{ + trace(4, "free_rtcm:\n"); + +/* free memory for observation and ephemeris buffer */ +#ifndef RTCM_STATIC + free(rtcm->obs.data); + rtcm->obs.data = NULL; + free(rtcm->nav.eph); + rtcm->nav.eph = NULL; + free(rtcm->nav.geph); + rtcm->nav.geph = NULL; +#endif + rtcm->nav.ng = 0; + rtcm->obs.n = 0; + rtcm->nav.n = 0; +} + +/* input RTCM 3 message from stream -------------------------------------------- + * fetch next RTCM 3 message and input a message from byte stream + * args : rtcm_t *rtcm IO rtcm control struct + * uint8_t data I stream data (1 byte) + * return : status (-1: error message, 0: no message, 1: input observation data, + * 2: input ephemeris, 5: input station pos/ant parameters, + * 10: input ssr messages) + * notes : before firstly calling the function, time in rtcm control struct has + * to be set to the approximate time within 1/2 week in order to resolve + * ambiguity of time in rtcm messages. + * + * to specify input options, set rtcm->opt to the following option + * strings separated by spaces. + * + * -EPHALL : input all ephemerides (default: only new) + * -STA=nnn : input only message with STAID=nnn (default: all) + * -GLss : select signal ss for GPS MSM (ss=1C,1P,...) + * -RLss : select signal ss for GLO MSM (ss=1C,1P,...) + * -ELss : select signal ss for GAL MSM (ss=1C,1B,...) + * -JLss : select signal ss for QZS MSM (ss=1C,2C,...) + * -CLss : select signal ss for BDS MSM (ss=2I,7I,...) + * -ILss : select signal ss for IRN MSM (ss=5A,9A,...) + * -GALINAV : select I/NAV for Galileo ephemeris (default: all) + * -GALFNAV : select F/NAV for Galileo ephemeris (default: all) + * + * supported RTCM 3 messages (ref [7][10][15][16][17][18]) + * + * TYPE : GPS GLONASS Galileo QZSS BDS SBAS NavIC + * ---------------------------------------------------------------------- + * OBS COMP L1 : 1001~ 1009~ - - - - - + * FULL L1 : 1002 1010 - - - - - + * COMP L1L2: 1003~ 1011~ - - - - - + * FULL L1L2: 1004 1012 - - - - - + * + * NAV : 1019 1020 1045** 1044 1042 - 1041 + * - - 1046** - 63* - - + * + * MSM 1 : 1071~ 1081~ 1091~ 1111~ 1121~ 1101~ 1131~ + * 2 : 1072~ 1082~ 1092~ 1112~ 1122~ 1102~ 1132~ + * 3 : 1073~ 1083~ 1093~ 1113~ 1123~ 1103~ 1133~ + * 4 : 1074 1084 1094 1114 1124 1104 1134 + * 5 : 1075 1085 1095 1115 1125 1105 1135 + * 6 : 1076 1086 1096 1116 1126 1106 1136 + * 7 : 1077 1087 1097 1117 1127 1107 1137 + * + * SSR ORBIT : 1057 1063 1240* 1246* 1258* - - + * CLOCK : 1058 1064 1241* 1247* 1259* - - + * CODE BIAS: 1059 1065 1242* 1248* 1260* - - + * OBT/CLK : 1060 1066 1243* 1249* 1261* - - + * URA : 1061 1067 1244* 1250* 1262* - - + * HR-CLOCK : 1062 1068 1245* 1251* 1263* - - + * PHAS BIAS: 11* - 12* 13* 14* - - + * + * ANT/RCV INFO : 1007 1008 1033 + * STA POSITION : 1005 1006 + * + * PROPRIETARY : 4076 (IGS) + * ---------------------------------------------------------------------- + * (* draft, ** 1045:F/NAV,1046:I/NAV, ~ only encode) + * + * for MSM observation data with multiple signals for a frequency, + * a signal is selected according to internal priority. to select + * a specified signal, use the input options. + * + * RTCM 3 message format: + * +----------+--------+-----------+--------------------+----------+ + * | preamble | 000000 | length | data message | parity | + * +----------+--------+-----------+--------------------+----------+ + * |<-- 8 --->|<- 6 -->|<-- 10 --->|<--- length x 8 --->|<-- 24 -->| + * + *-----------------------------------------------------------------------------*/ +extern int input_rtcm3(rtcm_t *rtcm, uint8_t data) +{ + trace(5, "input_rtcm3: data=%02x\n", data); + + /* synchronize frame */ + if (rtcm->nbyte == 0) + { + if (data != RTCM3PREAMB) + return 0; + rtcm->buff[rtcm->nbyte++] = data; + return 0; + } + rtcm->buff[rtcm->nbyte++] = data; + + if (rtcm->nbyte == 3) + { + rtcm->len = getbitu(rtcm->buff, 14, 10) + 3; /* length without parity */ + } + if (rtcm->nbyte < 3 || rtcm->nbyte < rtcm->len + 3) + return 0; + rtcm->nbyte = 0; + + /* check parity */ + if (rtk_crc24q(rtcm->buff, rtcm->len) != getbitu(rtcm->buff, rtcm->len * 8, 24)) + { + trace(2, "rtcm3 parity error: len=%d\n", rtcm->len); + return 0; + } + /* decode rtcm3 message */ + return decode_rtcm3(rtcm); +} +/* input RTCM 3 message from file ---------------------------------------------- + * fetch next RTCM 3 message and input a messsage from file + * args : rtcm_t *rtcm IO rtcm control struct + * FILE *fp I file pointer + * return : status (-2: end of file, -1...10: same as above) + * notes : same as above + *-----------------------------------------------------------------------------*/ +extern int input_rtcm3f(rtcm_t *rtcm, FILE *fp) +{ + int i, data = 0, ret; + + trace(4, "input_rtcm3f: data=%02x\n", data); + + for (i = 0; i < 4096; i++) + { + if ((data = fgetc(fp)) == EOF) + return -2; + if ((ret = input_rtcm3(rtcm, (uint8_t)data))) + return ret; + } + return 0; /* return at every 4k bytes */ +} diff --git a/RTK/rtcm3.c b/RTK/rtcm3.c new file mode 100644 index 0000000..a3eda32 --- /dev/null +++ b/RTK/rtcm3.c @@ -0,0 +1,2600 @@ +#include "rtklib.h" +/* RTCM3ְ֧ ---------------------------------------------------------- +* notes : RTCM3ĵ,ϸ˳õĹ +* args : ʹdefine Ӧϵͳ +* RTCM3_ENGPS : ʹGPSϵͳRTCMĽ +* RTCM3_ENGLO : ʹGLOϵͳRTCMĽ +* RTCM3_ENGAL : ʹGALϵͳRTCMĽ +* RTCM3_ENBDS : ʹCMPϵͳRTCMĽ +* RTCM3_ENQZS : ʹQZSϵͳRTCMĽ +* RTCM3_ENIRN : ʹIRNϵͳRTCMĽ (δ) +* RTCM3_ENSBS : ʹSBSϵͳRTCMĽ (δ) +* history : 2022/05/28 RTKlibĻ + 1. ͨ궨ֱ + 2. ŻRTCMṹ,ȡmsgouttype + 3. ޸BDS-RTCM-L5IJֵ֧ + 4. ɾ˲ֲֵ֧ĵ +*-----------------------------------------------------------------------------*/ +/* enalb RTCM3 system----*/ +#define RTCM3_ENGPS +#define RTCM3_ENBDS +// #define RTCM3_ENQZS +/* constants -----------------------------------------------------------------*/ +#define P2_10 0.0009765625 /* 2^-10 */ +#define P2_28 3.725290298461914E-09 /* 2^-28 */ +#define P2_34 5.820766091346740E-11 /* 2^-34 */ +#define P2_41 4.547473508864641E-13 /* 2^-41 */ +#define P2_46 1.421085471520200E-14 /* 2^-46 */ +#define P2_59 1.734723475976810E-18 /* 2^-59 */ +#define P2_66 1.355252715606880E-20 /* 2^-66 */ +#define RANGE_MS (CLIGHT*0.001) /* range in 1 ms */ + +#ifdef RTCM3_ENGPS +#define PRUNIT_GPS 299792.458 /* rtcm ver.3 unit of gps pseudorange (m) */ +#endif + +#ifdef RTCM3_ENGLO +#define PRUNIT_GLO 599584.916 /* rtcm ver.3 unit of glonass pseudorange (m) */ +#endif + +/* type definition -----------------------------------------------------------*/ +typedef struct { /* multi-signal-message header type */ + uint8_t iod; /* issue of data station */ + uint8_t time_s; /* cumulative session transmitting time */ + uint8_t clk_str; /* clock steering indicator */ + uint8_t clk_ext; /* external clock indicator */ + uint8_t smooth; /* divergence free smoothing indicator */ + uint8_t tint_s; /* soothing interval */ + uint8_t nsat,nsig; /* number of satellites/signals */ + uint8_t sats[64]; /* satellites */ + uint8_t sigs[32]; /* signals */ + uint8_t cellmask[64]; /* cell mask */ +} msm_h_t; + + + +/* MSM signal ID table -------------------------------------------------------*/ +#ifdef RTCM3_ENGPS +const char *msm_sig_gps[32]={ + /* GPS: ref [17] table 3.5-91 */ + "" ,"1C","1P","1W","" ,"" ,"" ,"2C","2P","2W","" ,"" , /* 1-12 */ + "" ,"" ,"2S","2L","2X","" ,"" ,"" ,"" ,"5I","5Q","5X", /* 13-24 */ + "" ,"" ,"" ,"" ,"" ,"1S","1L","1X" /* 25-32 */ +}; +#endif +#ifdef RTCM3_ENGLO +const char *msm_sig_glo[32]={ + /* GLONASS: ref [17] table 3.5-96 */ + "" ,"1C","1P","" ,"" ,"" ,"" ,"2C","2P","" ,"" ,"" , + "" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" , + "" ,"" ,"" ,"" ,"" ,"" ,"" ,"" +}; +#endif +#ifdef RTCM3_ENGAL +const char *msm_sig_gal[32]={ + /* Galileo: ref [17] table 3.5-99 */ + "" ,"1C","1A","1B","1X","1Z","" ,"6C","6A","6B","6X","6Z", + "" ,"7I","7Q","7X","" ,"8I","8Q","8X","" ,"5I","5Q","5X", + "" ,"" ,"" ,"" ,"" ,"" ,"" ,"" +}; +#endif +#ifdef RTCM3_ENQZS +const char *msm_sig_qzs[32]={ + /* QZSS: ref [17] table 3.5-105 */ + "" ,"1C","" ,"" ,"" ,"" ,"" ,"" ,"6S","6L","6X","" , + "" ,"" ,"2S","2L","2X","" ,"" ,"" ,"" ,"5I","5Q","5X", + "" ,"" ,"" ,"" ,"" ,"1S","1L","1X" +}; +#endif +#ifdef RTCM3_ENSBS +const char *msm_sig_sbs[32]={ + /* SBAS: ref [17] table 3.5-102 */ + "" ,"1C","" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" , + "" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"5I","5Q","5X", + "" ,"" ,"" ,"" ,"" ,"" ,"" ,"" +}; +#endif +#ifdef RTCM3_ENBDS +/* ???BDS L5 B2a ???? RINEX 3.05 */ +const char* msm_sig_cmp[32] = { + /* BeiDou: ref [17] table 3.5-108 */ + "" ,"2I","2Q","2X","" ,"" ,"" ,"6I","6Q","6X","" ,"" , /*1-12*/ + "" ,"7I","7Q","7X","" ,"" ,"" ,"" ,"" ,"5D","5P","5X", /*13-24*/ + "7D","" ,"" ,"" ,"" ,"1D" ,"1P" ,"1X" /*25-32*/ +}; +#endif +#ifdef RTCM3_ENIRN +const char *msm_sig_irn[32]={ + /* NavIC/IRNSS: ref [17] table 3.5-108.3 */ + "" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" , + "" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"" ,"5A","" ,"" , + "" ,"" ,"" ,"" ,"" ,"" ,"" ,"" +}; +#endif +#ifdef RTCM_ENA_SSR +/* SSR signal and tracking mode IDs ------------------------------------------*/ +const uint8_t ssr_sig_gps[32]={ + CODE_L1C,CODE_L1P,CODE_L1W,CODE_L1S,CODE_L1L,CODE_L2C,CODE_L2D,CODE_L2S, + CODE_L2L,CODE_L2X,CODE_L2P,CODE_L2W, 0, 0,CODE_L5I,CODE_L5Q +}; +const uint8_t ssr_sig_glo[32]={ + CODE_L1C,CODE_L1P,CODE_L2C,CODE_L2P,CODE_L4A,CODE_L4B,CODE_L6A,CODE_L6B, + CODE_L3I,CODE_L3Q +}; +const uint8_t ssr_sig_gal[32]={ + CODE_L1A,CODE_L1B,CODE_L1C, 0, 0,CODE_L5I,CODE_L5Q, 0, + CODE_L7I,CODE_L7Q, 0,CODE_L8I,CODE_L8Q, 0,CODE_L6A,CODE_L6B, + CODE_L6C +}; +const uint8_t ssr_sig_qzs[32]={ + CODE_L1C,CODE_L1S,CODE_L1L,CODE_L2S,CODE_L2L, 0,CODE_L5I,CODE_L5Q, + 0,CODE_L6S,CODE_L6L, 0, 0, 0, 0, 0, + 0,CODE_L6E +}; +const uint8_t ssr_sig_cmp[32]={ + CODE_L2I,CODE_L2Q, 0,CODE_L6I,CODE_L6Q, 0,CODE_L7I,CODE_L7Q, + 0,CODE_L1D,CODE_L1P, 0,CODE_L5D,CODE_L5P, 0,CODE_L1A, + 0, 0,CODE_L6A +}; +const uint8_t ssr_sig_sbs[32]={ + CODE_L1C,CODE_L5I,CODE_L5Q +}; +/* SSR update intervals ------------------------------------------------------*/ +static const double ssrudint[16]={ + 1,2,5,10,15,30,60,120,240,300,600,900,1800,3600,7200,10800 +}; +#endif +/* get sign-magnitude bits ---------------------------------------------------*/ +static double getbitg(const uint8_t *buff, int pos, int len) +{ + double value=getbitu(buff,pos+1,len-1); + return getbitu(buff,pos,1)?-value:value; +} +/* adjust weekly rollover of GPS time ----------------------------------------*/ +static void adjweek(rtcm_t *rtcm, double tow) +{ + double tow_p; + int week; + + /* if no time, get cpu time */ + if (rtcm->time.time==0) rtcm->time=utc2gpst(timeget()); + tow_p=time2gpst(rtcm->time,&week); + if (towtow_p+302400.0) tow-=604800.0; + rtcm->time=gpst2time(week,tow); +} +/* adjust weekly rollover of BDS time ----------------------------------------*/ +static int adjbdtweek(int week) +{ + int w; + (void)time2bdt(gpst2bdt(utc2gpst(timeget())),&w); + if (w<1) w=1; /* use 2006/1/1 if time is earlier than 2006/1/1 */ + return week+(w-week+512)/1024*1024; +} +/* adjust daily rollover of GLONASS time -------------------------------------*/ +static void adjday_glot(rtcm_t *rtcm, double tod) +{ + gtime_t time; + double tow,tod_p; + int week; + + if (rtcm->time.time==0) rtcm->time=utc2gpst(timeget()); + time=timeadd(gpst2utc(rtcm->time),10800.0); /* glonass time */ + tow=time2gpst(time,&week); + tod_p=fmod(tow,86400.0); tow-=tod_p; + if (todtod_p+43200.0) tod-=86400.0; + time=gpst2time(week,tow+tod); + rtcm->time=utc2gpst(timeadd(time,-10800.0)); +} +/* adjust carrier-phase rollover ---------------------------------------------*/ +static double adjcp(rtcm_t *rtcm, int sat, int idx, double cp) +{ + if (rtcm->cp[sat-1][idx]==0.0) ; + else if (cpcp[sat-1][idx]-750.0) cp+=1500.0; + else if (cp>rtcm->cp[sat-1][idx]+750.0) cp-=1500.0; + rtcm->cp[sat-1][idx]=cp; + return cp; +} +/* loss-of-lock indicator ----------------------------------------------------*/ +static int lossoflock(rtcm_t *rtcm, int sat, int idx, int lock) +{ + int lli=(!lock&&!rtcm->lock[sat-1][idx])||locklock[sat-1][idx]; + rtcm->lock[sat-1][idx]=(uint16_t)lock; + return lli; +} +/* S/N ratio -----------------------------------------------------------------*/ +static uint16_t snratio(double snr) +{ + return (uint16_t)(snr<=0.0||100.0<=snr?0.0:snr/SNR_UNIT+0.5); +} +/* get observation data index ------------------------------------------------*/ +static int obsindex(obs_t *obs, gtime_t time, int sat) +{ + int i,j; + + for (i=0;in;i++) { + if (obs->data[i].sat==sat) return i; /* field already exists */ + } + if (i>=MAXOBS) return -1; /* overflow */ + + /* add new field */ + obs->data[i].time=time; + obs->data[i].sat=sat; + for (j=0;jdata[i].L[j]=obs->data[i].P[j]=0.0; + obs->data[i].D[j]=0.0; + obs->data[i].SNR[j]=obs->data[i].LLI[j]=obs->data[i].code[j]=0; + } + obs->n++; + return i; +} +/* test station ID consistency -----------------------------------------------*/ +static int test_staid(rtcm_t *rtcm, int staid) +{ + //char *p; + //int id; + int type; + + /* test station id option */ + //if ((p=strstr(rtcm->opt,"-STA="))&&sscanf(p,"-STA=%d",&id)==1) { + // if (staid!=id) return 0; + //} + /* save station id */ + if (rtcm->staid==0||rtcm->obsflag) { + rtcm->staid=staid; + } + else if (staid!=rtcm->staid) { + type=getbitu(rtcm->buff,24,12); + trace(2,"rtcm3 %d staid invalid id=%d %d\n",type,staid,rtcm->staid); + + /* reset station id if station id error */ + rtcm->staid=0; + return 0; + } + return 1; +} +/* decode type 1001-1004 message header --------------------------------------*/ +static int decode_head1001(rtcm_t *rtcm, int *sync) +{ + double tow; + //char* msg; + char tstr[64]; + int i=24,staid,nsat,type; + + type=getbitu(rtcm->buff,i,12); i+=12; + + if (i+52<=rtcm->len*8) { + staid=getbitu(rtcm->buff,i,12); i+=12; + tow =getbitu(rtcm->buff,i,30)*0.001; i+=30; + *sync=getbitu(rtcm->buff,i, 1); i+= 1; + nsat =getbitu(rtcm->buff,i, 5); + } + else { + trace(2,"rtcm3 %d length error: len=%d\n",type,rtcm->len); + return -1; + } + /* test station ID */ + if (!test_staid(rtcm,staid)) return -1; + + adjweek(rtcm,tow); + + time2str(rtcm->time,tstr,2); + trace(4,"decode_head1001: time=%s nsat=%d sync=%d\n",tstr,nsat,*sync); + + //if (rtcm->outtype) { + // msg=rtcm->msgtype+strlen(rtcm->msgtype); + // sprintf(msg," staid=%4d %s nsat=%2d sync=%d",staid,tstr,nsat,*sync); + //} + return nsat; +} + +/* decode type 1002: extended L1-only GPS RTK observables --------------------*/ +static int decode_type1002(rtcm_t *rtcm) +{ + double pr1,cnr1,tt,cp1,freq=FREQL1; + int i=24+64,j,index,nsat,sync,prn,code,sat,ppr1,lock1,amb,sys; + + if ((nsat=decode_head1001(rtcm,&sync))<0) return -1; + + for (j=0;jobs.nlen*8;j++) { + prn =getbitu(rtcm->buff,i, 6); i+= 6; + code =getbitu(rtcm->buff,i, 1); i+= 1; + pr1 =getbitu(rtcm->buff,i,24); i+=24; + ppr1 =getbits(rtcm->buff,i,20); i+=20; + lock1=getbitu(rtcm->buff,i, 7); i+= 7; + amb =getbitu(rtcm->buff,i, 8); i+= 8; + cnr1 =getbitu(rtcm->buff,i, 8); i+= 8; + if (prn<40) { + sys=SYS_GPS; + } + else { + sys=SYS_SBS; prn+=80; + } + if (!(sat=satno(sys,prn))) { + trace(2,"rtcm3 1002 satellite number error: prn=%d\n",prn); + continue; + } + tt=timediff(rtcm->obs.data[0].time,rtcm->time); + if (rtcm->obsflag||fabs(tt)>1E-9) { + rtcm->obs.n=rtcm->obsflag=0; + } + if ((index=obsindex(&rtcm->obs,rtcm->time,sat))<0) continue; + pr1=pr1*0.02+amb*PRUNIT_GPS; + rtcm->obs.data[index].P[0]=pr1; + + if (ppr1!=(int)0xFFF80000) { + cp1=adjcp(rtcm,sat,0,ppr1*0.0005*freq/CLIGHT); + rtcm->obs.data[index].L[0]=pr1*freq/CLIGHT+cp1; + } + rtcm->obs.data[index].LLI[0]=lossoflock(rtcm,sat,0,lock1); + rtcm->obs.data[index].SNR[0]=snratio(cnr1*0.25); + rtcm->obs.data[index].code[0]=code?CODE_L1P:CODE_L1C; + } + return sync?0:1; +} + +/* decode type 1004: extended L1&L2 GPS RTK observables ----------------------*/ +static int decode_type1004(rtcm_t *rtcm) +{ + const int L2codes[]={CODE_L2X,CODE_L2P,CODE_L2D,CODE_L2W}; + double pr1,cnr1,cnr2,tt,cp1,cp2,freq[2]={FREQL1,FREQL2}; + int i=24+64,j,index,nsat,sync,prn,sat,code1,code2,pr21,ppr1,ppr2; + int lock1,lock2,amb,sys; + + if ((nsat=decode_head1001(rtcm,&sync))<0) return -1; + + for (j=0;jobs.nlen*8;j++) { + prn =getbitu(rtcm->buff,i, 6); i+= 6; + code1=getbitu(rtcm->buff,i, 1); i+= 1; + pr1 =getbitu(rtcm->buff,i,24); i+=24; + ppr1 =getbits(rtcm->buff,i,20); i+=20; + lock1=getbitu(rtcm->buff,i, 7); i+= 7; + amb =getbitu(rtcm->buff,i, 8); i+= 8; + cnr1 =getbitu(rtcm->buff,i, 8); i+= 8; + code2=getbitu(rtcm->buff,i, 2); i+= 2; + pr21 =getbits(rtcm->buff,i,14); i+=14; + ppr2 =getbits(rtcm->buff,i,20); i+=20; + lock2=getbitu(rtcm->buff,i, 7); i+= 7; + cnr2 =getbitu(rtcm->buff,i, 8); i+= 8; + if (prn<40) { + sys=SYS_GPS; + } + else { + sys=SYS_SBS; prn+=80; + } + if (!(sat=satno(sys,prn))) { + trace(2,"rtcm3 1004 satellite number error: sys=%d prn=%d\n",sys,prn); + continue; + } + tt=timediff(rtcm->obs.data[0].time,rtcm->time); + if (rtcm->obsflag||fabs(tt)>1E-9) { + rtcm->obs.n=rtcm->obsflag=0; + } + if ((index=obsindex(&rtcm->obs,rtcm->time,sat))<0) continue; + pr1=pr1*0.02+amb*PRUNIT_GPS; + rtcm->obs.data[index].P[0]=pr1; + + if (ppr1!=(int)0xFFF80000) { + cp1=adjcp(rtcm,sat,0,ppr1*0.0005*freq[0]/CLIGHT); + rtcm->obs.data[index].L[0]=pr1*freq[0]/CLIGHT+cp1; + } + rtcm->obs.data[index].LLI[0]=lossoflock(rtcm,sat,0,lock1); + rtcm->obs.data[index].SNR[0]=snratio(cnr1*0.25); + rtcm->obs.data[index].code[0]=code1?CODE_L1P:CODE_L1C; + + if (pr21!=(int)0xFFFFE000) { + rtcm->obs.data[index].P[1]=pr1+pr21*0.02; + } + if (ppr2!=(int)0xFFF80000) { + cp2=adjcp(rtcm,sat,1,ppr2*0.0005*freq[1]/CLIGHT); + rtcm->obs.data[index].L[1]=pr1*freq[1]/CLIGHT+cp2; + } + rtcm->obs.data[index].LLI[1]=lossoflock(rtcm,sat,1,lock2); + rtcm->obs.data[index].SNR[1]=snratio(cnr2*0.25); + rtcm->obs.data[index].code[1]=L2codes[code2]; + } + rtcm->obsflag=!sync; + return sync?0:1; +} +/* get signed 38bit field ----------------------------------------------------*/ +static double getbits_38(const uint8_t *buff, int pos) +{ + return (double)getbits(buff,pos,32)*64.0+getbitu(buff,pos+32,6); +} +/* decode type 1005: stationary RTK reference station ARP --------------------*/ +static int decode_type1005(rtcm_t *rtcm) +{ + double rr[3]; + //double re[3]; + //double pos[3]; + //char *msg; + int i=24+12,j,staid,itrf; + + if (i+140==rtcm->len*8) { + staid=getbitu(rtcm->buff,i,12); i+=12; + itrf =getbitu(rtcm->buff,i, 6); i+= 6+4; + rr[0]=getbits_38(rtcm->buff,i); i+=38+2; + rr[1]=getbits_38(rtcm->buff,i); i+=38+2; + rr[2]=getbits_38(rtcm->buff,i); + } + else { + trace(2,"rtcm3 1005 length error: len=%d\n",rtcm->len); + return -1; + } + //if (rtcm->outtype) { + // msg=rtcm->msgtype+strlen(rtcm->msgtype); + // for (j=0;j<3;j++) re[j]=rr[j]*0.0001; + // ecef2pos(re,pos); + // sprintf(msg," staid=%4d pos=%.8f %.8f %.3f",staid,pos[0]*R2D,pos[1]*R2D, + // pos[2]); + //} + + /* test station id */ + if (!test_staid(rtcm,staid)) return -1; + + sprintf(rtcm->sta.name,"%04d",staid); + rtcm->sta.deltype=0; /* xyz */ + for (j=0;j<3;j++) { + rtcm->sta.pos[j]=rr[j]*0.0001; + rtcm->sta.del[j]=0.0; + } + rtcm->sta.hgt=0.0; + rtcm->sta.itrf=itrf; + return 5; +} +/* decode type 1006: stationary RTK reference station ARP with height --------*/ +static int decode_type1006(rtcm_t *rtcm) +{ + double rr[3],anth; + //double re[3], pos[3]; + //char *msg; + int i=24+12,j,staid,itrf; + + if (i+156<=rtcm->len*8) { + staid=getbitu(rtcm->buff,i,12); i+=12; + itrf =getbitu(rtcm->buff,i, 6); i+= 6+4; + rr[0]=getbits_38(rtcm->buff,i); i+=38+2; + rr[1]=getbits_38(rtcm->buff,i); i+=38+2; + rr[2]=getbits_38(rtcm->buff,i); i+=38; + anth =getbitu(rtcm->buff,i,16); + } + else { + trace(2,"rtcm3 1006 length error: len=%d\n",rtcm->len); + return -1; + } + //if (rtcm->outtype) { + // msg=rtcm->msgtype+strlen(rtcm->msgtype); + // for (j=0;j<3;j++) re[j]=rr[j]*0.0001; + // ecef2pos(re,pos); + // sprintf(msg," staid=%4d pos=%.8f %.8f %.3f anth=%.3f",staid,pos[0]*R2D, + // pos[1]*R2D,pos[2],anth*0.0001); + //} + /* test station id */ + if (!test_staid(rtcm,staid)) return -1; + + sprintf(rtcm->sta.name,"%04d",staid); + rtcm->sta.deltype=1; /* xyz */ + for (j=0;j<3;j++) { + rtcm->sta.pos[j]=rr[j]*0.0001; + rtcm->sta.del[j]=0.0; + } + rtcm->sta.hgt=anth*0.0001; + rtcm->sta.itrf=itrf; + return 5; +} +/* decode type 1007: antenna descriptor --------------------------------------*/ +static int decode_type1007(rtcm_t *rtcm) +{ + char des[32]=""; + //char *msg; + int i=24+12,j,staid,n,setup; + + n=getbitu(rtcm->buff,i+12,8); + + if (i+28+8*n<=rtcm->len*8) { + staid=getbitu(rtcm->buff,i,12); i+=12+8; + for (j=0;jbuff,i,8); i+=8; + } + setup=getbitu(rtcm->buff,i, 8); + } + else { + trace(2,"rtcm3 1007 length error: len=%d\n",rtcm->len); + return -1; + } + //if (rtcm->outtype) { + // msg=rtcm->msgtype+strlen(rtcm->msgtype); + // sprintf(msg," staid=%4d",staid); + //} + /* test station ID */ + if (!test_staid(rtcm,staid)) return -1; + + sprintf(rtcm->sta.name,"%04d",staid); + strncpy(rtcm->sta.antdes,des,n); rtcm->sta.antdes[n]='\0'; + rtcm->sta.antsetup=setup; + rtcm->sta.antsno[0]='\0'; + return 5; +} +/* decode type 1008: antenna descriptor & serial number ----------------------*/ +static int decode_type1008(rtcm_t *rtcm) +{ + char des[32]="",sno[32]=""; + //char *msg; + int i=24+12,j,staid,n,m,setup; + + n=getbitu(rtcm->buff,i+12,8); + m=getbitu(rtcm->buff,i+28+8*n,8); + + if (i+36+8*(n+m)<=rtcm->len*8) { + staid=getbitu(rtcm->buff,i,12); i+=12+8; + for (j=0;jbuff,i,8); i+=8; + } + setup=getbitu(rtcm->buff,i, 8); i+=8+8; + for (j=0;jbuff,i,8); i+=8; + } + } + else { + trace(2,"rtcm3 1008 length error: len=%d\n",rtcm->len); + return -1; + } + //if (rtcm->outtype) { + // msg=rtcm->msgtype+strlen(rtcm->msgtype); + // sprintf(msg," staid=%4d",staid); + //} + /* test station ID */ + if (!test_staid(rtcm,staid)) return -1; + + sprintf(rtcm->sta.name,"%04d",staid); + strncpy(rtcm->sta.antdes,des,n); rtcm->sta.antdes[n]='\0'; + rtcm->sta.antsetup=setup; + strncpy(rtcm->sta.antsno,sno,m); rtcm->sta.antsno[m]='\0'; + return 5; +} +#ifdef RTCM3_ENGLO +/* decode type 1009-1012 message header --------------------------------------*/ +static int decode_head1009(rtcm_t *rtcm, int *sync) +{ + double tod; + //char* msg; + char tstr[64]; + int i=24,staid,nsat,type; + + type=getbitu(rtcm->buff,i,12); i+=12; + + if (i+49<=rtcm->len*8) { + staid=getbitu(rtcm->buff,i,12); i+=12; + tod =getbitu(rtcm->buff,i,27)*0.001; i+=27; /* sec in a day */ + *sync=getbitu(rtcm->buff,i, 1); i+= 1; + nsat =getbitu(rtcm->buff,i, 5); + } + else { + trace(2,"rtcm3 %d length error: len=%d\n",type,rtcm->len); + return -1; + } + /* test station ID */ + if (!test_staid(rtcm,staid)) return -1; + + adjday_glot(rtcm,tod); + + time2str(rtcm->time,tstr,2); + trace(4,"decode_head1009: time=%s nsat=%d sync=%d\n",tstr,nsat,*sync); + + //if (rtcm->outtype) { + // msg=rtcm->msgtype+strlen(rtcm->msgtype); + // sprintf(msg," staid=%4d %s nsat=%2d sync=%d",staid,tstr,nsat,*sync); + //} + return nsat; +} +/* decode type 1010: extended L1-only glonass rtk observables ----------------*/ +static int decode_type1010(rtcm_t *rtcm) +{ + double pr1,cnr1,tt,cp1,freq1; + int i=24+61,j,index,nsat,sync,prn,sat,code,fcn,ppr1,lock1,amb,sys=SYS_GLO; + + if ((nsat=decode_head1009(rtcm,&sync))<0) return -1; + + for (j=0;jobs.nlen*8;j++) { + prn =getbitu(rtcm->buff,i, 6); i+= 6; + code =getbitu(rtcm->buff,i, 1); i+= 1; + fcn =getbitu(rtcm->buff,i, 5); i+= 5; /* fcn+7 */ + pr1 =getbitu(rtcm->buff,i,25); i+=25; + ppr1 =getbits(rtcm->buff,i,20); i+=20; + lock1=getbitu(rtcm->buff,i, 7); i+= 7; + amb =getbitu(rtcm->buff,i, 7); i+= 7; + cnr1 =getbitu(rtcm->buff,i, 8); i+= 8; + if (!(sat=satno(sys,prn))) { + trace(2,"rtcm3 1010 satellite number error: prn=%d\n",prn); + continue; + } + if (!rtcm->nav.glo_fcn[prn-1]) { + rtcm->nav.glo_fcn[prn-1]=fcn-7+8; /* fcn+8 */ + } + tt=timediff(rtcm->obs.data[0].time,rtcm->time); + if (rtcm->obsflag||fabs(tt)>1E-9) { + rtcm->obs.n=rtcm->obsflag=0; + } + if ((index=obsindex(&rtcm->obs,rtcm->time,sat))<0) continue; + pr1=pr1*0.02+amb*PRUNIT_GLO; + rtcm->obs.data[index].P[0]=pr1; + + if (ppr1!=(int)0xFFF80000) { + freq1=code2freq(SYS_GLO,CODE_L1C,fcn-7); + cp1=adjcp(rtcm,sat,0,ppr1*0.0005*freq1/CLIGHT); + rtcm->obs.data[index].L[0]=pr1*freq1/CLIGHT+cp1; + } + rtcm->obs.data[index].LLI[0]=lossoflock(rtcm,sat,0,lock1); + rtcm->obs.data[index].SNR[0]=snratio(cnr1*0.25); + rtcm->obs.data[index].code[0]=code?CODE_L1P:CODE_L1C; + } + return sync?0:1; +} + +/* decode type 1012: extended L1&L2 GLONASS RTK observables ------------------*/ +static int decode_type1012(rtcm_t *rtcm) +{ + double pr1,cnr1,cnr2,tt,cp1,cp2,freq1,freq2; + int i=24+61,j,index,nsat,sync,prn,sat,fcn,code1,code2,pr21,ppr1,ppr2; + int lock1,lock2,amb,sys=SYS_GLO; + + if ((nsat=decode_head1009(rtcm,&sync))<0) return -1; + + for (j=0;jobs.nlen*8;j++) { + prn =getbitu(rtcm->buff,i, 6); i+= 6; + code1=getbitu(rtcm->buff,i, 1); i+= 1; + fcn =getbitu(rtcm->buff,i, 5); i+= 5; /* fcn+7 */ + pr1 =getbitu(rtcm->buff,i,25); i+=25; + ppr1 =getbits(rtcm->buff,i,20); i+=20; + lock1=getbitu(rtcm->buff,i, 7); i+= 7; + amb =getbitu(rtcm->buff,i, 7); i+= 7; + cnr1 =getbitu(rtcm->buff,i, 8); i+= 8; + code2=getbitu(rtcm->buff,i, 2); i+= 2; + pr21 =getbits(rtcm->buff,i,14); i+=14; + ppr2 =getbits(rtcm->buff,i,20); i+=20; + lock2=getbitu(rtcm->buff,i, 7); i+= 7; + cnr2 =getbitu(rtcm->buff,i, 8); i+= 8; + if (!(sat=satno(sys,prn))) { + trace(2,"rtcm3 1012 satellite number error: sys=%d prn=%d\n",sys,prn); + continue; + } + if (!rtcm->nav.glo_fcn[prn-1]) { + rtcm->nav.glo_fcn[prn-1]=fcn-7+8; /* fcn+8 */ + } + tt=timediff(rtcm->obs.data[0].time,rtcm->time); + if (rtcm->obsflag||fabs(tt)>1E-9) { + rtcm->obs.n=rtcm->obsflag=0; + } + if ((index=obsindex(&rtcm->obs,rtcm->time,sat))<0) continue; + pr1=pr1*0.02+amb*PRUNIT_GLO; + rtcm->obs.data[index].P[0]=pr1; + + if (ppr1!=(int)0xFFF80000) { + freq1=code2freq(SYS_GLO,CODE_L1C,fcn-7); + cp1=adjcp(rtcm,sat,0,ppr1*0.0005*freq1/CLIGHT); + rtcm->obs.data[index].L[0]=pr1*freq1/CLIGHT+cp1; + } + rtcm->obs.data[index].LLI[0]=lossoflock(rtcm,sat,0,lock1); + rtcm->obs.data[index].SNR[0]=snratio(cnr1*0.25); + rtcm->obs.data[index].code[0]=code1?CODE_L1P:CODE_L1C; + + if (pr21!=(int)0xFFFFE000) { + rtcm->obs.data[index].P[1]=pr1+pr21*0.02; + } + if (ppr2!=(int)0xFFF80000) { + freq2=code2freq(SYS_GLO,CODE_L2C,fcn-7); + cp2=adjcp(rtcm,sat,1,ppr2*0.0005*freq2/CLIGHT); + rtcm->obs.data[index].L[1]=pr1*freq2/CLIGHT+cp2; + } + rtcm->obs.data[index].LLI[1]=lossoflock(rtcm,sat,1,lock2); + rtcm->obs.data[index].SNR[1]=snratio(cnr2*0.25); + rtcm->obs.data[index].code[1]=code2?CODE_L2P:CODE_L2C; + } + rtcm->obsflag=!sync; + return sync?0:1; +} +#endif +#ifdef RTCM3_ENGPS +/* decode type 1019: GPS ephemerides -----------------------------------------*/ +static int decode_type1019(rtcm_t *rtcm) +{ + eph_t eph={0}; + double toc,sqrtA,tt; + //char *msg; + int i=24+12,prn,sat,week,sys=SYS_GPS; + + if (i+476<=rtcm->len*8) { + prn =getbitu(rtcm->buff,i, 6); i+= 6; + week =getbitu(rtcm->buff,i,10); i+=10; + eph.sva =getbitu(rtcm->buff,i, 4); i+= 4; + eph.code =getbitu(rtcm->buff,i, 2); i+= 2; + eph.idot =getbits(rtcm->buff,i,14)*P2_43*SC2RAD; i+=14; + eph.iode =getbitu(rtcm->buff,i, 8); i+= 8; + toc =getbitu(rtcm->buff,i,16)*16.0; i+=16; + eph.f2 =getbits(rtcm->buff,i, 8)*P2_55; i+= 8; + eph.f1 =getbits(rtcm->buff,i,16)*P2_43; i+=16; + eph.f0 =getbits(rtcm->buff,i,22)*P2_31; i+=22; + eph.iodc =getbitu(rtcm->buff,i,10); i+=10; + eph.crs =getbits(rtcm->buff,i,16)*P2_5; i+=16; + eph.deln =getbits(rtcm->buff,i,16)*P2_43*SC2RAD; i+=16; + eph.M0 =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; + eph.cuc =getbits(rtcm->buff,i,16)*P2_29; i+=16; + eph.e =getbitu(rtcm->buff,i,32)*P2_33; i+=32; + eph.cus =getbits(rtcm->buff,i,16)*P2_29; i+=16; + sqrtA =getbitu(rtcm->buff,i,32)*P2_19; i+=32; + eph.toes =getbitu(rtcm->buff,i,16)*16.0; i+=16; + eph.cic =getbits(rtcm->buff,i,16)*P2_29; i+=16; + eph.OMG0 =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; + eph.cis =getbits(rtcm->buff,i,16)*P2_29; i+=16; + eph.i0 =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; + eph.crc =getbits(rtcm->buff,i,16)*P2_5; i+=16; + eph.omg =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; + eph.OMGd =getbits(rtcm->buff,i,24)*P2_43*SC2RAD; i+=24; + eph.tgd[0]=getbits(rtcm->buff,i, 8)*P2_31; i+= 8; + eph.svh =getbitu(rtcm->buff,i, 6); i+= 6; + eph.flag =getbitu(rtcm->buff,i, 1); i+= 1; + eph.fit =getbitu(rtcm->buff,i, 1)?0.0:4.0; /* 0:4hr,1:>4hr */ + } + else { + trace(2,"rtcm3 1019 length error: len=%d\n",rtcm->len); + return -1; + } + if (prn>=40) { + sys=SYS_SBS; prn+=80; + } + trace(4,"decode_type1019: prn=%d iode=%d toe=%.0f\n",prn,eph.iode,eph.toes); + + //if (rtcm->outtype) { + // msg=rtcm->msgtype+strlen(rtcm->msgtype); + // sprintf(msg," prn=%2d iode=%3d iodc=%3d week=%d toe=%6.0f toc=%6.0f svh=%02X", + // prn,eph.iode,eph.iodc,week,eph.toes,toc,eph.svh); + //} + if (!(sat=satno(sys,prn))) { + trace(2,"rtcm3 1019 satellite number error: prn=%d\n",prn); + return -1; + } + eph.sat=sat; + eph.week=adjgpsweek(week); + if (rtcm->time.time==0) rtcm->time=utc2gpst(timeget()); + tt=timediff(gpst2time(eph.week,eph.toes),rtcm->time); + if (tt<-302400.0) eph.week++; + else if (tt>=302400.0) eph.week--; + eph.toe=gpst2time(eph.week,eph.toes); + eph.toc=gpst2time(eph.week,toc); + eph.ttr=rtcm->time; + eph.A=sqrtA*sqrtA; + //if (!strstr(rtcm->opt,"-EPHALL")) { + // if (eph.iode==rtcm->nav.eph[sat-1].iode) return 0; /* unchanged */ + //} + rtcm->nav.eph[sat-1]=eph; + rtcm->ephsat=sat; + rtcm->ephset=0; + return 2; +} +#endif +#ifdef RTCM3_ENGLO +/* decode type 1020: GLONASS ephemerides -------------------------------------*/ +static int decode_type1020(rtcm_t *rtcm) +{ + geph_t geph={0}; + double tk_h,tk_m,tk_s,toe,tow,tod,tof; + //char *msg; + int i=24+12,prn,sat,week,tb,bn,sys=SYS_GLO; + + if (i+348<=rtcm->len*8) { + prn =getbitu(rtcm->buff,i, 6); i+= 6; + geph.frq =getbitu(rtcm->buff,i, 5)-7; i+= 5+2+2; + tk_h =getbitu(rtcm->buff,i, 5); i+= 5; + tk_m =getbitu(rtcm->buff,i, 6); i+= 6; + tk_s =getbitu(rtcm->buff,i, 1)*30.0; i+= 1; + bn =getbitu(rtcm->buff,i, 1); i+= 1+1; + tb =getbitu(rtcm->buff,i, 7); i+= 7; + geph.vel[0]=getbitg(rtcm->buff,i,24)*P2_20*1E3; i+=24; + geph.pos[0]=getbitg(rtcm->buff,i,27)*P2_11*1E3; i+=27; + geph.acc[0]=getbitg(rtcm->buff,i, 5)*P2_30*1E3; i+= 5; + geph.vel[1]=getbitg(rtcm->buff,i,24)*P2_20*1E3; i+=24; + geph.pos[1]=getbitg(rtcm->buff,i,27)*P2_11*1E3; i+=27; + geph.acc[1]=getbitg(rtcm->buff,i, 5)*P2_30*1E3; i+= 5; + geph.vel[2]=getbitg(rtcm->buff,i,24)*P2_20*1E3; i+=24; + geph.pos[2]=getbitg(rtcm->buff,i,27)*P2_11*1E3; i+=27; + geph.acc[2]=getbitg(rtcm->buff,i, 5)*P2_30*1E3; i+= 5+1; + geph.gamn =getbitg(rtcm->buff,i,11)*P2_40; i+=11+3; + geph.taun =getbitg(rtcm->buff,i,22)*P2_30; i+=22; + geph.dtaun =getbitg(rtcm->buff,i, 5)*P2_30; i+=5; + geph.age =getbitu(rtcm->buff,i, 5); + } + else { + trace(2,"rtcm3 1020 length error: len=%d\n",rtcm->len); + return -1; + } + if (!(sat=satno(sys,prn))) { + trace(2,"rtcm3 1020 satellite number error: prn=%d\n",prn); + return -1; + } + trace(4,"decode_type1020: prn=%d tk=%02.0f:%02.0f:%02.0f\n",prn,tk_h,tk_m,tk_s); + + //if (rtcm->outtype) { + // msg=rtcm->msgtype+strlen(rtcm->msgtype); + // sprintf(msg," prn=%2d tk=%02.0f:%02.0f:%02.0f frq=%2d bn=%d tb=%d", + // prn,tk_h,tk_m,tk_s,geph.frq,bn,tb); + //} + geph.sat=sat; + geph.svh=bn; + geph.iode=tb&0x7F; + if (rtcm->time.time==0) rtcm->time=utc2gpst(timeget()); + tow=time2gpst(gpst2utc(rtcm->time),&week); + tod=fmod(tow,86400.0); tow-=tod; + tof=tk_h*3600.0+tk_m*60.0+tk_s-10800.0; /* lt->utc */ + if (toftod+43200.0) tof-=86400.0; + geph.tof=utc2gpst(gpst2time(week,tow+tof)); + toe=tb*900.0-10800.0; /* lt->utc */ + if (toetod+43200.0) toe-=86400.0; + geph.toe=utc2gpst(gpst2time(week,tow+toe)); /* utc->gpst */ + + //if (!strstr(rtcm->opt,"-EPHALL")) { + // if (fabs(timediff(geph.toe,rtcm->nav.geph[prn-1].toe))<1.0&& + // geph.svh==rtcm->nav.geph[prn-1].svh) return 0; /* unchanged */ + //} + rtcm->nav.geph[prn-1]=geph; + rtcm->ephsat=sat; + rtcm->ephset=0; + return 2; +} +#endif +/* decode type 1029: UNICODE text string -------------------------------------*/ +static int decode_type1029(rtcm_t *rtcm) +{ + //char *msg; + int i=24+12,staid,mjd,tod,nchar,cunit; + //int j; + + if (i+60<=rtcm->len*8) { + staid=getbitu(rtcm->buff,i,12); i+=12; + mjd =getbitu(rtcm->buff,i,16); i+=16; + tod =getbitu(rtcm->buff,i,17); i+=17; + nchar=getbitu(rtcm->buff,i, 7); i+= 7; + cunit=getbitu(rtcm->buff,i, 8); i+= 8; + } + else { + trace(2,"rtcm3 1029 length error: len=%d\n",rtcm->len); + return -1; + } + if (i+nchar*8>rtcm->len*8) { + trace(2,"rtcm3 1029 length error: len=%d nchar=%d\n",rtcm->len,nchar); + return -1; + } + //for (j=0;jmsg[j]=getbitu(rtcm->buff,i,8); i+=8; + //} + //rtcm->msg[j]='\0'; + + //if (rtcm->outtype) { + // msg=rtcm->msgtype+strlen(rtcm->msgtype); + // sprintf(msg," staid=%4d text=%s",staid,rtcm->msg); + //} + return 0; +} + +/* decode type 1033: receiver and antenna descriptor -------------------------*/ +static int decode_type1033(rtcm_t *rtcm) +{ + char des[32]="",sno[32]="",rec[32]="",ver[32]="",rsn[32]=""; + //char *msg; + int i=24+12,j,staid,n,m,n1,n2,n3,setup; + + n =getbitu(rtcm->buff,i+12,8); + m =getbitu(rtcm->buff,i+28+8*n,8); + n1=getbitu(rtcm->buff,i+36+8*(n+m),8); + n2=getbitu(rtcm->buff,i+44+8*(n+m+n1),8); + n3=getbitu(rtcm->buff,i+52+8*(n+m+n1+n2),8); + + if (i+60+8*(n+m+n1+n2+n3)<=rtcm->len*8) { + staid=getbitu(rtcm->buff,i,12); i+=12+8; + for (j=0;jbuff,i,8); i+=8; + } + setup=getbitu(rtcm->buff,i, 8); i+=8+8; + for (j=0;jbuff,i,8); i+=8; + } + i+=8; + for (j=0;jbuff,i,8); i+=8; + } + i+=8; + for (j=0;jbuff,i,8); i+=8; + } + i+=8; + for (j=0;jbuff,i,8); i+=8; + } + } + else { + trace(2,"rtcm3 1033 length error: len=%d\n",rtcm->len); + return -1; + } + //if (rtcm->outtype) { + // msg=rtcm->msgtype+strlen(rtcm->msgtype); + // sprintf(msg," staid=%4d",staid); + //} + /* test station id */ + if (!test_staid(rtcm,staid)) return -1; + + sprintf(rtcm->sta.name,"%04d",staid); + strncpy(rtcm->sta.antdes, des,n ); rtcm->sta.antdes [n] ='\0'; + rtcm->sta.antsetup=setup; + strncpy(rtcm->sta.antsno, sno,m ); rtcm->sta.antsno [m] ='\0'; + strncpy(rtcm->sta.rectype,rec,n1); rtcm->sta.rectype[n1]='\0'; + strncpy(rtcm->sta.recver, ver,n2); rtcm->sta.recver [n2]='\0'; + strncpy(rtcm->sta.recsno, rsn,n3); rtcm->sta.recsno [n3]='\0'; + + trace(4,"rtcm3 1033: ant=%s:%s rec=%s:%s:%s\n",des,sno,rec,ver,rsn); + return 5; +} +#ifdef RTCM3_ENIRN +/* decode type 1041: NavIC/IRNSS ephemerides ---------------------------------*/ +static int decode_type1041(rtcm_t *rtcm) +{ + eph_t eph={0}; + double toc,sqrtA,tt; + char *msg; + int i=24+12,prn,sat,week,sys=SYS_IRN; + + if (i+482-12<=rtcm->len*8) { + prn =getbitu(rtcm->buff,i, 6); i+= 6; + week =getbitu(rtcm->buff,i,10); i+=10; + eph.f0 =getbits(rtcm->buff,i,22)*P2_31; i+=22; + eph.f1 =getbits(rtcm->buff,i,16)*P2_43; i+=16; + eph.f2 =getbits(rtcm->buff,i, 8)*P2_55; i+= 8; + eph.sva =getbitu(rtcm->buff,i, 4); i+= 4; + toc =getbitu(rtcm->buff,i,16)*16.0; i+=16; + eph.tgd[0]=getbits(rtcm->buff,i, 8)*P2_31; i+= 8; + eph.deln =getbits(rtcm->buff,i,22)*P2_41*SC2RAD; i+=22; + eph.iode =getbitu(rtcm->buff,i, 8); i+= 8+10; /* IODEC */ + eph.svh =getbitu(rtcm->buff,i, 2); i+= 2; /* L5+Sflag */ + eph.cuc =getbits(rtcm->buff,i,15)*P2_28; i+=15; + eph.cus =getbits(rtcm->buff,i,15)*P2_28; i+=15; + eph.cic =getbits(rtcm->buff,i,15)*P2_28; i+=15; + eph.cis =getbits(rtcm->buff,i,15)*P2_28; i+=15; + eph.crc =getbits(rtcm->buff,i,15)*0.0625; i+=15; + eph.crs =getbits(rtcm->buff,i,15)*0.0625; i+=15; + eph.idot =getbits(rtcm->buff,i,14)*P2_43*SC2RAD; i+=14; + eph.M0 =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; + eph.toes =getbitu(rtcm->buff,i,16)*16.0; i+=16; + eph.e =getbitu(rtcm->buff,i,32)*P2_33; i+=32; + sqrtA =getbitu(rtcm->buff,i,32)*P2_19; i+=32; + eph.OMG0 =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; + eph.omg =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; + eph.OMGd =getbits(rtcm->buff,i,22)*P2_41*SC2RAD; i+=22; + eph.i0 =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; + } + else { + trace(2,"rtcm3 1041 length error: len=%d\n",rtcm->len); + return -1; + } + trace(4,"decode_type1041: prn=%d iode=%d toe=%.0f\n",prn,eph.iode,eph.toes); + + //if (rtcm->outtype) { + // msg=rtcm->msgtype+strlen(rtcm->msgtype); + // sprintf(msg," prn=%2d iode=%3d week=%d toe=%6.0f toc=%6.0f svh=%02X", + // prn,eph.iode,week,eph.toes,toc,eph.svh); + //} + if (!(sat=satno(sys,prn))) { + trace(2,"rtcm3 1041 satellite number error: prn=%d\n",prn); + return -1; + } + eph.sat=sat; + eph.week=adjgpsweek(week); + if (rtcm->time.time==0) rtcm->time=utc2gpst(timeget()); + tt=timediff(gpst2time(eph.week,eph.toes),rtcm->time); + if (tt<-302400.0) eph.week++; + else if (tt>=302400.0) eph.week--; + eph.toe=gpst2time(eph.week,eph.toes); + eph.toc=gpst2time(eph.week,toc); + eph.ttr=rtcm->time; + eph.A=sqrtA*sqrtA; + eph.iodc=eph.iode; + //if (!strstr(rtcm->opt,"-EPHALL")) { + // if (eph.iode==rtcm->nav.eph[sat-1].iode) return 0; /* unchanged */ + //} + rtcm->nav.eph[sat-1]=eph; + rtcm->ephsat=sat; + rtcm->ephset=0; + return 2; +} +#endif +#ifdef RTCM3_ENQZS +/* decode type 1044: QZSS ephemerides ----------------------------------------*/ +static int decode_type1044(rtcm_t *rtcm) +{ + eph_t eph={0}; + double toc,sqrtA,tt; + //char *msg; + int i=24+12,prn,sat,week,sys=SYS_QZS; + + if (i+473<=rtcm->len*8) { + prn =getbitu(rtcm->buff,i, 4)+192; i+= 4; + toc =getbitu(rtcm->buff,i,16)*16.0; i+=16; + eph.f2 =getbits(rtcm->buff,i, 8)*P2_55; i+= 8; + eph.f1 =getbits(rtcm->buff,i,16)*P2_43; i+=16; + eph.f0 =getbits(rtcm->buff,i,22)*P2_31; i+=22; + eph.iode =getbitu(rtcm->buff,i, 8); i+= 8; + eph.crs =getbits(rtcm->buff,i,16)*P2_5; i+=16; + eph.deln =getbits(rtcm->buff,i,16)*P2_43*SC2RAD; i+=16; + eph.M0 =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; + eph.cuc =getbits(rtcm->buff,i,16)*P2_29; i+=16; + eph.e =getbitu(rtcm->buff,i,32)*P2_33; i+=32; + eph.cus =getbits(rtcm->buff,i,16)*P2_29; i+=16; + sqrtA =getbitu(rtcm->buff,i,32)*P2_19; i+=32; + eph.toes =getbitu(rtcm->buff,i,16)*16.0; i+=16; + eph.cic =getbits(rtcm->buff,i,16)*P2_29; i+=16; + eph.OMG0 =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; + eph.cis =getbits(rtcm->buff,i,16)*P2_29; i+=16; + eph.i0 =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; + eph.crc =getbits(rtcm->buff,i,16)*P2_5; i+=16; + eph.omg =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; + eph.OMGd =getbits(rtcm->buff,i,24)*P2_43*SC2RAD; i+=24; + eph.idot =getbits(rtcm->buff,i,14)*P2_43*SC2RAD; i+=14; + eph.code =getbitu(rtcm->buff,i, 2); i+= 2; + week =getbitu(rtcm->buff,i,10); i+=10; + eph.sva =getbitu(rtcm->buff,i, 4); i+= 4; + eph.svh =getbitu(rtcm->buff,i, 6); i+= 6; + eph.tgd[0]=getbits(rtcm->buff,i, 8)*P2_31; i+= 8; + eph.iodc =getbitu(rtcm->buff,i,10); i+=10; + eph.fit =getbitu(rtcm->buff,i, 1)?0.0:2.0; /* 0:2hr,1:>2hr */ + } + else { + trace(2,"rtcm3 1044 length error: len=%d\n",rtcm->len); + return -1; + } + trace(4,"decode_type1044: prn=%d iode=%d toe=%.0f\n",prn,eph.iode,eph.toes); + + // if (rtcm->outtype) { + // msg=rtcm->msgtype+strlen(rtcm->msgtype); + // sprintf(msg," prn=%3d iode=%3d iodc=%3d week=%d toe=%6.0f toc=%6.0f svh=%02X", + // prn,eph.iode,eph.iodc,week,eph.toes,toc,eph.svh); + // } + if (!(sat=satno(sys,prn))) { + trace(2,"rtcm3 1044 satellite number error: prn=%d\n",prn); + return -1; + } + eph.sat=sat; + eph.week=adjgpsweek(week); + if (rtcm->time.time==0) rtcm->time=utc2gpst(timeget()); + tt=timediff(gpst2time(eph.week,eph.toes),rtcm->time); + if (tt<-302400.0) eph.week++; + else if (tt>=302400.0) eph.week--; + eph.toe=gpst2time(eph.week,eph.toes); + eph.toc=gpst2time(eph.week,toc); + eph.ttr=rtcm->time; + eph.A=sqrtA*sqrtA; + eph.flag=1; /* fixed to 1 */ + //if (!strstr(rtcm->opt,"-EPHALL")) { + // if (eph.iode==rtcm->nav.eph[sat-1].iode&& + // eph.iodc==rtcm->nav.eph[sat-1].iodc) return 0; /* unchanged */ + //} + rtcm->nav.eph[sat-1]=eph; + rtcm->ephsat=sat; + rtcm->ephset=0; + return 2; +} +#endif +#ifdef RTCM3_ENGAL +/* decode type 1045: Galileo F/NAV satellite ephemerides ---------------------*/ +static int decode_type1045(rtcm_t *rtcm) +{ + eph_t eph={0}; + double toc,sqrtA,tt; + //char *msg; + int i=24+12,prn,sat,week,e5a_hs,e5a_dvs,rsv,sys=SYS_GAL; + + //if (strstr(rtcm->opt,"-GALINAV")) return 0; + + if (i+484<=rtcm->len*8) { + prn =getbitu(rtcm->buff,i, 6); i+= 6; + week =getbitu(rtcm->buff,i,12); i+=12; /* gst-week */ + eph.iode =getbitu(rtcm->buff,i,10); i+=10; + eph.sva =getbitu(rtcm->buff,i, 8); i+= 8; + eph.idot =getbits(rtcm->buff,i,14)*P2_43*SC2RAD; i+=14; + toc =getbitu(rtcm->buff,i,14)*60.0; i+=14; + eph.f2 =getbits(rtcm->buff,i, 6)*P2_59; i+= 6; + eph.f1 =getbits(rtcm->buff,i,21)*P2_46; i+=21; + eph.f0 =getbits(rtcm->buff,i,31)*P2_34; i+=31; + eph.crs =getbits(rtcm->buff,i,16)*P2_5; i+=16; + eph.deln =getbits(rtcm->buff,i,16)*P2_43*SC2RAD; i+=16; + eph.M0 =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; + eph.cuc =getbits(rtcm->buff,i,16)*P2_29; i+=16; + eph.e =getbitu(rtcm->buff,i,32)*P2_33; i+=32; + eph.cus =getbits(rtcm->buff,i,16)*P2_29; i+=16; + sqrtA =getbitu(rtcm->buff,i,32)*P2_19; i+=32; + eph.toes =getbitu(rtcm->buff,i,14)*60.0; i+=14; + eph.cic =getbits(rtcm->buff,i,16)*P2_29; i+=16; + eph.OMG0 =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; + eph.cis =getbits(rtcm->buff,i,16)*P2_29; i+=16; + eph.i0 =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; + eph.crc =getbits(rtcm->buff,i,16)*P2_5; i+=16; + eph.omg =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; + eph.OMGd =getbits(rtcm->buff,i,24)*P2_43*SC2RAD; i+=24; + eph.tgd[0]=getbits(rtcm->buff,i,10)*P2_32; i+=10; /* E5a/E1 */ + e5a_hs =getbitu(rtcm->buff,i, 2); i+= 2; /* OSHS */ + e5a_dvs =getbitu(rtcm->buff,i, 1); i+= 1; /* OSDVS */ + rsv =getbitu(rtcm->buff,i, 7); + } + else { + trace(2,"rtcm3 1045 length error: len=%d\n",rtcm->len); + return -1; + } + trace(4,"decode_type1045: prn=%d iode=%d toe=%.0f\n",prn,eph.iode,eph.toes); + + // if (rtcm->outtype) { + // msg=rtcm->msgtype+strlen(rtcm->msgtype); + // sprintf(msg," prn=%2d iode=%3d week=%d toe=%6.0f toc=%6.0f hs=%d dvs=%d", + // prn,eph.iode,week,eph.toes,toc,e5a_hs,e5a_dvs); + // } + if (!(sat=satno(sys,prn))) { + trace(2,"rtcm3 1045 satellite number error: prn=%d\n",prn); + return -1; + } + //if (strstr(rtcm->opt,"-GALINAV")) { + // return 0; + //} + eph.sat=sat; + eph.week=week+1024; /* gal-week = gst-week + 1024 */ + if (rtcm->time.time==0) rtcm->time=utc2gpst(timeget()); + tt=timediff(gpst2time(eph.week,eph.toes),rtcm->time); + if (tt<-302400.0) eph.week++; + else if (tt>=302400.0) eph.week--; + eph.toe=gpst2time(eph.week,eph.toes); + eph.toc=gpst2time(eph.week,toc); + eph.ttr=rtcm->time; + eph.A=sqrtA*sqrtA; + eph.svh=(e5a_hs<<4)+(e5a_dvs<<3); + eph.code=(1<<1)+(1<<8); /* data source = F/NAV+E5a */ + eph.iodc=eph.iode; + //if (!strstr(rtcm->opt,"-EPHALL")) { + // if (eph.iode==rtcm->nav.eph[sat-1+MAXSAT].iode) return 0; /* unchanged */ + //} + rtcm->nav.eph[sat-1+MAXSAT]=eph; + rtcm->ephsat=sat; + rtcm->ephset=1; /* F/NAV */ + return 2; +} +/* decode type 1046: Galileo I/NAV satellite ephemerides ---------------------*/ +static int decode_type1046(rtcm_t *rtcm) +{ + eph_t eph={0}; + double toc,sqrtA,tt; + //char *msg; + int i=24+12,prn,sat,week,e5b_hs,e5b_dvs,e1_hs,e1_dvs,sys=SYS_GAL; + + //if (strstr(rtcm->opt,"-GALFNAV")) return 0; + + if (i+492<=rtcm->len*8) { + prn =getbitu(rtcm->buff,i, 6); i+= 6; + week =getbitu(rtcm->buff,i,12); i+=12; + eph.iode =getbitu(rtcm->buff,i,10); i+=10; + eph.sva =getbitu(rtcm->buff,i, 8); i+= 8; + eph.idot =getbits(rtcm->buff,i,14)*P2_43*SC2RAD; i+=14; + toc =getbitu(rtcm->buff,i,14)*60.0; i+=14; + eph.f2 =getbits(rtcm->buff,i, 6)*P2_59; i+= 6; + eph.f1 =getbits(rtcm->buff,i,21)*P2_46; i+=21; + eph.f0 =getbits(rtcm->buff,i,31)*P2_34; i+=31; + eph.crs =getbits(rtcm->buff,i,16)*P2_5; i+=16; + eph.deln =getbits(rtcm->buff,i,16)*P2_43*SC2RAD; i+=16; + eph.M0 =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; + eph.cuc =getbits(rtcm->buff,i,16)*P2_29; i+=16; + eph.e =getbitu(rtcm->buff,i,32)*P2_33; i+=32; + eph.cus =getbits(rtcm->buff,i,16)*P2_29; i+=16; + sqrtA =getbitu(rtcm->buff,i,32)*P2_19; i+=32; + eph.toes =getbitu(rtcm->buff,i,14)*60.0; i+=14; + eph.cic =getbits(rtcm->buff,i,16)*P2_29; i+=16; + eph.OMG0 =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; + eph.cis =getbits(rtcm->buff,i,16)*P2_29; i+=16; + eph.i0 =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; + eph.crc =getbits(rtcm->buff,i,16)*P2_5; i+=16; + eph.omg =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; + eph.OMGd =getbits(rtcm->buff,i,24)*P2_43*SC2RAD; i+=24; + eph.tgd[0]=getbits(rtcm->buff,i,10)*P2_32; i+=10; /* E5a/E1 */ + eph.tgd[1]=getbits(rtcm->buff,i,10)*P2_32; i+=10; /* E5b/E1 */ + e5b_hs =getbitu(rtcm->buff,i, 2); i+= 2; /* E5b OSHS */ + e5b_dvs =getbitu(rtcm->buff,i, 1); i+= 1; /* E5b OSDVS */ + e1_hs =getbitu(rtcm->buff,i, 2); i+= 2; /* E1 OSHS */ + e1_dvs =getbitu(rtcm->buff,i, 1); i+= 1; /* E1 OSDVS */ + } + else { + trace(2,"rtcm3 1046 length error: len=%d\n",rtcm->len); + return -1; + } + trace(4,"decode_type1046: prn=%d iode=%d toe=%.0f\n",prn,eph.iode,eph.toes); + + // if (rtcm->outtype) { + // msg=rtcm->msgtype+strlen(rtcm->msgtype); + // sprintf(msg," prn=%2d iode=%3d week=%d toe=%6.0f toc=%6.0f hs=%d %d dvs=%d %d", + // prn,eph.iode,week,eph.toes,toc,e5b_hs,e1_hs,e5b_dvs,e1_dvs); + // } + if (!(sat=satno(sys,prn))) { + trace(2,"rtcm3 1046 satellite number error: prn=%d\n",prn); + return -1; + } + //if (strstr(rtcm->opt,"-GALFNAV")) { + // return 0; + //} + eph.sat=sat; + eph.week=week+1024; /* gal-week = gst-week + 1024 */ + if (rtcm->time.time==0) rtcm->time=utc2gpst(timeget()); + tt=timediff(gpst2time(eph.week,eph.toes),rtcm->time); + if (tt<-302400.0) eph.week++; + else if (tt>=302400.0) eph.week--; + eph.toe=gpst2time(eph.week,eph.toes); + eph.toc=gpst2time(eph.week,toc); + eph.ttr=rtcm->time; + eph.A=sqrtA*sqrtA; + eph.svh=(e5b_hs<<7)+(e5b_dvs<<6)+(e1_hs<<1)+(e1_dvs<<0); + eph.code=(1<<0)+(1<<2)+(1<<9); /* data source = I/NAV+E1+E5b */ + eph.iodc=eph.iode; + //if (!strstr(rtcm->opt,"-EPHALL")) { + // if (eph.iode==rtcm->nav.eph[sat-1].iode) return 0; /* unchanged */ + //} + rtcm->nav.eph[sat-1]=eph; + rtcm->ephsat=sat; + rtcm->ephset=0; /* I/NAV */ + return 2; +} +#endif +#ifdef RTCM3_ENBDS +/* decode type 1042/63: Beidou ephemerides -----------------------------------*/ +static int decode_type1042(rtcm_t *rtcm) +{ + eph_t eph={0}; + double toc,sqrtA,tt; + //char *msg; + int i=24+12,prn,sat,week,sys=SYS_CMP; + + if (i+499<=rtcm->len*8) { + prn =getbitu(rtcm->buff,i, 6); i+= 6; + week =getbitu(rtcm->buff,i,13); i+=13; + eph.sva =getbitu(rtcm->buff,i, 4); i+= 4; + eph.idot =getbits(rtcm->buff,i,14)*P2_43*SC2RAD; i+=14; + eph.iode =getbitu(rtcm->buff,i, 5); i+= 5; /* AODE */ + toc =getbitu(rtcm->buff,i,17)*8.0; i+=17; + eph.f2 =getbits(rtcm->buff,i,11)*P2_66; i+=11; + eph.f1 =getbits(rtcm->buff,i,22)*P2_50; i+=22; + eph.f0 =getbits(rtcm->buff,i,24)*P2_33; i+=24; + eph.iodc =getbitu(rtcm->buff,i, 5); i+= 5; /* AODC */ + eph.crs =getbits(rtcm->buff,i,18)*P2_6; i+=18; + eph.deln =getbits(rtcm->buff,i,16)*P2_43*SC2RAD; i+=16; + eph.M0 =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; + eph.cuc =getbits(rtcm->buff,i,18)*P2_31; i+=18; + eph.e =getbitu(rtcm->buff,i,32)*P2_33; i+=32; + eph.cus =getbits(rtcm->buff,i,18)*P2_31; i+=18; + sqrtA =getbitu(rtcm->buff,i,32)*P2_19; i+=32; + eph.toes =getbitu(rtcm->buff,i,17)*8.0; i+=17; + eph.cic =getbits(rtcm->buff,i,18)*P2_31; i+=18; + eph.OMG0 =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; + eph.cis =getbits(rtcm->buff,i,18)*P2_31; i+=18; + eph.i0 =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; + eph.crc =getbits(rtcm->buff,i,18)*P2_6; i+=18; + eph.omg =getbits(rtcm->buff,i,32)*P2_31*SC2RAD; i+=32; + eph.OMGd =getbits(rtcm->buff,i,24)*P2_43*SC2RAD; i+=24; + eph.tgd[0]=getbits(rtcm->buff,i,10)*1E-10; i+=10; + eph.tgd[1]=getbits(rtcm->buff,i,10)*1E-10; i+=10; + eph.svh =getbitu(rtcm->buff,i, 1); i+= 1; + } + else { + trace(2,"rtcm3 1042 length error: len=%d\n",rtcm->len); + return -1; + } + trace(4,"decode_type1042: prn=%d iode=%d toe=%.0f\n",prn,eph.iode,eph.toes); + + // if (rtcm->outtype) { + // msg=rtcm->msgtype+strlen(rtcm->msgtype); + // sprintf(msg," prn=%2d iode=%3d iodc=%3d week=%d toe=%6.0f toc=%6.0f svh=%02X", + // prn,eph.iode,eph.iodc,week,eph.toes,toc,eph.svh); + // } + if (!(sat=satno(sys,prn))) { + trace(2,"rtcm3 1042 satellite number error: prn=%d\n",prn); + return -1; + } + eph.sat=sat; + eph.week=adjbdtweek(week); + if (rtcm->time.time==0) rtcm->time=utc2gpst(timeget()); + tt=timediff(bdt2gpst(bdt2time(eph.week,eph.toes)),rtcm->time); + if (tt<-302400.0) eph.week++; + else if (tt>=302400.0) eph.week--; + eph.toe=bdt2gpst(bdt2time(eph.week,eph.toes)); /* bdt -> gpst */ + eph.toc=bdt2gpst(bdt2time(eph.week,toc)); /* bdt -> gpst */ + eph.ttr=rtcm->time; + eph.A=sqrtA*sqrtA; + //if (!strstr(rtcm->opt,"-EPHALL")) { + // if (timediff(eph.toe,rtcm->nav.eph[sat-1].toe)==0.0&& + // eph.iode==rtcm->nav.eph[sat-1].iode&& + // eph.iodc==rtcm->nav.eph[sat-1].iodc) return 0; /* unchanged */ + //} + rtcm->nav.eph[sat-1]=eph; + rtcm->ephset=0; + rtcm->ephsat=sat; + return 2; +} +#endif +#ifdef RTCM_ENA_SSR +/* decode SSR message epoch time ---------------------------------------------*/ +static int decode_ssr_epoch(rtcm_t *rtcm, int sys, int subtype) +{ + double tod,tow; + int i=24+12; + + if (subtype==0) { /* RTCM SSR */ + + if (sys==SYS_GLO) { + tod=getbitu(rtcm->buff,i,17); i+=17; + adjday_glot(rtcm,tod); + } + else { + tow=getbitu(rtcm->buff,i,20); i+=20; + adjweek(rtcm,tow); + } + } + else { /* IGS SSR */ + i+=3+8; + tow=getbitu(rtcm->buff,i,20); i+=20; + adjweek(rtcm,tow); + } + return i; +} +/* decode SSR 1,4 message header ---------------------------------------------*/ +static int decode_ssr1_head(rtcm_t *rtcm, int sys, int subtype, int *sync, + int *iod, double *udint, int *refd, int *hsize) +{ + char *msg,tstr[64]; + int i=24+12,nsat,udi,provid=0,solid=0,ns; + + if (subtype==0) { /* RTCM SSR */ + ns=(sys==SYS_QZS)?4:6; + if (i+((sys==SYS_GLO)?53:50+ns)>rtcm->len*8) return -1; + } + else { /* IGS SSR */ + ns=6; + if (i+3+8+50+ns>rtcm->len*8) return -1; + } + i=decode_ssr_epoch(rtcm,sys,subtype); + udi =getbitu(rtcm->buff,i, 4); i+= 4; + *sync =getbitu(rtcm->buff,i, 1); i+= 1; + if (subtype==0) { /* RTCM SSR */ + *refd =getbitu(rtcm->buff,i, 1); i+= 1; /* satellite ref datum */ + } + *iod =getbitu(rtcm->buff,i, 4); i+= 4; /* IOD SSR */ + provid=getbitu(rtcm->buff,i,16); i+=16; /* provider ID */ + solid =getbitu(rtcm->buff,i, 4); i+= 4; /* solution ID */ + if (subtype>0) { /* IGS SSR */ + *refd=getbitu(rtcm->buff,i,1); i+=1; /* global/regional CRS indicator */ + } + nsat =getbitu(rtcm->buff,i,ns); i+=ns; + *udint=ssrudint[udi]; + + time2str(rtcm->time,tstr,2); + trace(4,"decode_ssr1_head: time=%s sys=%d subtype=%d nsat=%d sync=%d iod=%d" + " provid=%d solid=%d\n",tstr,sys,subtype,nsat,*sync,*iod,provid,solid); + + if (rtcm->outtype) { + msg=rtcm->msgtype+strlen(rtcm->msgtype); + sprintf(msg," %s nsat=%2d iod=%2d udi=%2d sync=%d",tstr,nsat,*iod,udi, + *sync); + } + *hsize=i; + return nsat; +} +/* decode SSR 2,3,5,6 message header -----------------------------------------*/ +static int decode_ssr2_head(rtcm_t *rtcm, int sys, int subtype, int *sync, + int *iod, double *udint, int *hsize) +{ + char *msg,tstr[64]; + int i=24+12,nsat,udi,provid=0,solid=0,ns; + + if (subtype==0) { /* RTCM SSR */ + ns=(sys==SYS_QZS)?4:6; + if (i+((sys==SYS_GLO)?52:49+ns)>rtcm->len*8) return -1; + } + else { + ns=6; + if (i+3+8+49+ns>rtcm->len*8) return -1; + } + i=decode_ssr_epoch(rtcm,sys,subtype); + udi =getbitu(rtcm->buff,i, 4); i+= 4; + *sync =getbitu(rtcm->buff,i, 1); i+= 1; + *iod =getbitu(rtcm->buff,i, 4); i+= 4; + provid=getbitu(rtcm->buff,i,16); i+=16; /* provider ID */ + solid =getbitu(rtcm->buff,i, 4); i+= 4; /* solution ID */ + nsat =getbitu(rtcm->buff,i,ns); i+=ns; + *udint=ssrudint[udi]; + + time2str(rtcm->time,tstr,2); + trace(4,"decode_ssr2_head: time=%s sys=%d subtype=%d nsat=%d sync=%d iod=%d" + " provid=%d solid=%d\n",tstr,sys,subtype,nsat,*sync,*iod,provid,solid); + + if (rtcm->outtype) { + msg=rtcm->msgtype+strlen(rtcm->msgtype); + sprintf(msg," %s nsat=%2d iod=%2d udi=%2d sync=%d",tstr,nsat,*iod,udi, + *sync); + } + *hsize=i; + return nsat; +} +/* decode SSR 1: orbit corrections -------------------------------------------*/ +static int decode_ssr1(rtcm_t *rtcm, int sys, int subtype) +{ + double udint,deph[3],ddeph[3]; + int i,j,k,type,sync,iod,nsat,prn,sat,iode,iodcrc=0,refd=0,np,ni,nj,offp; + + type=getbitu(rtcm->buff,24,12); + + if ((nsat=decode_ssr1_head(rtcm,sys,subtype,&sync,&iod,&udint,&refd,&i))<0) { + trace(2,"rtcm3 %d length error: len=%d\n",type,rtcm->len); + return -1; + } + switch (sys) { + case SYS_GPS: np=6; ni= 8; nj= 0; offp= 0; break; + case SYS_GLO: np=5; ni= 8; nj= 0; offp= 0; break; + case SYS_GAL: np=6; ni=10; nj= 0; offp= 0; break; + case SYS_QZS: np=4; ni= 8; nj= 0; offp=192; break; + case SYS_CMP: np=6; ni=10; nj=24; offp= 1; break; + case SYS_SBS: np=6; ni= 9; nj=24; offp=120; break; + default: return sync?0:10; + } + if (subtype>0) { /* IGS SSR */ + np=6; ni=8; nj=0; + if (sys==SYS_CMP) offp=0; + else if (sys==SYS_SBS) offp=119; + } + for (j=0;jlen*8;j++) { + prn =getbitu(rtcm->buff,i,np)+offp; i+=np; + iode =getbitu(rtcm->buff,i,ni); i+=ni; + iodcrc =getbitu(rtcm->buff,i,nj); i+=nj; + deph [0]=getbits(rtcm->buff,i,22)*1E-4; i+=22; + deph [1]=getbits(rtcm->buff,i,20)*4E-4; i+=20; + deph [2]=getbits(rtcm->buff,i,20)*4E-4; i+=20; + ddeph[0]=getbits(rtcm->buff,i,21)*1E-6; i+=21; + ddeph[1]=getbits(rtcm->buff,i,19)*4E-6; i+=19; + ddeph[2]=getbits(rtcm->buff,i,19)*4E-6; i+=19; + + if (!(sat=satno(sys,prn))) { + trace(2,"rtcm3 %d satellite number error: prn=%d\n",type,prn); + continue; + } + //rtcm->ssr[sat-1].t0 [0]=rtcm->time; + //rtcm->ssr[sat-1].udi[0]=udint; + //rtcm->ssr[sat-1].iod[0]=iod; + //rtcm->ssr[sat-1].iode=iode; /* SBAS/BDS: toe/t0 modulo */ + //rtcm->ssr[sat-1].iodcrc=iodcrc; /* SBAS/BDS: IOD CRC */ + //rtcm->ssr[sat-1].refd=refd; + // + //for (k=0;k<3;k++) { + // rtcm->ssr[sat-1].deph [k]=deph [k]; + // rtcm->ssr[sat-1].ddeph[k]=ddeph[k]; + //} + //rtcm->ssr[sat-1].update=1; + } + return sync?0:10; +} +/* decode SSR 2: clock corrections -------------------------------------------*/ +static int decode_ssr2(rtcm_t *rtcm, int sys, int subtype) +{ + double udint,dclk[3]; + int i,j,k,type,sync,iod,nsat,prn,sat,np,offp; + + type=getbitu(rtcm->buff,24,12); + + if ((nsat=decode_ssr2_head(rtcm,sys,subtype,&sync,&iod,&udint,&i))<0) { + trace(2,"rtcm3 %d length error: len=%d\n",type,rtcm->len); + return -1; + } + switch (sys) { + case SYS_GPS: np=6; offp= 0; break; + case SYS_GLO: np=5; offp= 0; break; + case SYS_GAL: np=6; offp= 0; break; + case SYS_QZS: np=4; offp=192; break; + case SYS_CMP: np=6; offp= 1; break; + case SYS_SBS: np=6; offp=120; break; + default: return sync?0:10; + } + if (subtype>0) { /* IGS SSR */ + np=6; + if (sys==SYS_CMP) offp=0; + else if (sys==SYS_SBS) offp=119; + } + for (j=0;jlen*8;j++) { + prn =getbitu(rtcm->buff,i,np)+offp; i+=np; + dclk[0]=getbits(rtcm->buff,i,22)*1E-4; i+=22; + dclk[1]=getbits(rtcm->buff,i,21)*1E-6; i+=21; + dclk[2]=getbits(rtcm->buff,i,27)*2E-8; i+=27; + + if (!(sat=satno(sys,prn))) { + trace(2,"rtcm3 %d satellite number error: prn=%d\n",type,prn); + continue; + } + rtcm->ssr[sat-1].t0 [1]=rtcm->time; + rtcm->ssr[sat-1].udi[1]=udint; + rtcm->ssr[sat-1].iod[1]=iod; + + for (k=0;k<3;k++) { + rtcm->ssr[sat-1].dclk[k]=dclk[k]; + } + rtcm->ssr[sat-1].update=1; + } + return sync?0:10; +} +/* decode SSR 3: satellite code biases ---------------------------------------*/ +static int decode_ssr3(rtcm_t *rtcm, int sys, int subtype) +{ + const uint8_t *sigs; + double udint,bias,cbias[MAXCODE]; + int i,j,k,type,mode,sync,iod,nsat,prn,sat,nbias,np,offp; + + type=getbitu(rtcm->buff,24,12); + + if ((nsat=decode_ssr2_head(rtcm,sys,subtype,&sync,&iod,&udint,&i))<0) { + trace(2,"rtcm3 %d length error: len=%d\n",type,rtcm->len); + return -1; + } + switch (sys) { + case SYS_GPS: np=6; offp= 0; sigs=ssr_sig_gps; break; + case SYS_GLO: np=5; offp= 0; sigs=ssr_sig_glo; break; + case SYS_GAL: np=6; offp= 0; sigs=ssr_sig_gal; break; + case SYS_QZS: np=4; offp=192; sigs=ssr_sig_qzs; break; + case SYS_CMP: np=6; offp= 1; sigs=ssr_sig_cmp; break; + case SYS_SBS: np=6; offp=120; sigs=ssr_sig_sbs; break; + default: return sync?0:10; + } + if (subtype>0) { /* IGS SSR */ + np=6; + if (sys==SYS_CMP) offp=0; + else if (sys==SYS_SBS) offp=119; + } + for (j=0;jlen*8;j++) { + prn =getbitu(rtcm->buff,i,np)+offp; i+=np; + nbias=getbitu(rtcm->buff,i, 5); i+= 5; + + for (k=0;klen*8;k++) { + mode=getbitu(rtcm->buff,i, 5); i+= 5; + bias=getbits(rtcm->buff,i,14)*0.01; i+=14; + if (sigs[mode]) { + cbias[sigs[mode]-1]=(float)bias; + } + else { + trace(2,"rtcm3 %d not supported mode: mode=%d\n",type,mode); + } + } + if (!(sat=satno(sys,prn))) { + trace(2,"rtcm3 %d satellite number error: prn=%d\n",type,prn); + continue; + } + rtcm->ssr[sat-1].t0 [4]=rtcm->time; + rtcm->ssr[sat-1].udi[4]=udint; + rtcm->ssr[sat-1].iod[4]=iod; + + for (k=0;kssr[sat-1].cbias[k]=(float)cbias[k]; + } + rtcm->ssr[sat-1].update=1; + } + return sync?0:10; +} +/* decode SSR 4: combined orbit and clock corrections ------------------------*/ +static int decode_ssr4(rtcm_t *rtcm, int sys, int subtype) +{ + double udint,deph[3],ddeph[3],dclk[3]; + int i,j,k,type,nsat,sync,iod,prn,sat,iode,iodcrc=0,refd=0,np,ni,nj,offp; + + type=getbitu(rtcm->buff,24,12); + + if ((nsat=decode_ssr1_head(rtcm,sys,subtype,&sync,&iod,&udint,&refd,&i))<0) { + trace(2,"rtcm3 %d length error: len=%d\n",type,rtcm->len); + return -1; + } + switch (sys) { + case SYS_GPS: np=6; ni= 8; nj= 0; offp= 0; break; + case SYS_GLO: np=5; ni= 8; nj= 0; offp= 0; break; + case SYS_GAL: np=6; ni=10; nj= 0; offp= 0; break; + case SYS_QZS: np=4; ni= 8; nj= 0; offp=192; break; + case SYS_CMP: np=6; ni=10; nj=24; offp= 1; break; + case SYS_SBS: np=6; ni= 9; nj=24; offp=120; break; + default: return sync?0:10; + } + if (subtype>0) { /* IGS SSR */ + np=6; ni=8; nj=0; + if (sys==SYS_CMP) offp=0; + else if (sys==SYS_SBS) offp=119; + } + for (j=0;jlen*8;j++) { + prn =getbitu(rtcm->buff,i,np)+offp; i+=np; + iode =getbitu(rtcm->buff,i,ni); i+=ni; + iodcrc =getbitu(rtcm->buff,i,nj); i+=nj; + deph [0]=getbits(rtcm->buff,i,22)*1E-4; i+=22; + deph [1]=getbits(rtcm->buff,i,20)*4E-4; i+=20; + deph [2]=getbits(rtcm->buff,i,20)*4E-4; i+=20; + ddeph[0]=getbits(rtcm->buff,i,21)*1E-6; i+=21; + ddeph[1]=getbits(rtcm->buff,i,19)*4E-6; i+=19; + ddeph[2]=getbits(rtcm->buff,i,19)*4E-6; i+=19; + + dclk [0]=getbits(rtcm->buff,i,22)*1E-4; i+=22; + dclk [1]=getbits(rtcm->buff,i,21)*1E-6; i+=21; + dclk [2]=getbits(rtcm->buff,i,27)*2E-8; i+=27; + + if (!(sat=satno(sys,prn))) { + trace(2,"rtcm3 %d satellite number error: prn=%d\n",type,prn); + continue; + } + rtcm->ssr[sat-1].t0 [0]=rtcm->ssr[sat-1].t0 [1]=rtcm->time; + rtcm->ssr[sat-1].udi[0]=rtcm->ssr[sat-1].udi[1]=udint; + rtcm->ssr[sat-1].iod[0]=rtcm->ssr[sat-1].iod[1]=iod; + rtcm->ssr[sat-1].iode=iode; + rtcm->ssr[sat-1].iodcrc=iodcrc; + rtcm->ssr[sat-1].refd=refd; + + for (k=0;k<3;k++) { + rtcm->ssr[sat-1].deph [k]=deph [k]; + rtcm->ssr[sat-1].ddeph[k]=ddeph[k]; + rtcm->ssr[sat-1].dclk [k]=dclk [k]; + } + rtcm->ssr[sat-1].update=1; + } + return sync?0:10; +} +/* decode SSR 5: URA ---------------------------------------------------------*/ +static int decode_ssr5(rtcm_t *rtcm, int sys, int subtype) +{ + double udint; + int i,j,type,nsat,sync,iod,prn,sat,ura,np,offp; + + type=getbitu(rtcm->buff,24,12); + + if ((nsat=decode_ssr2_head(rtcm,sys,subtype,&sync,&iod,&udint,&i))<0) { + trace(2,"rtcm3 %d length error: len=%d\n",type,rtcm->len); + return -1; + } + switch (sys) { + case SYS_GPS: np=6; offp= 0; break; + case SYS_GLO: np=5; offp= 0; break; + case SYS_GAL: np=6; offp= 0; break; + case SYS_QZS: np=4; offp=192; break; + case SYS_CMP: np=6; offp= 1; break; + case SYS_SBS: np=6; offp=120; break; + default: return sync?0:10; + } + if (subtype>0) { /* IGS SSR */ + np=6; + if (sys==SYS_CMP) offp=0; + else if (sys==SYS_SBS) offp=119; + } + for (j=0;jlen*8;j++) { + prn=getbitu(rtcm->buff,i,np)+offp; i+=np; + ura=getbitu(rtcm->buff,i, 6); i+= 6; + + if (!(sat=satno(sys,prn))) { + trace(2,"rtcm3 %d satellite number error: prn=%d\n",type,prn); + continue; + } + rtcm->ssr[sat-1].t0 [3]=rtcm->time; + rtcm->ssr[sat-1].udi[3]=udint; + rtcm->ssr[sat-1].iod[3]=iod; + rtcm->ssr[sat-1].ura=ura; + rtcm->ssr[sat-1].update=1; + } + return sync?0:10; +} +/* decode SSR 6: high rate clock correction ----------------------------------*/ +static int decode_ssr6(rtcm_t *rtcm, int sys, int subtype) +{ + double udint,hrclk; + int i,j,type,nsat,sync,iod,prn,sat,np,offp; + + type=getbitu(rtcm->buff,24,12); + + if ((nsat=decode_ssr2_head(rtcm,sys,subtype,&sync,&iod,&udint,&i))<0) { + trace(2,"rtcm3 %d length error: len=%d\n",type,rtcm->len); + return -1; + } + switch (sys) { + case SYS_GPS: np=6; offp= 0; break; + case SYS_GLO: np=5; offp= 0; break; + case SYS_GAL: np=6; offp= 0; break; + case SYS_QZS: np=4; offp=192; break; + case SYS_CMP: np=6; offp= 1; break; + case SYS_SBS: np=6; offp=120; break; + default: return sync?0:10; + } + if (subtype>0) { /* IGS SSR */ + np=6; + if (sys==SYS_CMP) offp=0; + else if (sys==SYS_SBS) offp=119; + } + for (j=0;jlen*8;j++) { + prn =getbitu(rtcm->buff,i,np)+offp; i+=np; + hrclk=getbits(rtcm->buff,i,22)*1E-4; i+=22; + + if (!(sat=satno(sys,prn))) { + trace(2,"rtcm3 %d satellite number error: prn=%d\n",type,prn); + continue; + } + rtcm->ssr[sat-1].t0 [2]=rtcm->time; + rtcm->ssr[sat-1].udi[2]=udint; + rtcm->ssr[sat-1].iod[2]=iod; + rtcm->ssr[sat-1].hrclk=hrclk; + rtcm->ssr[sat-1].update=1; + } + return sync?0:10; +} +/* decode SSR 7 message header -----------------------------------------------*/ +static int decode_ssr7_head(rtcm_t *rtcm, int sys, int subtype, int *sync, + int *iod, double *udint, int *dispe, int *mw, + int *hsize) +{ + char *msg,tstr[64]; + int i=24+12,nsat,udi,provid=0,solid=0,ns; + + if (subtype==0) { /* RTCM SSR */ + ns=(sys==SYS_QZS)?4:6; + if (i+((sys==SYS_GLO)?54:51+ns)>rtcm->len*8) return -1; + } + else { /* IGS SSR */ + ns=6; + if (i+3+8+51+ns>rtcm->len*8) return -1; + } + i=decode_ssr_epoch(rtcm,sys,subtype); + udi =getbitu(rtcm->buff,i, 4); i+= 4; + *sync =getbitu(rtcm->buff,i, 1); i+= 1; + *iod =getbitu(rtcm->buff,i, 4); i+= 4; + provid=getbitu(rtcm->buff,i,16); i+=16; /* provider ID */ + solid =getbitu(rtcm->buff,i, 4); i+= 4; /* solution ID */ + *dispe=getbitu(rtcm->buff,i, 1); i+= 1; /* dispersive bias consistency ind */ + *mw =getbitu(rtcm->buff,i, 1); i+= 1; /* MW consistency indicator */ + nsat =getbitu(rtcm->buff,i,ns); i+=ns; + *udint=ssrudint[udi]; + + time2str(rtcm->time,tstr,2); + trace(4,"decode_ssr7_head: time=%s sys=%d subtype=%d nsat=%d sync=%d iod=%d" + " provid=%d solid=%d\n",tstr,sys,subtype,nsat,*sync,*iod,provid,solid); + + if (rtcm->outtype) { + msg=rtcm->msgtype+strlen(rtcm->msgtype); + sprintf(msg," %s nsat=%2d iod=%2d udi=%2d sync=%d",tstr,nsat,*iod,udi, + *sync); + } + *hsize=i; + return nsat; +} +/* decode SSR 7: phase bias --------------------------------------------------*/ +static int decode_ssr7(rtcm_t *rtcm, int sys, int subtype) +{ + const uint8_t *sigs; + double udint,bias,std=0.0,pbias[MAXCODE],stdpb[MAXCODE]; + int i,j,k,type,mode,sync,iod,nsat,prn,sat,nbias,np,mw,offp,sii,swl; + int dispe,sdc,yaw_ang,yaw_rate; + + type=getbitu(rtcm->buff,24,12); + + if ((nsat=decode_ssr7_head(rtcm,sys,subtype,&sync,&iod,&udint,&dispe,&mw, + &i))<0) { + trace(2,"rtcm3 %d length error: len=%d\n",type,rtcm->len); + return -1; + } + switch (sys) { + case SYS_GPS: np=6; offp= 0; sigs=ssr_sig_gps; break; + case SYS_GLO: np=5; offp= 0; sigs=ssr_sig_glo; break; + case SYS_GAL: np=6; offp= 0; sigs=ssr_sig_gal; break; + case SYS_QZS: np=4; offp=192; sigs=ssr_sig_qzs; break; + case SYS_CMP: np=6; offp= 1; sigs=ssr_sig_cmp; break; + default: return sync?0:10; + } + if (subtype>0) { /* IGS SSR */ + np=6; + if (sys==SYS_CMP) offp=0; + else if (sys==SYS_SBS) offp=119; + } + for (j=0;jlen*8;j++) { + prn =getbitu(rtcm->buff,i,np)+offp; i+=np; + nbias =getbitu(rtcm->buff,i, 5); i+= 5; + yaw_ang =getbitu(rtcm->buff,i, 9); i+= 9; + yaw_rate=getbits(rtcm->buff,i, 8); i+= 8; + + for (k=0;klen*8;k++) { + mode=getbitu(rtcm->buff,i, 5); i+= 5; + sii =getbitu(rtcm->buff,i, 1); i+= 1; /* integer-indicator */ + swl =getbitu(rtcm->buff,i, 2); i+= 2; /* WL integer-indicator */ + sdc =getbitu(rtcm->buff,i, 4); i+= 4; /* discontinuity counter */ + bias=getbits(rtcm->buff,i,20); i+=20; /* phase bias (m) */ + if (subtype==0) { + std =getbitu(rtcm->buff,i,17); i+=17; /* phase bias std-dev (m) */ + } + if (sigs[mode]) { + pbias[sigs[mode]-1]=bias*0.0001; /* (m) */ + stdpb[sigs[mode]-1]=std *0.0001; /* (m) */ + } + else { + trace(2,"rtcm3 %d not supported mode: mode=%d\n",type,mode); + } + } + if (!(sat=satno(sys,prn))) { + trace(2,"rtcm3 %d satellite number error: prn=%d\n",type,prn); + continue; + } + rtcm->ssr[sat-1].t0 [5]=rtcm->time; + rtcm->ssr[sat-1].udi[5]=udint; + rtcm->ssr[sat-1].iod[5]=iod; + rtcm->ssr[sat-1].yaw_ang =yaw_ang / 256.0*180.0; /* (deg) */ + rtcm->ssr[sat-1].yaw_rate=yaw_rate/8192.0*180.0; /* (deg/s) */ + + for (k=0;kssr[sat-1].pbias[k]=pbias[k]; + rtcm->ssr[sat-1].stdpb[k]=(float)stdpb[k]; + } + } + return 20; +} +/* decode type 4076: proprietary message IGS ---------------------------------*/ +static int decode_type4076(rtcm_t *rtcm) +{ + int i=24+12,ver,subtype; + + if (i+3+8>=rtcm->len*8) { + trace(2,"rtcm3 4076: length error len=%d\n",rtcm->len); + return -1; + } + ver =getbitu(rtcm->buff,i,3); i+=3; + subtype=getbitu(rtcm->buff,i,8); i+=8; + + if (rtcm->outtype) { + sprintf(rtcm->msgtype+strlen(rtcm->msgtype)," ver=%d subtype=%3d",ver, + subtype); + } + switch (subtype) { + case 21: return decode_ssr1(rtcm,SYS_GPS,subtype); + case 22: return decode_ssr2(rtcm,SYS_GPS,subtype); + case 23: return decode_ssr4(rtcm,SYS_GPS,subtype); + case 24: return decode_ssr6(rtcm,SYS_GPS,subtype); + case 25: return decode_ssr3(rtcm,SYS_GPS,subtype); + case 26: return decode_ssr7(rtcm,SYS_GPS,subtype); + case 27: return decode_ssr5(rtcm,SYS_GPS,subtype); + case 41: return decode_ssr1(rtcm,SYS_GLO,subtype); + case 42: return decode_ssr2(rtcm,SYS_GLO,subtype); + case 43: return decode_ssr4(rtcm,SYS_GLO,subtype); + case 44: return decode_ssr6(rtcm,SYS_GLO,subtype); + case 45: return decode_ssr3(rtcm,SYS_GLO,subtype); + case 46: return decode_ssr7(rtcm,SYS_GLO,subtype); + case 47: return decode_ssr5(rtcm,SYS_GLO,subtype); + case 61: return decode_ssr1(rtcm,SYS_GAL,subtype); + case 62: return decode_ssr2(rtcm,SYS_GAL,subtype); + case 63: return decode_ssr4(rtcm,SYS_GAL,subtype); + case 64: return decode_ssr6(rtcm,SYS_GAL,subtype); + case 65: return decode_ssr3(rtcm,SYS_GAL,subtype); + case 66: return decode_ssr7(rtcm,SYS_GAL,subtype); + case 67: return decode_ssr5(rtcm,SYS_GAL,subtype); + case 81: return decode_ssr1(rtcm,SYS_QZS,subtype); + case 82: return decode_ssr2(rtcm,SYS_QZS,subtype); + case 83: return decode_ssr4(rtcm,SYS_QZS,subtype); + case 84: return decode_ssr6(rtcm,SYS_QZS,subtype); + case 85: return decode_ssr3(rtcm,SYS_QZS,subtype); + case 86: return decode_ssr7(rtcm,SYS_QZS,subtype); + case 87: return decode_ssr5(rtcm,SYS_QZS,subtype); + case 101: return decode_ssr1(rtcm,SYS_CMP,subtype); + case 102: return decode_ssr2(rtcm,SYS_CMP,subtype); + case 103: return decode_ssr4(rtcm,SYS_CMP,subtype); + case 104: return decode_ssr6(rtcm,SYS_CMP,subtype); + case 105: return decode_ssr3(rtcm,SYS_CMP,subtype); + case 106: return decode_ssr7(rtcm,SYS_CMP,subtype); + case 107: return decode_ssr5(rtcm,SYS_CMP,subtype); + case 121: return decode_ssr1(rtcm,SYS_SBS,subtype); + case 122: return decode_ssr2(rtcm,SYS_SBS,subtype); + case 123: return decode_ssr4(rtcm,SYS_SBS,subtype); + case 124: return decode_ssr6(rtcm,SYS_SBS,subtype); + case 125: return decode_ssr3(rtcm,SYS_SBS,subtype); + case 126: return decode_ssr7(rtcm,SYS_SBS,subtype); + case 127: return decode_ssr5(rtcm,SYS_SBS,subtype); + } + trace(2,"rtcm3 4076: unsupported message subtype=%d\n",subtype); + return 0; +} +#endif +/* get signal index ----------------------------------------------------------*/ +static void sigindex(int sys, const uint8_t *code, int n, const char *opt, + int *idx) +{ + int i,nex,pri,pri_h[8]={0},index[8]={0},ex[32]={0}; + + /* test code priority */ + for (i=0;i=NFREQ) { /* save as extended signal if idx >= NFREQ */ + ex[i]=1; + continue; + } + /* code priority */ + pri=getcodepri(sys,code[i],opt); + + /* select highest priority signal */ + if (pri>pri_h[idx[i]]) { + if (index[idx[i]]) ex[index[idx[i]]-1]=1; + pri_h[idx[i]]=pri; + index[idx[i]]=i+1; + } + else ex[i]=1; + } + /* signal index in obs data */ + for (i=nex=0;ibuff,24,12); + + switch (sys) { + case SYS_GPS: msm_type=q=rtcm->msmtype[0]; break; + case SYS_GLO: msm_type=q=rtcm->msmtype[1]; break; + case SYS_GAL: msm_type=q=rtcm->msmtype[2]; break; + case SYS_QZS: msm_type=q=rtcm->msmtype[3]; break; + case SYS_SBS: msm_type=q=rtcm->msmtype[4]; break; + case SYS_CMP: msm_type=q=rtcm->msmtype[5]; break; + case SYS_IRN: msm_type=q=rtcm->msmtype[6]; break; + } + /* id to signal */ + for (i=0;insig;i++) { + switch (sys) + { + case SYS_GPS: +#ifdef RTCM3_ENGPS + sig[i] = msm_sig_gps[h->sigs[i] - 1]; +#else + sig[i] = ""; +#endif + break; + case SYS_GLO: +#ifdef RTCM3_ENGLO + sig[i] = msm_sig_glo[h->sigs[i] - 1]; +#else + sig[i] = ""; +#endif + break; + case SYS_GAL: +#ifdef RTCM3_ENGAL + sig[i] = msm_sig_gal[h->sigs[i] - 1]; +#else + sig[i] = ""; +#endif + break; + case SYS_QZS: +#ifdef RTCM3_ENQZS + sig[i] = msm_sig_qzs[h->sigs[i] - 1]; +#else + sig[i] = ""; +#endif + break; + case SYS_SBS: +#ifdef RTCM3_ENSBS + sig[i] = msm_sig_sbs[h->sigs[i] - 1]; +#else + sig[i] = ""; +#endif + break; + case SYS_CMP: +#ifdef RTCM3_ENBDS + sig[i] = msm_sig_cmp[h->sigs[i] - 1]; +#else + sig[i] = ""; +#endif + break; + case SYS_IRN: +#ifdef RTCM3_ENIRN + sig[i] = msm_sig_irn[h->sigs[i] - 1]; +#else + sig[i] = ""; +#endif + break; + default: + sig[i] = ""; + break; + } + /* signal to rinex obs type */ + code[i]=obs2code(sig[i]); + idx[i]=code2idx(sys,code[i]); + + if (code[i]!=CODE_NONE) { + if (q) q+=sprintf(q,"L%s%s",sig[i],insig-1?",":""); + } + else { + if (q) q+=sprintf(q,"(%d)%s",h->sigs[i],insig-1?",":""); + + trace(2,"rtcm3 %d: unknown signal id=%2d\n",type,h->sigs[i]); + } + } + trace(4,"rtcm3 %d: signals=%s\n",type,msm_type); + + /* get signal index */ + //sigindex(sys,code,h->nsig,rtcm->opt,idx); + sigindex(sys, code, h->nsig, NULL, idx); + + for (i=j=0;insat;i++) { + + prn=h->sats[i]; + if (sys==SYS_QZS) prn+=MINPRNQZS-1; + else if (sys==SYS_SBS) prn+=MINPRNSBS-1; + + if ((sat=satno(sys,prn))) { + tt=timediff(rtcm->obs.data[0].time,rtcm->time); + if (rtcm->obsflag||fabs(tt)>1E-9) { + rtcm->obs.n=rtcm->obsflag=0; + } + index=obsindex(&rtcm->obs,rtcm->time,sat); + } + else { + trace(2,"rtcm3 %d satellite error: prn=%d\n",type,prn); + } + fcn=0; + if (sys==SYS_GLO) { + fcn=-8; /* no glonass fcn info */ + if (ex&&ex[i]<=13) { + fcn=ex[i]-7; + if (!rtcm->nav.glo_fcn[prn-1]) { + rtcm->nav.glo_fcn[prn-1]=fcn+8; /* fcn+8 */ + } + } + else if (rtcm->nav.geph[prn-1].sat==sat) { + fcn=rtcm->nav.geph[prn-1].frq; + } + else if (rtcm->nav.glo_fcn[prn-1]>0) { + fcn=rtcm->nav.glo_fcn[prn-1]-8; + } + } + for (k=0;knsig;k++) { + if (!h->cellmask[k+i*h->nsig]) continue; + + if (sat&&index>=0&&idx[k]>=0) { + freq=fcn<-7?0.0:code2freq(sys,code[k],fcn); + + /* pseudorange (m) */ + if (r[i]!=0.0&&pr[j]>-1E12) { + rtcm->obs.data[index].P[idx[k]]=r[i]+pr[j]; + } + /* carrier-phase (cycle) */ + if (r[i]!=0.0&&cp[j]>-1E12) { + rtcm->obs.data[index].L[idx[k]]=(r[i]+cp[j])*freq/CLIGHT; + } + /* doppler (hz) */ + if (rr&&rrf&&rrf[j]>-1E12) { + rtcm->obs.data[index].D[idx[k]]= + (float)(-(rr[i]+rrf[j])*freq/CLIGHT); + } + rtcm->obs.data[index].LLI[idx[k]]= + lossoflock(rtcm,sat,idx[k],lock[j])+(half[j]?2:0); + rtcm->obs.data[index].SNR [idx[k]]=(uint16_t)(cnr[j]/SNR_UNIT+0.5); + rtcm->obs.data[index].code[idx[k]]=code[k]; + } + j++; + } + } +} +/* decode type MSM message header --------------------------------------------*/ +static int decode_msm_head(rtcm_t *rtcm, int sys, int *sync, int *iod, + msm_h_t *h, int *hsize) +{ + msm_h_t h0={0}; + double tow,tod; + //char* msg; + char tstr[64]; + int i=24,j,dow,mask,staid,type,ncell=0; + + type=getbitu(rtcm->buff,i,12); i+=12; + + *h=h0; + if (i+157<=rtcm->len*8) { + staid =getbitu(rtcm->buff,i,12); i+=12; + + if (sys==SYS_GLO) { + dow =getbitu(rtcm->buff,i, 3); i+= 3; + tod =getbitu(rtcm->buff,i,27)*0.001; i+=27; + adjday_glot(rtcm,tod); + } + else if (sys==SYS_CMP) { + tow =getbitu(rtcm->buff,i,30)*0.001; i+=30; + tow+=14.0; /* BDT -> GPST */ + adjweek(rtcm,tow); + } + else { + tow =getbitu(rtcm->buff,i,30)*0.001; i+=30; + adjweek(rtcm,tow); + } + *sync =getbitu(rtcm->buff,i, 1); i+= 1; + *iod =getbitu(rtcm->buff,i, 3); i+= 3; + h->time_s =getbitu(rtcm->buff,i, 7); i+= 7; + h->clk_str=getbitu(rtcm->buff,i, 2); i+= 2; + h->clk_ext=getbitu(rtcm->buff,i, 2); i+= 2; + h->smooth =getbitu(rtcm->buff,i, 1); i+= 1; + h->tint_s =getbitu(rtcm->buff,i, 3); i+= 3; + for (j=1;j<=64;j++) { + mask=getbitu(rtcm->buff,i,1); i+=1; + if (mask) h->sats[h->nsat++]=j; + } + for (j=1;j<=32;j++) { + mask=getbitu(rtcm->buff,i,1); i+=1; + if (mask) h->sigs[h->nsig++]=j; + } + } + else { + trace(2,"rtcm3 %d length error: len=%d\n",type,rtcm->len); + return -1; + } + /* test station id */ + if (!test_staid(rtcm,staid)) return -1; + + if (h->nsat*h->nsig>64) { + trace(2,"rtcm3 %d number of sats and sigs error: nsat=%d nsig=%d\n", + type,h->nsat,h->nsig); + return -1; + } + if (i+h->nsat*h->nsig>rtcm->len*8) { + trace(2,"rtcm3 %d length error: len=%d nsat=%d nsig=%d\n",type, + rtcm->len,h->nsat,h->nsig); + return -1; + } + for (j=0;jnsat*h->nsig;j++) { + h->cellmask[j]=getbitu(rtcm->buff,i,1); i+=1; + if (h->cellmask[j]) ncell++; + } + *hsize=i; + + time2str(rtcm->time,tstr,2); + trace(4,"decode_head_msm: time=%s sys=%d staid=%d nsat=%d nsig=%d sync=%d iod=%d ncell=%d\n", + tstr,sys,staid,h->nsat,h->nsig,*sync,*iod,ncell); + + // if (rtcm->outtype) { + // msg=rtcm->msgtype+strlen(rtcm->msgtype); + // sprintf(msg," staid=%4d %s nsat=%2d nsig=%2d iod=%2d ncell=%2d sync=%d", + // staid,tstr,h->nsat,h->nsig,*iod,ncell,*sync); + // } + return ncell; +} +/* decode MSM 4: full pseudorange and phaserange plus CNR --------------------*/ +static int decode_msm4(rtcm_t *rtcm, int sys) +{ + msm_h_t h={0}; + double r[64],pr[64],cp[64],cnr[64]; + int i,j,type,sync,iod,ncell,rng,rng_m,prv,cpv,lock[64],half[64]; + + type=getbitu(rtcm->buff,24,12); + + /* decode msm header */ + if ((ncell=decode_msm_head(rtcm,sys,&sync,&iod,&h,&i))<0) return -1; + + if (i+h.nsat*18+ncell*48>rtcm->len*8) { + trace(2,"rtcm3 %d length error: nsat=%d ncell=%d len=%d\n",type,h.nsat, + ncell,rtcm->len); + return -1; + } + for (j=0;jbuff,i, 8); i+= 8; + if (rng!=255) r[j]=rng*RANGE_MS; + } + for (j=0;jbuff,i,10); i+=10; + if (r[j]!=0.0) r[j]+=rng_m*P2_10*RANGE_MS; + } + /* decode signal data */ + for (j=0;jbuff,i,15); i+=15; + if (prv!=-16384) pr[j]=prv*P2_24*RANGE_MS; + } + for (j=0;jbuff,i,22); i+=22; + if (cpv!=-2097152) cp[j]=cpv*P2_29*RANGE_MS; + } + for (j=0;jbuff,i,4); i+=4; + } + for (j=0;jbuff,i,1); i+=1; + } + for (j=0;jbuff,i,6)*1.0; i+=6; + } + /* save obs data in msm message */ + save_msm_obs(rtcm,sys,&h,r,pr,cp,NULL,NULL,cnr,lock,NULL,half); + + rtcm->obsflag=!sync; + return sync?0:1; +} +/* decode MSM 5: full pseudorange, phaserange, phaserangerate and CNR --------*/ +static int decode_msm5(rtcm_t *rtcm, int sys) +{ + msm_h_t h={0}; + double r[64],rr[64],pr[64],cp[64],rrf[64],cnr[64]; + int i,j,type,sync,iod,ncell,rng,rng_m,rate,prv,cpv,rrv,lock[64]; + int ex[64],half[64]; + + type=getbitu(rtcm->buff,24,12); + + /* decode msm header */ + if ((ncell=decode_msm_head(rtcm,sys,&sync,&iod,&h,&i))<0) return -1; + + if (i+h.nsat*36+ncell*63>rtcm->len*8) { + trace(2,"rtcm3 %d length error: nsat=%d ncell=%d len=%d\n",type,h.nsat, + ncell,rtcm->len); + return -1; + } + for (j=0;jbuff,i, 8); i+= 8; + if (rng!=255) r[j]=rng*RANGE_MS; + } + for (j=0;jbuff,i, 4); i+= 4; + } + for (j=0;jbuff,i,10); i+=10; + if (r[j]!=0.0) r[j]+=rng_m*P2_10*RANGE_MS; + } + for (j=0;jbuff,i,14); i+=14; + if (rate!=-8192) rr[j]=rate*1.0; + } + /* decode signal data */ + for (j=0;jbuff,i,15); i+=15; + if (prv!=-16384) pr[j]=prv*P2_24*RANGE_MS; + } + for (j=0;jbuff,i,22); i+=22; + if (cpv!=-2097152) cp[j]=cpv*P2_29*RANGE_MS; + } + for (j=0;jbuff,i,4); i+=4; + } + for (j=0;jbuff,i,1); i+=1; + } + for (j=0;jbuff,i,6)*1.0; i+=6; + } + for (j=0;jbuff,i,15); i+=15; + if (rrv!=-16384) rrf[j]=rrv*0.0001; + } + /* save obs data in msm message */ + save_msm_obs(rtcm,sys,&h,r,pr,cp,rr,rrf,cnr,lock,ex,half); + + rtcm->obsflag=!sync; + return sync?0:1; +} +/* decode MSM 6: full pseudorange and phaserange plus CNR (high-res) ---------*/ +static int decode_msm6(rtcm_t *rtcm, int sys) +{ + msm_h_t h={0}; + double r[64],pr[64],cp[64],cnr[64]; + int i,j,type,sync,iod,ncell,rng,rng_m,prv,cpv,lock[64],half[64]; + + type=getbitu(rtcm->buff,24,12); + + /* decode msm header */ + if ((ncell=decode_msm_head(rtcm,sys,&sync,&iod,&h,&i))<0) return -1; + + if (i+h.nsat*18+ncell*65>rtcm->len*8) { + trace(2,"rtcm3 %d length error: nsat=%d ncell=%d len=%d\n",type,h.nsat, + ncell,rtcm->len); + return -1; + } + for (j=0;jbuff,i, 8); i+= 8; + if (rng!=255) r[j]=rng*RANGE_MS; + } + for (j=0;jbuff,i,10); i+=10; + if (r[j]!=0.0) r[j]+=rng_m*P2_10*RANGE_MS; + } + /* decode signal data */ + for (j=0;jbuff,i,20); i+=20; + if (prv!=-524288) pr[j]=prv*P2_29*RANGE_MS; + } + for (j=0;jbuff,i,24); i+=24; + if (cpv!=-8388608) cp[j]=cpv*P2_31*RANGE_MS; + } + for (j=0;jbuff,i,10); i+=10; + } + for (j=0;jbuff,i,1); i+=1; + } + for (j=0;jbuff,i,10)*0.0625; i+=10; + } + /* save obs data in msm message */ + save_msm_obs(rtcm,sys,&h,r,pr,cp,NULL,NULL,cnr,lock,NULL,half); + + rtcm->obsflag=!sync; + return sync?0:1; +} +/* decode MSM 7: full pseudorange, phaserange, phaserangerate and CNR (h-res) */ +static int decode_msm7(rtcm_t *rtcm, int sys) +{ + msm_h_t h={0}; + double r[64],rr[64],pr[64],cp[64],rrf[64],cnr[64]; + int i,j,type,sync,iod,ncell,rng,rng_m,rate,prv,cpv,rrv,lock[64]; + int ex[64],half[64]; + + type=getbitu(rtcm->buff,24,12); + + /* decode msm header */ + if ((ncell=decode_msm_head(rtcm,sys,&sync,&iod,&h,&i))<0) return -1; + + if (i+h.nsat*36+ncell*80>rtcm->len*8) { + trace(2,"rtcm3 %d length error: nsat=%d ncell=%d len=%d\n",type,h.nsat, + ncell,rtcm->len); + return -1; + } + for (j=0;jbuff,i, 8); i+= 8; + if (rng!=255) r[j]=rng*RANGE_MS; + } + for (j=0;jbuff,i, 4); i+= 4; + } + for (j=0;jbuff,i,10); i+=10; + if (r[j]!=0.0) r[j]+=rng_m*P2_10*RANGE_MS; + } + for (j=0;jbuff,i,14); i+=14; + if (rate!=-8192) rr[j]=rate*1.0; + } + /* decode signal data */ + for (j=0;jbuff,i,20); i+=20; + if (prv!=-524288) pr[j]=prv*P2_29*RANGE_MS; + } + for (j=0;jbuff,i,24); i+=24; + if (cpv!=-8388608) cp[j]=cpv*P2_31*RANGE_MS; + } + for (j=0;jbuff,i,10); i+=10; + } + for (j=0;jbuff,i,1); i+=1; + } + for (j=0;jbuff,i,10)*0.0625; i+=10; + } + for (j=0;jbuff,i,15); i+=15; + if (rrv!=-16384) rrf[j]=rrv*0.0001; + } + /* save obs data in msm message */ + save_msm_obs(rtcm,sys,&h,r,pr,cp,rr,rrf,cnr,lock,ex,half); + + rtcm->obsflag=!sync; + return sync?0:1; +} +/* decode type 1230: GLONASS L1 and L2 code-phase biases ---------------------*/ +static int decode_type1230(rtcm_t *rtcm) +{ + int i=24+12,j,staid,align,mask,bias; + + if (i+20>=rtcm->len*8) { + trace(2,"rtcm3 1230: length error len=%d\n",rtcm->len); + return -1; + } + staid=getbitu(rtcm->buff,i,12); i+=12; + align=getbitu(rtcm->buff,i, 1); i+= 1+3; + mask =getbitu(rtcm->buff,i, 4); i+= 4; + + // if (rtcm->outtype) { + // sprintf(rtcm->msgtype+strlen(rtcm->msgtype), + // " staid=%4d align=%d mask=0x%X",staid,align,mask); + // } + /* test station ID */ + if (!test_staid(rtcm,staid)) return -1; + + rtcm->sta.glo_cp_align=align; + for (j=0;j<4;j++) { + rtcm->sta.glo_cp_bias[j]=0.0; + } + for (j=0;j<4&&i+16<=rtcm->len*8;j++) { + if (!(mask&(1<<(3-j)))) continue; + bias=getbits(rtcm->buff,i,16); i+=16; + if (bias!=-32768) { + rtcm->sta.glo_cp_bias[j]=bias*0.02; + } + } + return 5; +} +/* decode type 4073: proprietary message Mitsubishi Electric -----------------*/ +static int decode_type4073(rtcm_t *rtcm) +{ + int i=24+12,subtype; + + subtype=getbitu(rtcm->buff,i,4); i+=4; + + //if (rtcm->outtype) { + // sprintf(rtcm->msgtype+strlen(rtcm->msgtype)," subtype=%d",subtype); + //} + trace(2,"rtcm3 4073: unsupported message subtype=%d\n",subtype); + return 0; +} + +/* decode RTCM ver.3 message -------------------------------------------------*/ +extern int decode_rtcm3(rtcm_t *rtcm) +{ + //double tow; + int ret = 0, type = getbitu(rtcm->buff, 24, 12); + //int week; + + trace(4,"decode_rtcm3: len=%3d type=%d\n",rtcm->len,type); + + // if (rtcm->outtype) { + // sprintf(rtcm->msgtype,"RTCM %4d (%4d):",type,rtcm->len); + // } + /* real-time input option */ + //if (strstr(rtcm->opt,"-RT_INP")) { + // tow=time2gpst(utc2gpst(timeget()),&week); + // rtcm->time=gpst2time(week,floor(tow)); + //} + switch (type) + { + case 1002: ret=decode_type1002(rtcm); break; /* extended L1-only GPS RTK observables */ + case 1004: ret=decode_type1004(rtcm); break; /* extended L1&L2 GPS RTK observables */ + case 1005: ret=decode_type1005(rtcm); break; /* stationary RTK reference station ARP */ + case 1006: ret=decode_type1006(rtcm); break; /* stationary RTK reference station ARP with height */ + case 1007: ret=decode_type1007(rtcm); break; /* antenna descriptor */ + case 1008: ret=decode_type1008(rtcm); break; /* antenna descriptor & serial number */ + case 1013: break; /* ϵͳ */ + case 1029: ret=decode_type1029(rtcm); break; /* UNICODE text string */ + case 1033: ret=decode_type1033(rtcm); break; /* receiver and antenna descriptor */ + +#ifdef RTCM3_ENGPS + case 1019: ret=decode_type1019(rtcm); break; /* GPS ephemerides */ + case 1074: ret=decode_msm4(rtcm,SYS_GPS); break; + case 1075: ret=decode_msm5(rtcm,SYS_GPS); break; + case 1076: ret=decode_msm6(rtcm,SYS_GPS); break; + case 1077: ret=decode_msm7(rtcm,SYS_GPS); break; +#endif +#ifdef RTCM3_ENGLO + case 1010: ret = decode_type1010(rtcm); break; + case 1012: ret = decode_type1012(rtcm); break; + case 1020: ret=decode_type1020(rtcm); break; /* GLO ephemerides */ + case 1084: ret=decode_msm4(rtcm,SYS_GLO); break; + case 1085: ret=decode_msm5(rtcm,SYS_GLO); break; + case 1086: ret=decode_msm6(rtcm,SYS_GLO); break; + case 1087: ret=decode_msm7(rtcm,SYS_GLO); break; + case 1230: ret=decode_type1230(rtcm); break; /* GLO L1 and L2 code-phase */ +#endif +#ifdef RTCM3_ENGAL + case 1045: ret=decode_type1045(rtcm); break; /* GAL F/NAV ephemerides */ + case 1046: ret=decode_type1046(rtcm); break; /* GAL I/NAV ephemerides */ + case 1094: ret=decode_msm4(rtcm,SYS_GAL); break; + case 1095: ret=decode_msm5(rtcm,SYS_GAL); break; + case 1096: ret=decode_msm6(rtcm,SYS_GAL); break; + case 1097: ret=decode_msm7(rtcm,SYS_GAL); break; +#endif +#ifdef RTCM3_ENSBS + case 1104: ret=decode_msm4(rtcm,SYS_SBS); break; + case 1105: ret=decode_msm5(rtcm,SYS_SBS); break; + case 1106: ret=decode_msm6(rtcm,SYS_SBS); break; + case 1107: ret=decode_msm7(rtcm,SYS_SBS); break; +#endif +#ifdef RTCM3_ENQZS + case 1044: ret=decode_type1044(rtcm); break; /* QZS ephemerides */ + case 1114: ret=decode_msm4(rtcm,SYS_QZS); break; + case 1115: ret=decode_msm5(rtcm,SYS_QZS); break; + case 1116: ret=decode_msm6(rtcm,SYS_QZS); break; + case 1117: ret=decode_msm7(rtcm,SYS_QZS); break; +#endif +#ifdef RTCM3_ENBDS + case 63: ret=decode_type1042(rtcm); break; /* Beidou ephemerides */ + case 1042: ret=decode_type1042(rtcm); break; /* Beidou ephemerides */ + case 1124: ret=decode_msm4(rtcm,SYS_CMP); break; + case 1125: ret=decode_msm5(rtcm,SYS_CMP); break; + case 1126: ret=decode_msm6(rtcm,SYS_CMP); break; + case 1127: ret=decode_msm7(rtcm,SYS_CMP); break; +#endif +#ifdef RTCM3_ENIRN + case 1041: ret=decode_type1041(rtcm); break; /* IRN ephemerides */ + case 1134: ret=decode_msm4(rtcm,SYS_IRN); break; + case 1135: ret=decode_msm5(rtcm,SYS_IRN); break; + case 1136: ret=decode_msm6(rtcm,SYS_IRN); break; + case 1137: ret=decode_msm7(rtcm,SYS_IRN); break; +#endif +#ifdef RTCM_ENA_SSR +case 1057: ret=decode_ssr1(rtcm,SYS_GPS,0); break; +case 1058: ret=decode_ssr2(rtcm,SYS_GPS,0); break; +case 1059: ret=decode_ssr3(rtcm,SYS_GPS,0); break; +case 1060: ret=decode_ssr4(rtcm,SYS_GPS,0); break; +case 1061: ret=decode_ssr5(rtcm,SYS_GPS,0); break; +case 1062: ret=decode_ssr6(rtcm,SYS_GPS,0); break; +case 1063: ret=decode_ssr1(rtcm,SYS_GLO,0); break; +case 1064: ret=decode_ssr2(rtcm,SYS_GLO,0); break; +case 1065: ret=decode_ssr3(rtcm,SYS_GLO,0); break; +case 1066: ret=decode_ssr4(rtcm,SYS_GLO,0); break; +case 1067: ret=decode_ssr5(rtcm,SYS_GLO,0); break; +case 1068: ret=decode_ssr6(rtcm,SYS_GLO,0); break; +case 1240: ret=decode_ssr1(rtcm,SYS_GAL,0); break; /* draft */ +case 1241: ret=decode_ssr2(rtcm,SYS_GAL,0); break; /* draft */ +case 1242: ret=decode_ssr3(rtcm,SYS_GAL,0); break; /* draft */ +case 1243: ret=decode_ssr4(rtcm,SYS_GAL,0); break; /* draft */ +case 1244: ret=decode_ssr5(rtcm,SYS_GAL,0); break; /* draft */ +case 1245: ret=decode_ssr6(rtcm,SYS_GAL,0); break; /* draft */ +case 1246: ret=decode_ssr1(rtcm,SYS_QZS,0); break; /* draft */ +case 1247: ret=decode_ssr2(rtcm,SYS_QZS,0); break; /* draft */ +case 1248: ret=decode_ssr3(rtcm,SYS_QZS,0); break; /* draft */ +case 1249: ret=decode_ssr4(rtcm,SYS_QZS,0); break; /* draft */ +case 1250: ret=decode_ssr5(rtcm,SYS_QZS,0); break; /* draft */ +case 1251: ret=decode_ssr6(rtcm,SYS_QZS,0); break; /* draft */ +case 1252: ret=decode_ssr1(rtcm,SYS_SBS,0); break; /* draft */ +case 1253: ret=decode_ssr2(rtcm,SYS_SBS,0); break; /* draft */ +case 1254: ret=decode_ssr3(rtcm,SYS_SBS,0); break; /* draft */ +case 1255: ret=decode_ssr4(rtcm,SYS_SBS,0); break; /* draft */ +case 1256: ret=decode_ssr5(rtcm,SYS_SBS,0); break; /* draft */ +case 1257: ret=decode_ssr6(rtcm,SYS_SBS,0); break; /* draft */ +case 1258: ret=decode_ssr1(rtcm,SYS_CMP,0); break; /* draft */ +case 1259: ret=decode_ssr2(rtcm,SYS_CMP,0); break; /* draft */ +case 1260: ret=decode_ssr3(rtcm,SYS_CMP,0); break; /* draft */ +case 1261: ret=decode_ssr4(rtcm,SYS_CMP,0); break; /* draft */ +case 1262: ret=decode_ssr5(rtcm,SYS_CMP,0); break; /* draft */ +case 1263: ret=decode_ssr6(rtcm,SYS_CMP,0); break; /* draft */ +case 11: ret=decode_ssr7(rtcm,SYS_GPS,0); break; /* tentative */ +case 12: ret=decode_ssr7(rtcm,SYS_GAL,0); break; /* tentative */ +case 13: ret=decode_ssr7(rtcm,SYS_QZS,0); break; /* tentative */ +case 14: ret=decode_ssr7(rtcm,SYS_CMP,0); break; /* tentative */ +case 4073: ret=decode_type4073(rtcm); break; +case 4076: ret=decode_type4076(rtcm); break; +#endif + } + if (ret>=0) { + if (1001<=type&&type<=1299) rtcm->nmsg3[type-1000]++; /* 1-299 */ + else if (4070<=type&&type<=4099) rtcm->nmsg3[type-3770]++; /* 300-329 */ + else rtcm->nmsg3[0]++; /* other */ + } + return ret; +} diff --git a/RTK/rtkcmn.c b/RTK/rtkcmn.c new file mode 100644 index 0000000..80955b6 --- /dev/null +++ b/RTK/rtkcmn.c @@ -0,0 +1,4516 @@ +/*------------------------------------------------------------------------------ + * rtkcmn.c : rtklib common functions + * + * Copyright (C) 2007-2020 by T.TAKASU, All rights reserved. + * + * options : -DLAPACK use LAPACK/BLAS + * -DMKL use Intel MKL + * -DTRACE enable debug trace + * -DWIN32 use WIN32 API + * -DNOCALLOC no use calloc for zero matrix + * -DIERS_MODEL use GMF instead of NMF + * -DDLL built for shared library + * -DCPUTIME_IN_GPST cputime operated in gpst + * + * references : + * [1] IS-GPS-200D, Navstar GPS Space Segment/Navigation User Interfaces, + * 7 March, 2006 + * [2] RTCA/DO-229C, Minimum operational performance standards for global + * positioning system/wide area augmentation system airborne equipment, + * November 28, 2001 + * [3] M.Rothacher, R.Schmid, ANTEX: The Antenna Exchange Format Version 1.4, + * 15 September, 2010 + * [4] A.Gelb ed., Applied Optimal Estimation, The M.I.T Press, 1974 + * [5] A.E.Niell, Global mapping functions for the atmosphere delay at radio + * wavelengths, Jounal of geophysical research, 1996 + * [6] W.Gurtner and L.Estey, RINEX The Receiver Independent Exchange Format + * Version 3.00, November 28, 2007 + * [7] J.Kouba, A Guide to using International GNSS Service (IGS) products, + * May 2009 + * [8] China Satellite Navigation Office, BeiDou navigation satellite system + * signal in space interface control document, open service signal B1I + * (version 1.0), Dec 2012 + * [9] J.Boehm, A.Niell, P.Tregoning and H.Shuh, Global Mapping Function + * (GMF): A new empirical mapping function base on numerical weather + * model data, Geophysical Research Letters, 33, L07304, 2006 + * [10] GLONASS/GPS/Galileo/Compass/SBAS NV08C receiver series BINR interface + * protocol specification ver.1.3, August, 2012 + * + * version : $Revision: 1.1 $ $Date: 2008/07/17 21:48:06 $ + * history : 2007/01/12 1.0 new + * 2007/03/06 1.1 input initial rover pos of pntpos() + * update only effective states of filter() + * fix bug of atan2() domain error + * 2007/04/11 1.2 add function antmodel() + * add gdop mask for pntpos() + * change constant MAXDTOE value + * 2007/05/25 1.3 add function execcmd(),expandpath() + * 2008/06/21 1.4 add funciton sortobs(),uniqeph(),screent() + * replace geodist() by sagnac correction way + * 2008/10/29 1.5 fix bug of ionosphereic mapping function + * fix bug of seasonal variation term of tropmapf + * 2008/12/27 1.6 add function tickget(), sleepms(), tracenav(), + * xyz2enu(), satposv(), pntvel(), covecef() + * 2009/03/12 1.7 fix bug on error-stop when localtime() returns NULL + * 2009/03/13 1.8 fix bug on time adjustment for summer time + * 2009/04/10 1.9 add function adjgpsweek(),getbits(),getbitu() + * add function geph2pos() + * 2009/06/08 1.10 add function seph2pos() + * 2009/11/28 1.11 change function pntpos() + * add function tracegnav(),tracepeph() + * 2009/12/22 1.12 change default parameter of ionos std + * valid under second for timeget() + * 2010/07/28 1.13 fix bug in tropmapf() + * added api: + * obs2code(),code2obs(),cross3(),normv3(), + * gst2time(),time2gst(),time_str(),timeset(), + * deg2dms(),dms2deg(),searchpcv(),antmodel_s(), + * tracehnav(),tracepclk(),reppath(),reppaths(), + * createdir() + * changed api: + * readpcv(), + * deleted api: + * uniqeph() + * 2010/08/20 1.14 omit to include mkl header files + * fix bug on chi-sqr(n) table + * 2010/12/11 1.15 added api: + * freeobs(),freenav(),ionppp() + * 2011/05/28 1.16 fix bug on half-hour offset by time2epoch() + * added api: + * uniqnav() + * 2012/06/09 1.17 add a leap second after 2012-6-30 + * 2012/07/15 1.18 add api setbits(),setbitu(),utc2gmst() + * fix bug on interpolation of antenna pcv + * fix bug on str2num() for string with over 256 char + * add api readblq(),satexclude(),setcodepri(), + * getcodepri() + * change api obs2code(),code2obs(),antmodel() + * 2012/12/25 1.19 fix bug on satwavelen(),code2obs(),obs2code() + * add api testsnr() + * 2013/01/04 1.20 add api gpst2bdt(),bdt2gpst(),bdt2time(),time2bdt() + * readblq(),readerp(),geterp(),crc16() + * change api eci2ecef(),sunmoonpos() + * 2013/03/26 1.21 tickget() uses clock_gettime() for linux + * 2013/05/08 1.22 fix bug on nutation coefficients for ast_args() + * 2013/06/02 1.23 add #ifdef for undefined CLOCK_MONOTONIC_RAW + * 2013/09/01 1.24 fix bug on interpolation of satellite antenna pcv + * 2013/09/06 1.25 fix bug on extrapolation of erp + * 2014/04/27 1.26 add SYS_LEO for satellite system + * add BDS L1 code for RINEX 3.02 and RTCM 3.2 + * support BDS L1 in satwavelen() + * 2014/05/29 1.27 fix bug on obs2code() to search obs code table + * 2014/08/26 1.28 fix problem on output of uncompress() for tar file + * add function to swap trace file with keywords + * 2014/10/21 1.29 strtok() -> strtok_r() in expath() for thread-safe + * add bdsmodear in procopt_default + * 2015/03/19 1.30 fix bug on interpolation of erp values in geterp() + * add leap second insertion before 2015/07/01 00:00 + * add api read_leaps() + * 2015/05/31 1.31 delte api windupcorr() + * 2015/08/08 1.32 add compile option CPUTIME_IN_GPST + * add api add_fatal() + * support usno leapsec.dat for api read_leaps() + * 2016/01/23 1.33 enable septentrio + * 2016/02/05 1.34 support GLONASS for savenav(), loadnav() + * 2016/06/11 1.35 delete trace() in reppath() to avoid deadlock + * 2016/07/01 1.36 support IRNSS + * add leap second before 2017/1/1 00:00:00 + * 2016/07/29 1.37 rename api compress() -> rtk_uncompress() + * rename api crc16() -> rtk_crc16() + * rename api crc24q() -> rtk_crc24q() + * rename api crc32() -> rtk_crc32() + * 2016/08/20 1.38 fix type incompatibility in win64 environment + * change constant _POSIX_C_SOURCE 199309 -> 199506 + * 2016/08/21 1.39 fix bug on week overflow in time2gpst()/gpst2time() + * 2016/09/05 1.40 fix bug on invalid nav data read in readnav() + * 2016/09/17 1.41 suppress warnings + * 2016/09/19 1.42 modify api deg2dms() to consider numerical error + * 2017/04/11 1.43 delete EXPORT for global variables + * 2018/10/10 1.44 modify api satexclude() + * 2020/11/30 1.45 add API code2idx() to get freq-index + * add API code2freq() to get carrier frequency + * add API timereset() to reset current time + * modify API obs2code(), code2obs() and setcodepri() + * delete API satwavelen() + * delete API csmooth() + * delete global variable lam_carr[] + * compensate L3,L4,... PCVs by L2 PCV if no PCV data + * in input file by API readpcv() + * add support hatanaka-compressed RINEX files with + * extension ".crx" or ".CRX" + * update stream format strings table + * update obs code strings and priority table + * use integer types in stdint.h + * surppress warnings + *-----------------------------------------------------------------------------*/ +#define _POSIX_C_SOURCE 199506 +#include "rtklib.h" + +#include +#include +#include + + +/* constants -----------------------------------------------------------------*/ + +#define POLYCRC32 0xEDB88320u /* CRC32 polynomial */ +#define POLYCRC24Q 0x1864CFBu /* CRC24Q polynomial */ + +#define SQR(x) ((x) * (x)) +#define MAX_VAR_EPH SQR(300.0) /* max variance eph to reject satellite (m^2) */ + +static const double gpst0[] = {1980, 1, 6, 0, 0, 0}; /* gps time reference */ +static const double gst0[] = {1999, 8, 22, 0, 0, 0}; /* galileo system time reference */ +static const double bdt0[] = {2006, 1, 1, 0, 0, 0}; /* beidou time reference */ + +static double leaps[MAXLEAPS + 1][7] = {/* leap seconds (y,m,d,h,m,s,utc-gpst) */ + {2017, 1, 1, 0, 0, 0, -18}, + {2015, 7, 1, 0, 0, 0, -17}, + {2012, 7, 1, 0, 0, 0, -16}, + {2009, 1, 1, 0, 0, 0, -15}, + {2006, 1, 1, 0, 0, 0, -14}, + {1999, 1, 1, 0, 0, 0, -13}, + {1997, 7, 1, 0, 0, 0, -12}, + {1996, 1, 1, 0, 0, 0, -11}, + {1994, 7, 1, 0, 0, 0, -10}, + {1993, 7, 1, 0, 0, 0, -9}, + {1992, 7, 1, 0, 0, 0, -8}, + {1991, 1, 1, 0, 0, 0, -7}, + {1990, 1, 1, 0, 0, 0, -6}, + {1988, 1, 1, 0, 0, 0, -5}, + {1985, 7, 1, 0, 0, 0, -4}, + {1983, 7, 1, 0, 0, 0, -3}, + {1982, 7, 1, 0, 0, 0, -2}, + {1981, 7, 1, 0, 0, 0, -1}, + {0}}; +const double chisqr[100] = {/* chi-sqr(n) (alpha=0.001) */ + 10.8, 13.8, 16.3, 18.5, 20.5, 22.5, 24.3, 26.1, 27.9, 29.6, + 31.3, 32.9, 34.5, 36.1, 37.7, 39.3, 40.8, 42.3, 43.8, 45.3, + 46.8, 48.3, 49.7, 51.2, 52.6, 54.1, 55.5, 56.9, 58.3, 59.7, + 61.1, 62.5, 63.9, 65.2, 66.6, 68.0, 69.3, 70.7, 72.1, 73.4, + 74.7, 76.0, 77.3, 78.6, 80.0, 81.3, 82.6, 84.0, 85.4, 86.7, + 88.0, 89.3, 90.6, 91.9, 93.3, 94.7, 96.0, 97.4, 98.7, 100, + 101, 102, 103, 104, 105, 107, 108, 109, 110, 112, + 113, 114, 115, 116, 118, 119, 120, 122, 123, 125, + 126, 127, 128, 129, 131, 132, 133, 134, 135, 137, + 138, 139, 140, 142, 143, 144, 145, 147, 148, 149}; +const char *formatstrs[32] = { /* stream format strings */ + "RTCM 2", /* 0 */ + "RTCM 3", /* 1 */ + "NovAtel OEM7", /* 2 */ + "ComNav", /* 3 */ + "u-blox UBX", /* 4 */ + "Swift Navigation SBP", /* 5 */ + "Hemisphere", /* 6 */ + "SkyTraq", /* 7 */ + "Javad GREIS", /* 8 */ + "NVS BINR", /* 9 */ + "BINEX", /* 10 */ + "Trimble RT17", /* 11 */ + "Septentrio SBF", /* 12 */ + "Tersus", /* 13 */ + "RINEX", /* 14 */ + "SP3", /* 15 */ + "RINEX CLK", /* 16 */ + "SBAS", /* 17 */ + "NMEA 0183", /* 18 */ + "TERSUS", /* 19 */ + NULL}; + +static char *obscodes[] = { + /* observation code strings */ + + "", "1C", "1P", "1W", "1Y", "1M", "1N", "1S", "1L", "1E", /* 0- 9 */ + "1A", "1B", "1X", "1Z", "2C", "2D", "2S", "2L", "2X", "2P", /* 10-19 */ + "2W", "2Y", "2M", "2N", "5I", "5Q", "5X", "7I", "7Q", "7X", /* 20-29 */ + "6A", "6B", "6C", "6X", "6Z", "6S", "6L", "8L", "8Q", "8X", /* 30-39 */ + "2I", "2Q", "6I", "6Q", "3I", "3Q", "3X", "1I", "1Q", "5A", /* 40-49 */ + "5B", "5C", "9A", "9B", "9C", "9X", "1D", "5D", "5P", "5Z", /* 50-59 */ + "6E", "7D", "7P", "7Z", "8D", "8P", "4A", "4B", "4X", "" /* 60-69 */ +}; +#ifdef L5_TO_L2 +/*L1 + L5˫Ƶջ L5ȼL2ǰ*/ +static char codepris[7][MAXFREQ][16] = { + /* code priority for each freq-index */ + /* L1/E1/B1 L2/E5b/B2b L5/E5a/B2a E6/LEX/B3 E5(a+b) */ + {"CPYWMNSL", "IQX", "CPYWMNDLSX", "", "", ""}, /* GPS */ + {"CPABX", "IQX", "CPABX", "", "", ""}, /* GLO */ + {"CABXZ", "XIQ", "XIQ", "ABCXZ", "IQX", ""}, /* GAL */ + {"CLSXZ", "IQXDPZ", "LSX", "LSXEZ", "", ""}, /* QZS */ + {"C", "IQX", "", "", "", ""}, /* SBS */ + {"IQXDPAN", "DPX", "IQXDPZ", "IQXA", "DPX", ""}, /* BDS */ + {"ABCX", "ABCX", "", "", "", ""} /* IRN */ +}; +#else +//ԭȼ +static char codepris[7][MAXFREQ][16] = { + /* code priority for each freq-index */ + /* L1/E1/B1 L2/E5b/B2b L5/E5a/B2a E6/LEX/B3 E5(a+b) */ + {"CPYWMNSL", "CPYWMNDLSX", "IQX", "", "", ""}, /* GPS */ + {"CPABX", "CPABX", "IQX", "", "", ""}, /* GLO */ + {"CABXZ", "XIQ", "XIQ", "ABCXZ", "IQX", ""}, /* GAL */ + {"CLSXZ", "LSX", "IQXDPZ", "LSXEZ", "", ""}, /* QZS */ + {"C", "IQX", "", "", "", ""}, /* SBS */ + {"IQXDPAN", "IQXDPZ", "DPX", "IQXA", "DPX", ""}, /* BDS */ + {"ABCX", "ABCX", "", "", "", ""} /* IRN */ +}; +#endif + +static fatalfunc_t *fatalfunc = NULL; /* fatal callback function */ + +/* crc tables generated by util/gencrc ---------------------------------------*/ +static const uint16_t tbl_CRC16[] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, + 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, + 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, + 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, + 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, + 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, + 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, + 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, + 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, + 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, + 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, + 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, + 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, + 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, + 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, + 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, + 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, + 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, + 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, + 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, + 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, + 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, + 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0}; +static const uint32_t tbl_CRC24Q[] = { + 0x000000, 0x864CFB, 0x8AD50D, 0x0C99F6, 0x93E6E1, 0x15AA1A, 0x1933EC, 0x9F7F17, + 0xA18139, 0x27CDC2, 0x2B5434, 0xAD18CF, 0x3267D8, 0xB42B23, 0xB8B2D5, 0x3EFE2E, + 0xC54E89, 0x430272, 0x4F9B84, 0xC9D77F, 0x56A868, 0xD0E493, 0xDC7D65, 0x5A319E, + 0x64CFB0, 0xE2834B, 0xEE1ABD, 0x685646, 0xF72951, 0x7165AA, 0x7DFC5C, 0xFBB0A7, + 0x0CD1E9, 0x8A9D12, 0x8604E4, 0x00481F, 0x9F3708, 0x197BF3, 0x15E205, 0x93AEFE, + 0xAD50D0, 0x2B1C2B, 0x2785DD, 0xA1C926, 0x3EB631, 0xB8FACA, 0xB4633C, 0x322FC7, + 0xC99F60, 0x4FD39B, 0x434A6D, 0xC50696, 0x5A7981, 0xDC357A, 0xD0AC8C, 0x56E077, + 0x681E59, 0xEE52A2, 0xE2CB54, 0x6487AF, 0xFBF8B8, 0x7DB443, 0x712DB5, 0xF7614E, + 0x19A3D2, 0x9FEF29, 0x9376DF, 0x153A24, 0x8A4533, 0x0C09C8, 0x00903E, 0x86DCC5, + 0xB822EB, 0x3E6E10, 0x32F7E6, 0xB4BB1D, 0x2BC40A, 0xAD88F1, 0xA11107, 0x275DFC, + 0xDCED5B, 0x5AA1A0, 0x563856, 0xD074AD, 0x4F0BBA, 0xC94741, 0xC5DEB7, 0x43924C, + 0x7D6C62, 0xFB2099, 0xF7B96F, 0x71F594, 0xEE8A83, 0x68C678, 0x645F8E, 0xE21375, + 0x15723B, 0x933EC0, 0x9FA736, 0x19EBCD, 0x8694DA, 0x00D821, 0x0C41D7, 0x8A0D2C, + 0xB4F302, 0x32BFF9, 0x3E260F, 0xB86AF4, 0x2715E3, 0xA15918, 0xADC0EE, 0x2B8C15, + 0xD03CB2, 0x567049, 0x5AE9BF, 0xDCA544, 0x43DA53, 0xC596A8, 0xC90F5E, 0x4F43A5, + 0x71BD8B, 0xF7F170, 0xFB6886, 0x7D247D, 0xE25B6A, 0x641791, 0x688E67, 0xEEC29C, + 0x3347A4, 0xB50B5F, 0xB992A9, 0x3FDE52, 0xA0A145, 0x26EDBE, 0x2A7448, 0xAC38B3, + 0x92C69D, 0x148A66, 0x181390, 0x9E5F6B, 0x01207C, 0x876C87, 0x8BF571, 0x0DB98A, + 0xF6092D, 0x7045D6, 0x7CDC20, 0xFA90DB, 0x65EFCC, 0xE3A337, 0xEF3AC1, 0x69763A, + 0x578814, 0xD1C4EF, 0xDD5D19, 0x5B11E2, 0xC46EF5, 0x42220E, 0x4EBBF8, 0xC8F703, + 0x3F964D, 0xB9DAB6, 0xB54340, 0x330FBB, 0xAC70AC, 0x2A3C57, 0x26A5A1, 0xA0E95A, + 0x9E1774, 0x185B8F, 0x14C279, 0x928E82, 0x0DF195, 0x8BBD6E, 0x872498, 0x016863, + 0xFAD8C4, 0x7C943F, 0x700DC9, 0xF64132, 0x693E25, 0xEF72DE, 0xE3EB28, 0x65A7D3, + 0x5B59FD, 0xDD1506, 0xD18CF0, 0x57C00B, 0xC8BF1C, 0x4EF3E7, 0x426A11, 0xC426EA, + 0x2AE476, 0xACA88D, 0xA0317B, 0x267D80, 0xB90297, 0x3F4E6C, 0x33D79A, 0xB59B61, + 0x8B654F, 0x0D29B4, 0x01B042, 0x87FCB9, 0x1883AE, 0x9ECF55, 0x9256A3, 0x141A58, + 0xEFAAFF, 0x69E604, 0x657FF2, 0xE33309, 0x7C4C1E, 0xFA00E5, 0xF69913, 0x70D5E8, + 0x4E2BC6, 0xC8673D, 0xC4FECB, 0x42B230, 0xDDCD27, 0x5B81DC, 0x57182A, 0xD154D1, + 0x26359F, 0xA07964, 0xACE092, 0x2AAC69, 0xB5D37E, 0x339F85, 0x3F0673, 0xB94A88, + 0x87B4A6, 0x01F85D, 0x0D61AB, 0x8B2D50, 0x145247, 0x921EBC, 0x9E874A, 0x18CBB1, + 0xE37B16, 0x6537ED, 0x69AE1B, 0xEFE2E0, 0x709DF7, 0xF6D10C, 0xFA48FA, 0x7C0401, + 0x42FA2F, 0xC4B6D4, 0xC82F22, 0x4E63D9, 0xD11CCE, 0x575035, 0x5BC9C3, 0xDD8538}; +/* function prototypes -------------------------------------------------------*/ +#ifdef MKL +#define LAPACK +#define dgemm_ dgemm +#define dgetrf_ dgetrf +#define dgetri_ dgetri +#define dgetrs_ dgetrs +#endif +#ifdef LAPACK +extern void dgemm_(char *, char *, int *, int *, int *, double *, double *, + int *, double *, int *, double *, double *, int *); +extern void dgetrf_(int *, int *, double *, int *, int *, int *); +extern void dgetri_(int *, double *, int *, int *, double *, int *, int *); +extern void dgetrs_(char *, int *, int *, double *, int *, int *, double *, + int *, int *); +#endif + +#ifdef IERS_MODEL +extern int gmf_(double *mjd, double *lat, double *lon, double *hgt, double *zd, + double *gmfh, double *gmfw); +#endif + +/* fatal error ---------------------------------------------------------------*/ +static void fatalerr(const char *format, ...) +{ + char msg[1024]; + va_list ap; + va_start(ap, format); + vsprintf(msg, format, ap); + va_end(ap); + if (fatalfunc) + fatalfunc(msg); + else + fprintf(stderr, "%s", msg); + exit(-9); +} +/* add fatal callback function ------------------------------------------------- + * add fatal callback function for mat(),zeros(),imat() + * args : fatalfunc_t *func I callback function + * return : none + * notes : if malloc() failed in return : none + *-----------------------------------------------------------------------------*/ +extern void add_fatal(fatalfunc_t *func) +{ + fatalfunc = func; +} +/* satellite system+prn/slot number to satellite number ------------------------ + * convert satellite system+prn/slot number to satellite number + * args : int sys I satellite system (SYS_GPS,SYS_GLO,...) + * int prn I satellite prn/slot number + * return : satellite number (0:error) + *-----------------------------------------------------------------------------*/ +extern int satno(int sys, int prn) +{ + if (prn <= 0) + return 0; + switch (sys) + { + case SYS_GPS: + if (prn < MINPRNGPS || MAXPRNGPS < prn) + return 0; + return prn - MINPRNGPS + 1; + case SYS_GLO: + if (prn < MINPRNGLO || MAXPRNGLO < prn) + return 0; + return NSATGPS + prn - MINPRNGLO + 1; + case SYS_GAL: + if (prn < MINPRNGAL || MAXPRNGAL < prn) + return 0; + return NSATGPS + NSATGLO + prn - MINPRNGAL + 1; + case SYS_QZS: + if (prn < MINPRNQZS || MAXPRNQZS < prn) + return 0; + return NSATGPS + NSATGLO + NSATGAL + prn - MINPRNQZS + 1; + case SYS_CMP: + if (prn < MINPRNCMP || MAXPRNCMP < prn) + return 0; + return NSATGPS + NSATGLO + NSATGAL + NSATQZS + prn - MINPRNCMP + 1; + case SYS_IRN: + if (prn < MINPRNIRN || MAXPRNIRN < prn) + return 0; + return NSATGPS + NSATGLO + NSATGAL + NSATQZS + NSATCMP + prn - MINPRNIRN + 1; + case SYS_LEO: + if (prn < MINPRNLEO || MAXPRNLEO < prn) + return 0; + return NSATGPS + NSATGLO + NSATGAL + NSATQZS + NSATCMP + NSATIRN + + prn - MINPRNLEO + 1; + case SYS_SBS: + if (prn < MINPRNSBS || MAXPRNSBS < prn) + return 0; + return NSATGPS + NSATGLO + NSATGAL + NSATQZS + NSATCMP + NSATIRN + NSATLEO + + prn - MINPRNSBS + 1; + } + return 0; +} +/* satellite number to satellite system ---------------------------------------- + * convert satellite number to satellite system + * args : int sat I satellite number (1-MAXSAT) + * int *prn IO satellite prn/slot number (NULL: no output) + * return : satellite system (SYS_GPS,SYS_GLO,...) + *-----------------------------------------------------------------------------*/ +extern int satsys(int sat, int *prn) +{ + int sys = SYS_NONE; + if (sat <= 0 || MAXSAT < sat) + sat = 0; + else if (sat <= NSATGPS) + { + sys = SYS_GPS; + sat += MINPRNGPS - 1; + } + else if ((sat -= NSATGPS) <= NSATGLO) + { + sys = SYS_GLO; + sat += MINPRNGLO - 1; + } + else if ((sat -= NSATGLO) <= NSATGAL) + { + sys = SYS_GAL; + sat += MINPRNGAL - 1; + } + else if ((sat -= NSATGAL) <= NSATQZS) + { + sys = SYS_QZS; + sat += MINPRNQZS - 1; + } + else if ((sat -= NSATQZS) <= NSATCMP) + { + sys = SYS_CMP; + sat += MINPRNCMP - 1; + } + else if ((sat -= NSATCMP) <= NSATIRN) + { + sys = SYS_IRN; + sat += MINPRNIRN - 1; + } + else if ((sat -= NSATIRN) <= NSATLEO) + { + sys = SYS_LEO; + sat += MINPRNLEO - 1; + } + else if ((sat -= NSATLEO) <= NSATSBS) + { + sys = SYS_SBS; + sat += MINPRNSBS - 1; + } + else + sat = 0; + if (prn) + *prn = sat; + return sys; +} +/* satellite id to satellite number -------------------------------------------- + * convert satellite id to satellite number + * args : char *id I satellite id (nn,Gnn,Rnn,Enn,Jnn,Cnn,Inn or Snn) + * return : satellite number (0: error) + * notes : 120-142 and 193-199 are also recognized as sbas and qzss + *-----------------------------------------------------------------------------*/ +extern int satid2no(const char *id) +{ + int sys, prn; + char code; + + if (sscanf(id, "%d", &prn) == 1) + { + if (MINPRNGPS <= prn && prn <= MAXPRNGPS) + sys = SYS_GPS; + else if (MINPRNSBS <= prn && prn <= MAXPRNSBS) + sys = SYS_SBS; + else if (MINPRNQZS <= prn && prn <= MAXPRNQZS) + sys = SYS_QZS; + else + return 0; + return satno(sys, prn); + } + if (sscanf(id, "%c%d", &code, &prn) < 2) + return 0; + + switch (code) + { + case 'G': + sys = SYS_GPS; + prn += MINPRNGPS - 1; + break; + case 'R': + sys = SYS_GLO; + prn += MINPRNGLO - 1; + break; + case 'E': + sys = SYS_GAL; + prn += MINPRNGAL - 1; + break; + case 'J': + sys = SYS_QZS; + prn += MINPRNQZS - 1; + break; + case 'C': + sys = SYS_CMP; + prn += MINPRNCMP - 1; + break; + case 'I': + sys = SYS_IRN; + prn += MINPRNIRN - 1; + break; + case 'L': + sys = SYS_LEO; + prn += MINPRNLEO - 1; + break; + case 'S': + sys = SYS_SBS; + prn += 100; + break; + default: + return 0; + } + return satno(sys, prn); +} +/* satellite number to satellite id -------------------------------------------- + * convert satellite number to satellite id + * args : int sat I satellite number + * char *id O satellite id (Gnn,Rnn,Enn,Jnn,Cnn,Inn or nnn) + * return : none + *-----------------------------------------------------------------------------*/ +extern void satno2id(int sat, char *id) +{ + int prn; + switch (satsys(sat, &prn)) + { + case SYS_GPS: + sprintf(id, "G%02d", prn - MINPRNGPS + 1); + return; + case SYS_GLO: + sprintf(id, "R%02d", prn - MINPRNGLO + 1); + return; + case SYS_GAL: + sprintf(id, "E%02d", prn - MINPRNGAL + 1); + return; + case SYS_QZS: + sprintf(id, "J%02d", prn - MINPRNQZS + 1); + return; + case SYS_CMP: + sprintf(id, "C%02d", prn - MINPRNCMP + 1); + return; + case SYS_IRN: + sprintf(id, "I%02d", prn - MINPRNIRN + 1); + return; + case SYS_LEO: + sprintf(id, "L%02d", prn - MINPRNLEO + 1); + return; + case SYS_SBS: + sprintf(id, "%03d", prn); + return; + } + strcpy(id, ""); +} +/* test excluded satellite ----------------------------------------------------- + * test excluded satellite + * args : int sat I satellite number + * double var I variance of ephemeris (m^2) + * int svh I sv health flag + * prcopt_t *opt I processing options (NULL: not used) + * return : status (1:excluded,0:not excluded) + *-----------------------------------------------------------------------------*/ +extern int satexclude(int sat, double var, int svh, const prcopt_t *opt) +{ + int sys = satsys(sat, NULL); + + if (svh < 0) + return 1; /* ephemeris unavailable */ + + if (opt) + { + if (opt->exsats[sat - 1] == 1) + return 1; /* excluded satellite */ + if (opt->exsats[sat - 1] == 2) + return 0; /* included satellite */ + if (!(sys & opt->navsys)) + return 1; /* unselected sat sys */ + } + if (sys == SYS_QZS) + svh &= 0xFE; /* mask QZSS LEX health */ + if (svh) + { + trace(3, "unhealthy satellite: sat=%3d svh=%02X\n", sat, svh); + return 1; + } + if (var > MAX_VAR_EPH) + { + trace(3, "invalid ura satellite: sat=%3d ura=%.2f\n", sat, sqrt(var)); + return 1; + } + return 0; +} +/* test SNR mask --------------------------------------------------------------- + * test SNR mask + * args : int base I rover or base-station (0:rover,1:base station) + * int idx I frequency index (0:L1,1:L2,2:L3,...) + * double el I elevation angle (rad) + * double snr I C/N0 (dBHz) + * snrmask_t *mask I SNR mask + * return : status (1:masked,0:unmasked) + *-----------------------------------------------------------------------------*/ +extern int testsnr(int base, int idx, double el, double snr, + const snrmask_t *mask) +{ + double minsnr, a; + int i; + + if (!mask->ena[base] || idx < 0 || idx >= NFREQ) + return 0; + + a = (el * R2D + 5.0) / 10.0; + i = (int)floor(a); + a -= i; + if (i < 1) + minsnr = mask->mask[idx][0]; + else if (i > 8) + minsnr = mask->mask[idx][8]; + else + minsnr = (1.0 - a) * mask->mask[idx][i - 1] + a * mask->mask[idx][i]; + + return snr < minsnr; +} +/* obs type string to obs code ------------------------------------------------- + * convert obs code type string to obs code + * args : char *str I obs code string ("1C","1P","1Y",...) + * return : obs code (CODE_???) + * notes : obs codes are based on RINEX 3.04 + *-----------------------------------------------------------------------------*/ +extern uint8_t obs2code(const char *obs) +{ + int i; + + for (i = 1; *obscodes[i]; i++) + { + if (strcmp(obscodes[i], obs)) + continue; + return (uint8_t)i; + } + return CODE_NONE; +} +/* obs code to obs code string ------------------------------------------------- + * convert obs code to obs code string + * args : uint8_t code I obs code (CODE_???) + * return : obs code string ("1C","1P","1P",...) + * notes : obs codes are based on RINEX 3.04 + *-----------------------------------------------------------------------------*/ +extern char *code2obs(uint8_t code) +{ + if (code <= CODE_NONE || MAXCODE < code) + return ""; + return obscodes[code]; +} +/* GPS obs code to frequency -------------------------------------------------*/ +static int code2freq_GPS(uint8_t code, double *freq) +{ + char *obs = code2obs(code); + + switch (obs[0]) + { + case '1': + *freq = FREQL1; + return 0; /* L1 */ + case '2': + *freq = FREQL2; + return 1; /* L2 */ + case '5': + *freq = FREQL5; + return 2; /* L5 */ + } + return -1; +} +/* GLONASS obs code to frequency ---------------------------------------------*/ +static int code2freq_GLO(uint8_t code, int fcn, double *freq) +{ + char *obs = code2obs(code); + + if (fcn < -7 || fcn > 6) + return -1; + + switch (obs[0]) + { + case '1': + *freq = FREQ1_GLO + DFRQ1_GLO * fcn; + return 0; /* G1 */ + case '2': + *freq = FREQ2_GLO + DFRQ2_GLO * fcn; + return 1; /* G2 */ + case '3': + *freq = FREQ3_GLO; + return 2; /* G3 */ + case '4': + *freq = FREQ1a_GLO; + return 0; /* G1a */ + case '6': + *freq = FREQ2a_GLO; + return 1; /* G2a */ + } + return -1; +} +/* Galileo obs code to frequency ---------------------------------------------*/ +static int code2freq_GAL(uint8_t code, double *freq) +{ + char *obs = code2obs(code); + + switch (obs[0]) + { + case '1': + *freq = FREQL1; + return 0; /* E1 */ + case '7': + *freq = FREQE5b; + return 1; /* E5b */ + case '5': + *freq = FREQL5; + return 2; /* E5a */ + case '6': + *freq = FREQL6; + return 3; /* E6 */ + case '8': + *freq = FREQE5ab; + return 4; /* E5ab */ + } + return -1; +} + +/* QZSS obs code to frequency ------------------------------------------------*/ +static int code2freq_QZS(uint8_t code, double *freq) +{ + char *obs = code2obs(code); + + switch (obs[0]) + { + case '1': + *freq = FREQL1; + return 0; /* L1 */ + case '2': + *freq = FREQL2; + return 1; /* L2 */ + case '5': + *freq = FREQL5; + return 2; /* L5 */ + case '6': + *freq = FREQL6; + return 3; /* L6 */ + } + return -1; +} +/* SBAS obs code to frequency ------------------------------------------------*/ +static int code2freq_SBS(uint8_t code, double *freq) +{ + char *obs = code2obs(code); + + switch (obs[0]) + { + case '1': + *freq = FREQL1; + return 0; /* L1 */ + case '5': + *freq = FREQL5; + return 1; /* L5 */ + } + return -1; +} +/* BDS obs code to frequency -------------------------------------------------*/ +static int code2freq_BDS(uint8_t code, double *freq) +{ + char *obs = code2obs(code); + + switch (obs[0]) + { + case '1': + *freq = FREQL1; + return 0; /* B1C ---->C1(BDS3)*/ + case '2': + *freq = FREQ1_CMP; + return 0; /* B1I---->C2(BDS2,BDS3) */ + case '7': + *freq = FREQ2_CMP; + return 1; /* B2I/B2b ---->C7(BDS2,BDS3)*/ + case '5': + *freq = FREQL5; + return 2; /* B2a ----->C5(BDS3)*/ + case '6': + *freq = FREQ3_CMP; + return 3; /* B3 ----C6(BDS2)*/ + case '8': + *freq = FREQE5ab; + return 4; /* B2ab----C8,B2(BDS3) */ + } + return -1; +} + +/* NavIC obs code to frequency -----------------------------------------------*/ +static int code2freq_IRN(uint8_t code, double *freq) +{ + char *obs = code2obs(code); + + switch (obs[0]) + { + case '5': + *freq = FREQL5; + return 0; /* L5 */ + case '9': + *freq = FREQs; + return 1; /* S */ + } + return -1; +} +/* system and obs code to frequency index -------------------------------------- + * convert system and obs code to frequency index + * args : int sys I satellite system (SYS_???) + * uint8_t code I obs code (CODE_???) + * return : frequency index (-1: error) + * 0 1 2 3 4 + * -------------------------------------- + * GPS L1 L2 L5 - - + * GLONASS G1 G2 G3 - - (G1=G1,G1a,G2=G2,G2a) + * Galileo E1 E5b E5a E6 E5ab + * QZSS L1 L2 L5 L6 - + * SBAS L1 - L5 - - + * BDS B1 B2 B2a B3 B2ab (B1=B1I,B1C,B2=B2I,B2b) + * NavIC L5 S - - - + *-----------------------------------------------------------------------------*/ +extern int code2idx(int sys, uint8_t code) +{ + double freq; + + switch (sys) + { + case SYS_GPS: + return code2freq_GPS(code, &freq); + case SYS_GLO: + return code2freq_GLO(code, 0, &freq); + case SYS_GAL: + return code2freq_GAL(code, &freq); + case SYS_QZS: + return code2freq_QZS(code, &freq); + case SYS_SBS: + return code2freq_SBS(code, &freq); + case SYS_CMP: + return code2freq_BDS(code, &freq); + case SYS_IRN: + return code2freq_IRN(code, &freq); + } + return -1; +} +/* system and obs code to frequency -------------------------------------------- + * convert system and obs code to carrier frequency + * args : int sys I satellite system (SYS_???) + * uint8_t code I obs code (CODE_???) + * int fcn I frequency channel number for GLONASS + * return : carrier frequency (Hz) (0.0: error) + *-----------------------------------------------------------------------------*/ +extern double code2freq(int sys, uint8_t code, int fcn) +{ + double freq = 0.0; + + switch (sys) + { + case SYS_GPS: + (void)code2freq_GPS(code, &freq); + break; + case SYS_GLO: + (void)code2freq_GLO(code, fcn, &freq); + break; + case SYS_GAL: + (void)code2freq_GAL(code, &freq); + break; + case SYS_QZS: + (void)code2freq_QZS(code, &freq); + break; + case SYS_SBS: + (void)code2freq_SBS(code, &freq); + break; + case SYS_CMP: + (void)code2freq_BDS(code, &freq); + break; + case SYS_IRN: + (void)code2freq_IRN(code, &freq); + break; + } + return freq; +} +/* satellite and obs code to frequency ----------------------------------------- + * convert satellite and obs code to carrier frequency + * args : int sat I satellite number + * uint8_t code I obs code (CODE_???) + * nav_t *nav_t I navigation data for GLONASS (NULL: not used) + * return : carrier frequency (Hz) (0.0: error) + *-----------------------------------------------------------------------------*/ +extern double sat2freq(int sat, uint8_t code, const nav_t *nav) +{ + int i, fcn = 0, sys, prn; + + sys = satsys(sat, &prn); + + if (sys == SYS_GLO) + { + if (!nav) + return 0.0; + for (i = 0; i < nav->ng; i++) + { + if (nav->geph[i].sat == sat) + break; + } + if (i < nav->ng) + { + fcn = nav->geph[i].frq; + } + else if (nav->glo_fcn[prn - 1] > 0) + { + fcn = nav->glo_fcn[prn - 1] - 8; + } + else + return 0.0; + } + return code2freq(sys, code, fcn); +} +/* set code priority ----------------------------------------------------------- + * set code priority for multiple codes in a frequency + * args : int sys I system (or of SYS_???) + * int idx I frequency index (0- ) + * char *pri I priority of codes (series of code characters) + * (higher priority precedes lower) + * return : none + *-----------------------------------------------------------------------------*/ +extern void setcodepri(int sys, int idx, const char *pri) +{ + trace(3, "setcodepri:sys=%d idx=%d pri=%s\n", sys, idx, pri); + + if (idx < 0 || idx >= MAXFREQ) + return; + if (sys & SYS_GPS) + strcpy(codepris[0][idx], pri); + if (sys & SYS_GLO) + strcpy(codepris[1][idx], pri); + if (sys & SYS_GAL) + strcpy(codepris[2][idx], pri); + if (sys & SYS_QZS) + strcpy(codepris[3][idx], pri); + if (sys & SYS_SBS) + strcpy(codepris[4][idx], pri); + if (sys & SYS_CMP) + strcpy(codepris[5][idx], pri); + if (sys & SYS_IRN) + strcpy(codepris[6][idx], pri); +} +/* get code priority ----------------------------------------------------------- + * get code priority for multiple codes in a frequency + * args : int sys I system (SYS_???) + * uint8_t code I obs code (CODE_???) + * char *opt I code options (NULL:no option) + * return : priority (15:highest-1:lowest,0:error) + *-----------------------------------------------------------------------------*/ +extern int getcodepri(int sys, uint8_t code, const char *opt) +{ + const char *p, *optstr; + char *obs, str[8] = ""; + int i, j; + + switch (sys) + { + case SYS_GPS: + i = 0; + optstr = "-GL%2s"; + break; + case SYS_GLO: + i = 1; + optstr = "-RL%2s"; + break; + case SYS_GAL: + i = 2; + optstr = "-EL%2s"; + break; + case SYS_QZS: + i = 3; + optstr = "-JL%2s"; + break; + case SYS_SBS: + i = 4; + optstr = "-SL%2s"; + break; + case SYS_CMP: + i = 5; + optstr = "-CL%2s"; + break; + case SYS_IRN: + i = 6; + optstr = "-IL%2s"; + break; + default: + return 0; + } + if ((j = code2idx(sys, code)) < 0) + return 0; + obs = code2obs(code); + + /* parse code options */ + for (p = opt; p && (p = strchr(p, '-')); p++) + { + if (sscanf(p, optstr, str) < 1 || str[0] != obs[0]) + continue; + return str[1] == obs[1] ? 15 : 0; + } + /* search code priority */ + return (p = strchr(codepris[i][j], obs[1])) ? 14 - (int)(p - codepris[i][j]) : 0; +} +/* extract unsigned/signed bits ------------------------------------------------ + * extract unsigned/signed bits from byte data + * args : uint8_t *buff I byte data + * int pos I bit position from start of data (bits) + * int len I bit length (bits) (len<=32) + * return : extracted unsigned/signed bits + *-----------------------------------------------------------------------------*/ +extern uint32_t getbitu(const uint8_t *buff, int pos, int len) +{ + uint32_t bits = 0; + int i; + for (i = pos; i < pos + len; i++) + bits = (bits << 1) + ((buff[i / 8] >> (7 - i % 8)) & 1u); + return bits; +} +extern int32_t getbits(const uint8_t *buff, int pos, int len) +{ + uint32_t bits = getbitu(buff, pos, len); + if (len <= 0 || 32 <= len || !(bits & (1u << (len - 1)))) + return (int32_t)bits; + return (int32_t)(bits | (~0u << len)); /* extend sign */ +} +/* set unsigned/signed bits ---------------------------------------------------- + * set unsigned/signed bits to byte data + * args : uint8_t *buff IO byte data + * int pos I bit position from start of data (bits) + * int len I bit length (bits) (len<=32) + * [u]int32_t data I unsigned/signed data + * return : none + *-----------------------------------------------------------------------------*/ +extern void setbitu(uint8_t *buff, int pos, int len, uint32_t data) +{ + uint32_t mask = 1u << (len - 1); + int i; + if (len <= 0 || 32 < len) + return; + for (i = pos; i < pos + len; i++, mask >>= 1) + { + if (data & mask) + buff[i / 8] |= 1u << (7 - i % 8); + else + buff[i / 8] &= ~(1u << (7 - i % 8)); + } +} +extern void setbits(uint8_t *buff, int pos, int len, int32_t data) +{ + if (data < 0) + data |= 1 << (len - 1); + else + data &= ~(1 << (len - 1)); /* set sign bit */ + setbitu(buff, pos, len, (uint32_t)data); +} +/* crc-32 parity --------------------------------------------------------------- + * compute crc-32 parity for novatel raw + * args : uint8_t *buff I data + * int len I data length (bytes) + * return : crc-32 parity + * notes : see NovAtel OEMV firmware manual 1.7 32-bit CRC + *-----------------------------------------------------------------------------*/ +extern uint32_t rtk_crc32(const uint8_t *buff, int len) +{ + uint32_t crc = 0; + int i, j; + + trace(4, "rtk_crc32: len=%d\n", len); + + for (i = 0; i < len; i++) + { + crc ^= buff[i]; + for (j = 0; j < 8; j++) + { + if (crc & 1) + crc = (crc >> 1) ^ POLYCRC32; + else + crc >>= 1; + } + } + return crc; +} +/* crc-24q parity -------------------------------------------------------------- + * compute crc-24q parity for sbas, rtcm3 + * args : uint8_t *buff I data + * int len I data length (bytes) + * return : crc-24Q parity + * notes : see reference [2] A.4.3.3 Parity + *-----------------------------------------------------------------------------*/ +extern uint32_t rtk_crc24q(const uint8_t *buff, int len) +{ + uint32_t crc = 0; + int i; + + trace(4, "rtk_crc24q: len=%d\n", len); + + for (i = 0; i < len; i++) + crc = ((crc << 8) & 0xFFFFFF) ^ tbl_CRC24Q[(crc >> 16) ^ buff[i]]; + return crc; +} +/* crc-16 parity --------------------------------------------------------------- + * compute crc-16 parity for binex, nvs + * args : uint8_t *buff I data + * int len I data length (bytes) + * return : crc-16 parity + * notes : see reference [10] A.3. + *-----------------------------------------------------------------------------*/ +extern uint16_t rtk_crc16(const uint8_t *buff, int len) +{ + uint16_t crc = 0; + int i; + + trace(4, "rtk_crc16: len=%d\n", len); + + for (i = 0; i < len; i++) + { + crc = (crc << 8) ^ tbl_CRC16[((crc >> 8) ^ buff[i]) & 0xFF]; + } + return crc; +} +/* decode navigation data word ------------------------------------------------- + * check party and decode navigation data word + * args : uint32_t word I navigation data word (2+30bit) + * (previous word D29*-30* + current word D1-30) + * uint8_t *data O decoded navigation data without parity + * (8bitx3) + * return : status (1:ok,0:parity error) + * notes : see reference [1] 20.3.5.2 user parity algorithm + *-----------------------------------------------------------------------------*/ +extern int decode_word(uint32_t word, uint8_t *data) +{ + const uint32_t hamming[] = { + 0xBB1F3480, 0x5D8F9A40, 0xAEC7CD00, 0x5763E680, 0x6BB1F340, 0x8B7A89C0}; + uint32_t parity = 0, w; + int i; + + trace(5, "decodeword: word=%08x\n", word); + + if (word & 0x40000000) + word ^= 0x3FFFFFC0; + + for (i = 0; i < 6; i++) + { + parity <<= 1; + for (w = (word & hamming[i]) >> 6; w; w >>= 1) + parity ^= w & 1; + } + if (parity != (word & 0x3F)) + return 0; + + for (i = 0; i < 3; i++) + data[i] = (uint8_t)(word >> (22 - i * 8)); + return 1; +} +/* new matrix ------------------------------------------------------------------ + * allocate memory of matrix + * args : int n,m I number of rows and columns of matrix + * return : matrix pointer (if n<=0 or m<=0, return NULL) + *-----------------------------------------------------------------------------*/ +extern double *mat(int n, int m) +{ + double *p; + + if (n <= 0 || m <= 0) + return NULL; + if (!(p = (double *)malloc(sizeof(double) * n * m))) + { + fatalerr("matrix memory allocation error: n=%d,m=%d\n", n, m); + } + return p; +} +/* new integer matrix ---------------------------------------------------------- + * allocate memory of integer matrix + * args : int n,m I number of rows and columns of matrix + * return : matrix pointer (if n<=0 or m<=0, return NULL) + *-----------------------------------------------------------------------------*/ +extern int *imat(int n, int m) +{ + int *p; + + if (n <= 0 || m <= 0) + return NULL; + if (!(p = (int *)malloc(sizeof(int) * n * m))) + { + fatalerr("integer matrix memory allocation error: n=%d,m=%d\n", n, m); + } + return p; +} +/* zero matrix ----------------------------------------------------------------- + * generate new zero matrix + * args : int n,m I number of rows and columns of matrix + * return : matrix pointer (if n<=0 or m<=0, return NULL) + *-----------------------------------------------------------------------------*/ +extern double *zeros(int n, int m) +{ + double *p; + +#if NOCALLOC + if ((p = mat(n, m))) + for (n = n * m - 1; n >= 0; n--) + p[n] = 0.0; +#else + if (n <= 0 || m <= 0) + return NULL; + if (!(p = (double *)calloc(sizeof(double), n * m))) + { + fatalerr("matrix memory allocation error: n=%d,m=%d\n", n, m); + } +#endif + return p; +} +/* identity matrix ------------------------------------------------------------- + * generate new identity matrix + * args : int n I number of rows and columns of matrix + * return : matrix pointer (if n<=0, return NULL) + *-----------------------------------------------------------------------------*/ +extern double *eye(int n) +{ + double *p; + int i; + + if ((p = zeros(n, n))) + for (i = 0; i < n; i++) + p[i + i * n] = 1.0; + return p; +} +/* inner product --------------------------------------------------------------- + * inner product of vectors + * args : double *a,*b I vector a,b (n x 1) + * int n I size of vector a,b + * return : a'*b + *-----------------------------------------------------------------------------*/ +extern double dot(const double *a, const double *b, int n) +{ + double c = 0.0; + + while (--n >= 0) + c += a[n] * b[n]; + return c; +} +/* euclid norm ----------------------------------------------------------------- + * euclid norm of vector + * args : double *a I vector a (n x 1) + * int n I size of vector a + * return : || a || + *-----------------------------------------------------------------------------*/ +extern double norm(const double *a, int n) +{ + return sqrt(dot(a, a, n)); +} +/* outer product of 3d vectors ------------------------------------------------- + * outer product of 3d vectors + * args : double *a,*b I vector a,b (3 x 1) + * double *c O outer product (a x b) (3 x 1) + * return : none + *-----------------------------------------------------------------------------*/ +extern void cross3(const double *a, const double *b, double *c) +{ + c[0] = a[1] * b[2] - a[2] * b[1]; + c[1] = a[2] * b[0] - a[0] * b[2]; + c[2] = a[0] * b[1] - a[1] * b[0]; +} +/* normalize 3d vector --------------------------------------------------------- + * normalize 3d vector + * args : double *a I vector a (3 x 1) + * double *b O normlized vector (3 x 1) || b || = 1 + * return : status (1:ok,0:error) + *-----------------------------------------------------------------------------*/ +extern int normv3(const double *a, double *b) +{ + double r; + if ((r = norm(a, 3)) <= 0.0) + return 0; + b[0] = a[0] / r; + b[1] = a[1] / r; + b[2] = a[2] / r; + return 1; +} +/* copy matrix ----------------------------------------------------------------- + * copy matrix + * args : double *A O destination matrix A (n x m) + * double *B I source matrix B (n x m) + * int n,m I number of rows and columns of matrix + * return : none + *-----------------------------------------------------------------------------*/ +extern void matcpy(double *A, const double *B, int n, int m) +{ + memcpy(A, B, sizeof(double) * n * m); +} + +/* multiply matrix ----------------------------------------------------------- +ڶRTKLIBжοʱһõ˺matmul + +extern void matmul(const char *tr, int n, int k, int m, double alpha, const double *A, const double *B, double beta, double *C) + +ΪC=alpha*A*B+beta*C + +trΪǷתõı־ + +nkmĴС˵ӦĸˣһбȻڵڶУͿԱʾ + +nһУkڶУmһк͵ڶС + +֮԰nkmǰ棬˳߼ʵǾһҪѭn*kΣӱ̵˳ŵġ +*/ +extern void matmul(const char *tr, int n, int k, int m, double alpha, + const double *A, const double *B, double beta, double *C) +{ + double d; + int i, j, x, f = tr[0] == 'N' ? (tr[1] == 'N' ? 1 : 2) : (tr[1] == 'N' ? 3 : 4); + + for (i = 0; i < n; i++) + for (j = 0; j < k; j++) + { + d = 0.0; + switch (f) + { + case 1: + for (x = 0; x < m; x++) + d += A[i + x * n] * B[x + j * m]; + break; + case 2: + for (x = 0; x < m; x++) + d += A[i + x * n] * B[j + x * k]; + break; + case 3: + for (x = 0; x < m; x++) + d += A[x + i * m] * B[x + j * m]; + break; + case 4: + for (x = 0; x < m; x++) + d += A[x + i * m] * B[j + x * k]; + break; + } + if (beta == 0.0) + C[i + j * n] = alpha * d; + else + C[i + j * n] = alpha * d + beta * C[i + j * n]; + } +} +/* LU decomposition ----------------------------------------------------------*/ +static int ludcmp(double *A, int n, int *indx, double *d) +{ + double big, s, tmp, *vv = mat(n, 1); + int i, imax = 0, j, k; + + *d = 1.0; + for (i = 0; i < n; i++) + { + big = 0.0; + for (j = 0; j < n; j++) + if ((tmp = fabs(A[i + j * n])) > big) + big = tmp; + if (big > 0.0) + vv[i] = 1.0 / big; + else + { + free(vv); + return -1; + } + } + for (j = 0; j < n; j++) + { + for (i = 0; i < j; i++) + { + s = A[i + j * n]; + for (k = 0; k < i; k++) + s -= A[i + k * n] * A[k + j * n]; + A[i + j * n] = s; + } + big = 0.0; + for (i = j; i < n; i++) + { + s = A[i + j * n]; + for (k = 0; k < j; k++) + s -= A[i + k * n] * A[k + j * n]; + A[i + j * n] = s; + if ((tmp = vv[i] * fabs(s)) >= big) + { + big = tmp; + imax = i; + } + } + if (j != imax) + { + for (k = 0; k < n; k++) + { + tmp = A[imax + k * n]; + A[imax + k * n] = A[j + k * n]; + A[j + k * n] = tmp; + } + *d = -(*d); + vv[imax] = vv[j]; + } + indx[j] = imax; + if (A[j + j * n] == 0.0) + { + free(vv); + return -1; + } + if (j != n - 1) + { + tmp = 1.0 / A[j + j * n]; + for (i = j + 1; i < n; i++) + A[i + j * n] *= tmp; + } + } + free(vv); + return 0; +} +/* LU back-substitution ------------------------------------------------------*/ +static void lubksb(const double *A, int n, const int *indx, double *b) +{ + double s; + int i, ii = -1, ip, j; + + for (i = 0; i < n; i++) + { + ip = indx[i]; + s = b[ip]; + b[ip] = b[i]; + if (ii >= 0) + for (j = ii; j < i; j++) + s -= A[i + j * n] * b[j]; + else if (s) + ii = i; + b[i] = s; + } + for (i = n - 1; i >= 0; i--) + { + s = b[i]; + for (j = i + 1; j < n; j++) + s -= A[i + j * n] * b[j]; + b[i] = s / A[i + i * n]; + } +} +/* inverse of matrix ---------------------------------------------------------*/ +extern int matinv(double *A, int n) +{ + double d, *B; + int i, j, *indx; + + indx = imat(n, 1); + B = mat(n, n); + matcpy(B, A, n, n); + if (ludcmp(B, n, indx, &d)) + { + free(indx); + free(B); + return -1; + } + for (j = 0; j < n; j++) + { + for (i = 0; i < n; i++) + A[i + j * n] = 0.0; + A[j + j * n] = 1.0; + lubksb(B, n, indx, A + j * n); + } + free(indx); + free(B); + return 0; +} +/* solve linear equation -----------------------------------------------------*/ +extern int solve(const char *tr, const double *A, const double *Y, int n, + int m, double *X) +{ + double *B = mat(n, n); + int info; + + matcpy(B, A, n, n); + if (!(info = matinv(B, n))) + matmul(tr[0] == 'N' ? "NN" : "TN", n, m, n, 1.0, B, Y, 0.0, X); + free(B); + return info; +} +/* end of matrix routines ----------------------------------------------------*/ + +/* least square estimation ----------------------------------------------------- + * least square estimation by solving normal equation (x=(A*A')^-1*A*y) + * args : double *A I transpose of (weighted) design matrix (n x m) + * double *y I (weighted) measurements (m x 1) + * int n,m I number of parameters and measurements (n<=m) + * double *x O estmated parameters (n x 1) + * double *Q O esimated parameters covariance matrix (n x n) + * return : status (0:ok,0>:error) + * notes : for weighted least square, replace A and y by A*w and w*y (w=W^(1/2)) + * matirix stored by column-major order (fortran convention) + * õ $x=(AAT){-1}Ay$ ߵֵ͸ֵЭ $Q=(AAT){-1}$ + *-----------------------------------------------------------------------------*/ +extern int lsq(const double *A, const double *y, int n, int m, double *x, + double *Q) +{ + double *Ay; + int info; + + if (m < n) + return -1; + Ay = mat(n, 1); + matmul("NN", n, 1, m, 1.0, A, y, 0.0, Ay); /* Ay=A*y 1ȼҰ벿 $A_y=Ay$*/ + matmul("NT", n, n, m, 1.0, A, A, 0.0, Q); /* Q=A*A' 2ټ벿ֵ $Q=AA^T$ */ + + if (!(info = matinv(Q, n))) + matmul("NN", n, 1, n, 1.0, Q, Ay, 0.0, x); /* x=Q^-1*Ay 3 Q $Q^{-1}$Դ洢 QУ + ҳ $A_y$õ xֵ*/ + free(Ay); + return info; +} +/* kalman filter --------------------------------------------------------------- +* kalman filter state update as follows: +* +* K=P*H*(H'*P*H+R)^-1, xp=x+K*v, Pp=(I-K*H')*P +* +* args : double *x I states vector (n x 1) +* double *P I covariance matrix of states (n x n) +* double *H I transpose of design matrix (n x m) +* double *v I innovation (measurement - model) (m x 1) +* double *R I covariance matrix of measurement error (m x m) +* int n,m I number of states and measurements +* double *xp O states vector after update (n x 1) +* double *Pp O covariance matrix of states after update (n x n) +* return : status (0:ok,<0:error) +* notes : matirix stored by column-major order (fortran convention) +* if state x[i]==0.0, not updates state x[i]/P[i+i*n] +* ˲״̬£ K=P*H*(H'*P*H+R)^-1, xp=x+K*v, Pp=(I-K*H')*P +* 9 +double *x I ״̬ (n x 1) +double *P I ״̬Э (n x n) +double *H I ۲ת (n x m) +double *v I ʵʹ۲Ԥ۲IJв (measurement - model) (m x 1) +double *R I Э (m x m) +int n I ״̬ +int m I ۲ֵ +double *xp O º״̬ (n x 1) +double *Pp O º״̬Э (n x n) +: +int O (0:ok,<0:error) +ǰȵ˳ (fortran convention) +*-----------------------------------------------------------------------------*/ +static int filter_(const double *x, const double *P, const double *H, + const double *v, const double *R, int n, int m, + double *xp, double *Pp) +{ + //þ㺯չʽо + double *F = mat(n, m), *Q = mat(m, m), *K = mat(n, m), *I = eye(n); + int info; + + matcpy(Q, R, m, m); + matcpy(xp, x, n, 1); + matmul("NN", n, m, n, 1.0, P, H, 0.0, F); /* Q=H'*P*H+R */ + matmul("TN", m, m, n, 1.0, H, F, 1.0, Q); + if (!(info = matinv(Q, m))) + { + matmul("NN", n, m, m, 1.0, F, Q, 0.0, K); /* K=P*H*Q^-1 */ + matmul("NN", n, 1, m, 1.0, K, v, 1.0, xp); /* xp=x+K*v */ + matmul("NT", n, n, m, -1.0, K, H, 1.0, I); /* Pp=(I-K*H')*P */ + matmul("NN", n, n, n, 1.0, I, P, 0.0, Pp); + } + free(F); + free(Q); + free(K); + free(I); + return info; +} +/*kalman˲ +7 +double *x IO ״̬ (n x 1) +double *P IO ״̬Э (n x n) +double *H I ۲ת (n x m) +double *v I ʵʹ۲Ԥ۲IJв (measurement - model) (m x 1) +double *R I Э (m x m) +int n I ״̬ +int m I ۲ֵ +: +int O (0:ok,<0:error) +*/ +extern int filter(double *x, double *P, const double *H, const double *v, + const double *R, int n, int m) +{ + double *x_, *xp_, *P_, *Pp_, *H_; + int i, j, k, info, *ix; + + /* create list of non-zero states + 1ѡҪµ״̬ x ͶӦ PH x_p_H_ */ + ix = imat(n, 1); + for (i = k = 0; i < n; i++) + if (x[i] != 0.0 && P[i + i * n] > 0.0) + ix[k++] = i; + x_ = mat(k, 1); + xp_ = mat(k, 1); + P_ = mat(k, k); + Pp_ = mat(k, k); + H_ = mat(k, m); + /* compress array by removing zero elements to save computation time */ + for (i = 0; i < k; i++) + { + x_[i] = x[ix[i]]; + for (j = 0; j < k; j++) + P_[i + j * k] = P[ix[i] + ix[j] * n]; + for (j = 0; j < m; j++) + H_[i + j * k] = H[ix[i] + j * n]; + } + /* do kalman filter state update on compressed arrays + 2 filter_ kalman˲*/ + info = filter_(x_, P_, H_, v, R, k, m, xp_, Pp_); + /* copy values from compressed arrays back to full arrays + 3ֵ浽 xP*/ + for (i = 0; i < k; i++) + { + x[ix[i]] = xp_[i]; + for (j = 0; j < k; j++) + P[ix[i] + ix[j] * n] = Pp_[i + j * k]; + } + free(ix); + free(x_); + free(xp_); + free(P_); + free(Pp_); + free(H_); + return info; +} +/* smoother -------------------------------------------------------------------- + * combine forward and backward filters by fixed-interval smoother as follows: + * + * xs=Qs*(Qf^-1*xf+Qb^-1*xb), Qs=(Qf^-1+Qb^-1)^-1) + * + * args : double *xf I forward solutions (n x 1) + * args : double *Qf I forward solutions covariance matrix (n x n) + * double *xb I backward solutions (n x 1) + * double *Qb I backward solutions covariance matrix (n x n) + * int n I number of solutions + * double *xs O smoothed solutions (n x 1) + * double *Qs O smoothed solutions covariance matrix (n x n) + * return : status (0:ok,0>:error) + * notes : see reference [4] 5.2 + * matirix stored by column-major order (fortran convention) + *-----------------------------------------------------------------------------*/ +extern int smoother(const double *xf, const double *Qf, const double *xb, + const double *Qb, int n, double *xs, double *Qs) +{ + double *invQf = mat(n, n), *invQb = mat(n, n), *xx = mat(n, 1); + int i, info = -1; + + matcpy(invQf, Qf, n, n); + matcpy(invQb, Qb, n, n); + if (!matinv(invQf, n) && !matinv(invQb, n)) + { + for (i = 0; i < n * n; i++) + Qs[i] = invQf[i] + invQb[i]; + if (!(info = matinv(Qs, n))) + { + matmul("NN", n, 1, n, 1.0, invQf, xf, 0.0, xx); + matmul("NN", n, 1, n, 1.0, invQb, xb, 1.0, xx); + matmul("NN", n, 1, n, 1.0, Qs, xx, 0.0, xs); + } + } + free(invQf); + free(invQb); + free(xx); + return info; +} +/* print matrix ---------------------------------------------------------------- + * print matrix to stdout + * args : double *A I matrix A (n x m) + * int n,m I number of rows and columns of A + * int p,q I total columns, columns under decimal point + * (FILE *fp I output file pointer) + * return : none + * notes : matirix stored by column-major order (fortran convention) + *-----------------------------------------------------------------------------*/ +extern void matfprint(const double A[], int n, int m, int p, int q, FILE *fp) +{ + int i, j; + + for (i = 0; i < n; i++) + { + for (j = 0; j < m; j++) + fprintf(fp, " %*.*f", p, q, A[i + j * n]); + fprintf(fp, "\n"); + } +} +extern void matprint(const double A[], int n, int m, int p, int q) +{ + matfprint(A, n, m, p, q, stdout); +} +/* string to number ------------------------------------------------------------ + * convert substring in string to number + * args : char *s I string ("... nnn.nnn ...") + * int i,n I substring position and width + * return : converted number (0.0:error) + *-----------------------------------------------------------------------------*/ +extern double str2num(const char *s, int i, int n) +{ + double value; + char str[256], *p = str; + + if (i < 0 || (int)strlen(s) < i || (int)sizeof(str) - 1 < n) + return 0.0; + for (s += i; *s && --n >= 0; s++) + *p++ = *s == 'd' || *s == 'D' ? 'E' : *s; + *p = '\0'; + return sscanf(str, "%lf", &value) == 1 ? value : 0.0; +} +/* string to time -------------------------------------------------------------- + * convert substring in string to gtime_t struct + * args : char *s I string ("... yyyy mm dd hh mm ss ...") + * int i,n I substring position and width + * gtime_t *t O gtime_t struct + * return : status (0:ok,0>:error) + *-----------------------------------------------------------------------------*/ +extern int str2time(const char *s, int i, int n, gtime_t *t) +{ + double ep[6]; + char str[256], *p = str; + + if (i < 0 || (int)strlen(s) < i || (int)sizeof(str) - 1 < i) + return -1; + for (s += i; *s && --n >= 0;) + *p++ = *s++; + *p = '\0'; + if (sscanf(str, "%lf %lf %lf %lf %lf %lf", ep, ep + 1, ep + 2, ep + 3, ep + 4, ep + 5) < 6) + return -1; + if (ep[0] < 100.0) + ep[0] += ep[0] < 80.0 ? 2000.0 : 1900.0; + *t = epoch2time(ep); + return 0; +} +/* convert calendar day/time to time ------------------------------------------- + * convert calendar day/time to gtime_t struct + * args : double *ep I day/time {year,month,day,hour,min,sec} + * return : gtime_t struct + * notes : proper in 1970-2037 or 1970-2099 (64bit time_t) + *-----------------------------------------------------------------------------*/ +extern gtime_t epoch2time(const double *ep) +{ + const int doy[] = {1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}; + gtime_t time = {0}; + int days, sec, year = (int)ep[0], mon = (int)ep[1], day = (int)ep[2]; + + if (year < 1970 || 2099 < year || mon < 1 || 12 < mon) + return time; + + /* leap year if year%4==0 in 1901-2099 */ + days = (year - 1970) * 365 + (year - 1969) / 4 + doy[mon - 1] + day - 2 + (year % 4 == 0 && mon >= 3 ? 1 : 0); + sec = (int)floor(ep[5]); + time.time = (time_t)days * 86400 + (int)ep[3] * 3600 + (int)ep[4] * 60 + sec; + time.sec = ep[5] - sec; + return time; +} +/* time to calendar day/time --------------------------------------------------- + * convert gtime_t struct to calendar day/time + * args : gtime_t t I gtime_t struct + * double *ep O day/time {year,month,day,hour,min,sec} + * return : none + * notes : proper in 1970-2037 or 1970-2099 (64bit time_t) + *-----------------------------------------------------------------------------*/ +extern void time2epoch(gtime_t t, double *ep) +{ + const int mday[] = {/* # of days in a month */ + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, + 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + int days, sec, mon, day; + + /* leap year if year%4==0 in 1901-2099 */ + days = (int)(t.time / 86400); + sec = (int)(t.time - (time_t)days * 86400); + for (day = days % 1461, mon = 0; mon < 48; mon++) + { + if (day >= mday[mon]) + day -= mday[mon]; + else + break; + } + ep[0] = 1970 + days / 1461 * 4 + mon / 12; + ep[1] = mon % 12 + 1; + ep[2] = day + 1; + ep[3] = sec / 3600; + ep[4] = sec % 3600 / 60; + ep[5] = sec % 60 + t.sec; +} +/* same as above but output limited to n decimals for formatted output */ +extern void time2epoch_n(gtime_t t, double *ep, int n) +{ + if (n < 0) + n = 0; + else if (n > 12) + n = 12; + if (1.0 - t.sec < 0.5 / pow(10.0, n)) + { + t.time++; + t.sec = 0.0; + }; + time2epoch(t, ep); +} +/* gps time to time ------------------------------------------------------------ + * convert week and tow in gps time to gtime_t struct + * args : int week I week number in gps time + * double sec I time of week in gps time (s) + * return : gtime_t struct + *-----------------------------------------------------------------------------*/ +extern gtime_t gpst2time(int week, double sec) +{ + gtime_t t = epoch2time(gpst0); + + if (sec < -1E9 || 1E9 < sec) + sec = 0.0; + t.time += (time_t)86400 * 7 * week + (int)sec; + t.sec = sec - (int)sec; + return t; +} +/* time to gps time ------------------------------------------------------------ + * convert gtime_t struct to week and tow in gps time + * args : gtime_t t I gtime_t struct + * int *week IO week number in gps time (NULL: no output) + * return : time of week in gps time (s) + *-----------------------------------------------------------------------------*/ +extern double time2gpst(gtime_t t, int *week) +{ + gtime_t t0 = epoch2time(gpst0); + time_t sec = t.time - t0.time; + int w = (int)(sec / (86400 * 7)); + + if (week) + *week = w; + return (double)(sec - (double)w * 86400 * 7) + t.sec; +} +/* galileo system time to time ------------------------------------------------- + * convert week and tow in galileo system time (gst) to gtime_t struct + * args : int week I week number in gst + * double sec I time of week in gst (s) + * return : gtime_t struct + *-----------------------------------------------------------------------------*/ +extern gtime_t gst2time(int week, double sec) +{ + gtime_t t = epoch2time(gst0); + + if (sec < -1E9 || 1E9 < sec) + sec = 0.0; + t.time += (time_t)86400 * 7 * week + (int)sec; + t.sec = sec - (int)sec; + return t; +} +/* time to galileo system time ------------------------------------------------- + * convert gtime_t struct to week and tow in galileo system time (gst) + * args : gtime_t t I gtime_t struct + * int *week IO week number in gst (NULL: no output) + * return : time of week in gst (s) + *-----------------------------------------------------------------------------*/ +extern double time2gst(gtime_t t, int *week) +{ + gtime_t t0 = epoch2time(gst0); + time_t sec = t.time - t0.time; + int w = (int)(sec / (86400 * 7)); + + if (week) + *week = w; + return (double)(sec - (double)w * 86400 * 7) + t.sec; +} +/* beidou time (bdt) to time --------------------------------------------------- + * convert week and tow in beidou time (bdt) to gtime_t struct + * args : int week I week number in bdt + * double sec I time of week in bdt (s) + * return : gtime_t struct + *-----------------------------------------------------------------------------*/ +extern gtime_t bdt2time(int week, double sec) +{ + gtime_t t = epoch2time(bdt0); + + if (sec < -1E9 || 1E9 < sec) + sec = 0.0; + t.time += (time_t)86400 * 7 * week + (int)sec; + t.sec = sec - (int)sec; + return t; +} +/* time to beidouo time (bdt) -------------------------------------------------- + * convert gtime_t struct to week and tow in beidou time (bdt) + * args : gtime_t t I gtime_t struct + * int *week IO week number in bdt (NULL: no output) + * return : time of week in bdt (s) + *-----------------------------------------------------------------------------*/ +extern double time2bdt(gtime_t t, int *week) +{ + gtime_t t0 = epoch2time(bdt0); + time_t sec = t.time - t0.time; + int w = (int)(sec / (86400 * 7)); + + if (week) + *week = w; + return (double)(sec - (double)w * 86400 * 7) + t.sec; +} +/* add time -------------------------------------------------------------------- + * add time to gtime_t struct + * args : gtime_t t I gtime_t struct + * double sec I time to add (s) + * return : gtime_t struct (t+sec) + *-----------------------------------------------------------------------------*/ +extern gtime_t timeadd(gtime_t t, double sec) +{ + double tt; + + t.sec += sec; + tt = floor(t.sec); + t.time += (int)tt; + t.sec -= tt; + return t; +} +/* time difference ------------------------------------------------------------- + * difference between gtime_t structs + * args : gtime_t t1,t2 I gtime_t structs + * return : time difference (t1-t2) (s) + *-----------------------------------------------------------------------------*/ +extern double timediff(gtime_t t1, gtime_t t2) +{ + return difftime(t1.time, t2.time) + t1.sec - t2.sec; +} +/* get current time in utc ----------------------------------------------------- + * get current time in utc + * args : none + * return : current time in utc + *-----------------------------------------------------------------------------*/ +static double timeoffset_ = 0.0; /* time offset (s) */ + +extern gtime_t timeget(void) +{ + gtime_t now; + now.time =time(RT_NULL); + now.sec =time(RT_NULL); + return timeadd(now, timeoffset_); +} +/* set current time in utc ----------------------------------------------------- + * set current time in utc + * args : gtime_t I current time in utc + * return : none + * notes : just set time offset between cpu time and current time + * the time offset is reflected to only timeget() + * not reentrant + *-----------------------------------------------------------------------------*/ +extern void timeset(gtime_t t) +{ + timeoffset_ += timediff(t, timeget()); +} +/* reset current time ---------------------------------------------------------- + * reset current time + * args : none + * return : none + *-----------------------------------------------------------------------------*/ +extern void timereset(void) +{ + timeoffset_ = 0.0; +} +/* read leap seconds table by text -------------------------------------------*/ +static int read_leaps_text(FILE *fp) +{ + char buff[256], *p; + int i, n = 0, ep[6], ls; + + rewind(fp); + + while (fgets(buff, sizeof(buff), fp) && n < MAXLEAPS) + { + if ((p = strchr(buff, '#'))) + *p = '\0'; + if (sscanf(buff, "%d %d %d %d %d %d %d", ep, ep + 1, ep + 2, ep + 3, ep + 4, ep + 5, + &ls) < 7) + continue; + for (i = 0; i < 6; i++) + leaps[n][i] = ep[i]; + leaps[n++][6] = ls; + } + return n; +} +/* read leap seconds table by usno -------------------------------------------*/ +static int read_leaps_usno(FILE *fp) +{ + static const char *months[] = { + "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"}; + double jd, tai_utc; + char buff[256], month[32] = {'\0'}, ls[MAXLEAPS][7] = {{0}}; + int i, j, y, m, d, n = 0; + + rewind(fp); + + while (fgets(buff, sizeof(buff), fp) && n < MAXLEAPS) + { + if (sscanf(buff, "%d %s %d =JD %lf TAI-UTC= %lf", &y, month, &d, &jd, + &tai_utc) < 5) + continue; + if (y < 1980) + continue; + for (m = 1; m <= 12; m++) + if (!strcmp(months[m - 1], month)) + break; + if (m >= 13) + continue; + ls[n][0] = y; + ls[n][1] = m; + ls[n][2] = d; + ls[n++][6] = (char)(19.0 - tai_utc); + } + for (i = 0; i < n; i++) + for (j = 0; j < 7; j++) + { + leaps[i][j] = ls[n - i - 1][j]; + } + return n; +} +/* read leap seconds table ----------------------------------------------------- + * read leap seconds table + * args : char *file I leap seconds table file + * return : status (1:ok,0:error) + * notes : The leap second table should be as follows or leapsec.dat provided + * by USNO. + * (1) The records in the table file cosist of the following fields: + * year month day hour min sec UTC-GPST(s) + * (2) The date and time indicate the start UTC time for the UTC-GPST + * (3) The date and time should be descending order. + *-----------------------------------------------------------------------------*/ +extern int read_leaps(const char *file) +{ + FILE *fp; + int i, n; + + if (!(fp = fopen(file, "r"))) + return 0; + + /* read leap seconds table by text or usno */ + if (!(n = read_leaps_text(fp)) && !(n = read_leaps_usno(fp))) + { + fclose(fp); + return 0; + } + for (i = 0; i < 7; i++) + leaps[n][i] = 0.0; + fclose(fp); + return 1; +} +/* gpstime to utc -------------------------------------------------------------- + * convert gpstime to utc considering leap seconds + * args : gtime_t t I time expressed in gpstime + * return : time expressed in utc + * notes : ignore slight time offset under 100 ns + *-----------------------------------------------------------------------------*/ +extern gtime_t gpst2utc(gtime_t t) +{ + gtime_t tu; + int i; + + for (i = 0; leaps[i][0] > 0; i++) + { + tu = timeadd(t, leaps[i][6]); + if (timediff(tu, epoch2time(leaps[i])) >= 0.0) + return tu; + } + return t; +} +/* utc to gpstime -------------------------------------------------------------- + * convert utc to gpstime considering leap seconds + * args : gtime_t t I time expressed in utc + * return : time expressed in gpstime + * notes : ignore slight time offset under 100 ns + *-----------------------------------------------------------------------------*/ +extern gtime_t utc2gpst(gtime_t t) +{ + int i; + + for (i = 0; leaps[i][0] > 0; i++) + { + if (timediff(t, epoch2time(leaps[i])) >= 0.0) + return timeadd(t, -leaps[i][6]); + } + return t; +} +/* gpstime to bdt -------------------------------------------------------------- + * convert gpstime to bdt (beidou navigation satellite system time) + * args : gtime_t t I time expressed in gpstime + * return : time expressed in bdt + * notes : ref [8] 3.3, 2006/1/1 00:00 BDT = 2006/1/1 00:00 UTC + * no leap seconds in BDT + * ignore slight time offset under 100 ns + *-----------------------------------------------------------------------------*/ +extern gtime_t gpst2bdt(gtime_t t) +{ + return timeadd(t, -14.0); +} +/* bdt to gpstime -------------------------------------------------------------- + * convert bdt (beidou navigation satellite system time) to gpstime + * args : gtime_t t I time expressed in bdt + * return : time expressed in gpstime + * notes : see gpst2bdt() + *-----------------------------------------------------------------------------*/ +extern gtime_t bdt2gpst(gtime_t t) +{ + return timeadd(t, 14.0); +} +/* time to day and sec -------------------------------------------------------*/ +static double time2sec(gtime_t time, gtime_t *day) +{ + double ep[6], sec; + time2epoch(time, ep); + sec = ep[3] * 3600.0 + ep[4] * 60.0 + ep[5]; + ep[3] = ep[4] = ep[5] = 0.0; + *day = epoch2time(ep); + return sec; +} +/* utc to gmst ----------------------------------------------------------------- + * convert utc to gmst (Greenwich mean sidereal time) + * args : gtime_t t I time expressed in utc + * double ut1_utc I UT1-UTC (s) + * return : gmst (rad) + *-----------------------------------------------------------------------------*/ +extern double utc2gmst(gtime_t t, double ut1_utc) +{ + const double ep2000[] = {2000, 1, 1, 12, 0, 0}; + gtime_t tut, tut0; + double ut, t1, t2, t3, gmst0, gmst; + + tut = timeadd(t, ut1_utc); + ut = time2sec(tut, &tut0); + t1 = timediff(tut0, epoch2time(ep2000)) / 86400.0 / 36525.0; + t2 = t1 * t1; + t3 = t2 * t1; + gmst0 = 24110.54841 + 8640184.812866 * t1 + 0.093104 * t2 - 6.2E-6 * t3; + gmst = gmst0 + 1.002737909350795 * ut; + + return fmod(gmst, 86400.0) * PI / 43200.0; /* 0 <= gmst <= 2*PI */ +} +/* time to string -------------------------------------------------------------- + * convert gtime_t struct to string + * args : gtime_t t I gtime_t struct + * char *s O string ("yyyy/mm/dd hh:mm:ss.ssss") + * int n I number of decimals + * return : none + *-----------------------------------------------------------------------------*/ +extern void time2str(gtime_t t, char *s, int n) +{ + double ep[6]; + + if (n < 0) + n = 0; + else if (n > 12) + n = 12; + if (1.0 - t.sec < 0.5 / pow(10.0, n)) + { + t.time++; + t.sec = 0.0; + }; + time2epoch(t, ep); + sprintf(s, "%04.0f/%02.0f/%02.0f %02.0f:%02.0f:%0*.*f", ep[0], ep[1], ep[2], + ep[3], ep[4], n <= 0 ? 2 : n + 3, n <= 0 ? 0 : n, ep[5]); +} +/* get time string ------------------------------------------------------------- + * get time string + * args : gtime_t t I gtime_t struct + * int n I number of decimals + * return : time string + * notes : not reentrant, do not use multiple in a function + *-----------------------------------------------------------------------------*/ +extern char *time_str(gtime_t t, int n) +{ + static char buff[64]; + time2str(t, buff, n); + return buff; +} +/* time to day of year --------------------------------------------------------- + * convert time to day of year + * args : gtime_t t I gtime_t struct + * return : day of year (days) + *-----------------------------------------------------------------------------*/ +extern double time2doy(gtime_t t) +{ + double ep[6]; + + time2epoch(t, ep); + ep[1] = ep[2] = 1.0; + ep[3] = ep[4] = ep[5] = 0.0; + return timediff(t, epoch2time(ep)) / 86400.0 + 1.0; +} +/* adjust gps week number ------------------------------------------------------ + * adjust gps week number using cpu time + * args : int week I not-adjusted gps week number (0-1023) + * return : adjusted gps week number + *-----------------------------------------------------------------------------*/ +extern int adjgpsweek(int week) +{ + int w; + (void)time2gpst(utc2gpst(timeget()), &w); + if (w < 1560) + w = 1560; /* use 2009/12/1 if time is earlier than 2009/12/1 */ + return week + (w - week + 1) / 1024 * 1024; +} +/* get tick time --------------------------------------------------------------- + * get current tick in ms + * args : none + * return : current tick in ms + *-----------------------------------------------------------------------------*/ +extern uint32_t tickget(void) +{ + return rt_tick_get(); + +} + +/* sleep ms -------------------------------------------------------------------- + * sleep ms + * args : int ms I miliseconds to sleep (<0:no sleep) + * return : none + *-----------------------------------------------------------------------------*/ +extern void sleepms(int ms) +{ + rt_thread_sleep((rt_tick_t)ms); +} +/* convert degree to deg-min-sec ----------------------------------------------- + * convert degree to degree-minute-second + * args : double deg I degree + * double *dms O degree-minute-second {deg,min,sec} + * int ndec I number of decimals of second + * return : none + *-----------------------------------------------------------------------------*/ +extern void deg2dms(double deg, double *dms, int ndec) +{ + double sign = deg < 0.0 ? -1.0 : 1.0, a = fabs(deg); + double unit = pow(0.1, ndec); + dms[0] = floor(a); + a = (a - dms[0]) * 60.0; + dms[1] = floor(a); + a = (a - dms[1]) * 60.0; + dms[2] = floor(a / unit + 0.5) * unit; + if (dms[2] >= 60.0) + { + dms[2] = 0.0; + dms[1] += 1.0; + if (dms[1] >= 60.0) + { + dms[1] = 0.0; + dms[0] += 1.0; + } + } + dms[0] *= sign; +} +/* convert deg-min-sec to degree ----------------------------------------------- + * convert degree-minute-second to degree + * args : double *dms I degree-minute-second {deg,min,sec} + * return : degree + *-----------------------------------------------------------------------------*/ +extern double dms2deg(const double *dms) +{ + double sign = dms[0] < 0.0 ? -1.0 : 1.0; + return sign * (fabs(dms[0]) + dms[1] / 60.0 + dms[2] / 3600.0); +} +/* transform ecef to geodetic postion ------------------------------------------ + * transform ecef position to geodetic position + * args : double *r I ecef position {x,y,z} (m) + * double *pos O geodetic position {lat,lon,h} (rad,m) + * return : none + * notes : WGS84, ellipsoidal height + *-----------------------------------------------------------------------------*/ +extern void ecef2pos(const double *r, double *pos) +{ + double e2 = FE_WGS84 * (2.0 - FE_WGS84), r2 = dot(r, r, 2), z, zk, v = RE_WGS84, sinp; + + for (z = r[2], zk = 0.0; fabs(z - zk) >= 1E-4;) + { + zk = z; + sinp = z / sqrt(r2 + z * z); + v = RE_WGS84 / sqrt(1.0 - e2 * sinp * sinp); + z = r[2] + v * e2 * sinp; + } + pos[0] = r2 > 1E-12 ? atan(z / sqrt(r2)) : (r[2] > 0.0 ? PI / 2.0 : -PI / 2.0); + pos[1] = r2 > 1E-12 ? atan2(r[1], r[0]) : 0.0; + pos[2] = sqrt(r2 + z * z) - v; +} +/* transform geodetic to ecef position ----------------------------------------- + * transform geodetic position to ecef position + * args : double *pos I geodetic position {lat,lon,h} (rad,m) + * double *r O ecef position {x,y,z} (m) + * return : none + * notes : WGS84, ellipsoidal height + *-----------------------------------------------------------------------------*/ +extern void pos2ecef(const double *pos, double *r) +{ + double sinp = sin(pos[0]), cosp = cos(pos[0]), sinl = sin(pos[1]), cosl = cos(pos[1]); + double e2 = FE_WGS84 * (2.0 - FE_WGS84), v = RE_WGS84 / sqrt(1.0 - e2 * sinp * sinp); + + r[0] = (v + pos[2]) * cosp * cosl; + r[1] = (v + pos[2]) * cosp * sinl; + r[2] = (v * (1.0 - e2) + pos[2]) * sinp; +} +/* ecef to local coordinate transfromation matrix ------------------------------ + * compute ecef to local coordinate transfromation matrix + * args : double *pos I geodetic position {lat,lon} (rad) + * double *E O ecef to local coord transformation matrix (3x3) + * return : none + * notes : matirix stored by column-major order (fortran convention) + *-----------------------------------------------------------------------------*/ +extern void xyz2enu(const double *pos, double *E) +{ + double sinp = sin(pos[0]), cosp = cos(pos[0]), sinl = sin(pos[1]), cosl = cos(pos[1]); + + E[0] = -sinl; + E[1] = -sinp * cosl; + E[2] = cosp * cosl; + E[3] = cosl; + E[4] = -sinp * sinl; + E[5] = cosp * sinl; + E[6] = 0.0; + E[7] = cosp; + E[8] = sinp; +} +/* transform ecef vector to local tangental coordinate ------------------------- + * transform ecef vector to local tangental coordinate + * args : double *pos I geodetic position {lat,lon} (rad) + * double *r I vector in ecef coordinate {x,y,z} + * double *e O vector in local tangental coordinate {e,n,u} + * return : none + *-----------------------------------------------------------------------------*/ +extern void ecef2enu(const double *pos, const double *r, double *e) +{ + double E[9]; + + xyz2enu(pos, E); + matmul("NN", 3, 1, 3, 1.0, E, r, 0.0, e); +} +/* transform local vector to ecef coordinate ----------------------------------- + * transform local tangental coordinate vector to ecef + * args : double *pos I geodetic position {lat,lon} (rad) + * double *e I vector in local tangental coordinate {e,n,u} + * double *r O vector in ecef coordinate {x,y,z} + * return : none + *-----------------------------------------------------------------------------*/ +extern void enu2ecef(const double *pos, const double *e, double *r) +{ + double E[9]; + + xyz2enu(pos, E); + matmul("TN", 3, 1, 3, 1.0, E, e, 0.0, r); +} +/* transform covariance to local tangental coordinate -------------------------- + * transform ecef covariance to local tangental coordinate + * args : double *pos I geodetic position {lat,lon} (rad) + * double *P I covariance in ecef coordinate + * double *Q O covariance in local tangental coordinate + * return : none + *-----------------------------------------------------------------------------*/ +extern void covenu(const double *pos, const double *P, double *Q) +{ + double E[9], EP[9]; + + xyz2enu(pos, E); + matmul("NN", 3, 3, 3, 1.0, E, P, 0.0, EP); + matmul("NT", 3, 3, 3, 1.0, EP, E, 0.0, Q); +} +/* transform local enu coordinate covariance to xyz-ecef ----------------------- + * transform local enu covariance to xyz-ecef coordinate + * args : double *pos I geodetic position {lat,lon} (rad) + * double *Q I covariance in local enu coordinate + * double *P O covariance in xyz-ecef coordinate + * return : none + *-----------------------------------------------------------------------------*/ +extern void covecef(const double *pos, const double *Q, double *P) +{ + double E[9], EQ[9]; + + xyz2enu(pos, E); + matmul("TN", 3, 3, 3, 1.0, E, Q, 0.0, EQ); + matmul("NN", 3, 3, 3, 1.0, EQ, E, 0.0, P); +} +/* coordinate rotation matrix ------------------------------------------------*/ +#define Rx(t, X) \ + do \ + { \ + (X)[0] = 1.0; \ + (X)[1] = (X)[2] = (X)[3] = (X)[6] = 0.0; \ + (X)[4] = (X)[8] = cos(t); \ + (X)[7] = sin(t); \ + (X)[5] = -(X)[7]; \ + } while (0) + +#define Ry(t, X) \ + do \ + { \ + (X)[4] = 1.0; \ + (X)[1] = (X)[3] = (X)[5] = (X)[7] = 0.0; \ + (X)[0] = (X)[8] = cos(t); \ + (X)[2] = sin(t); \ + (X)[6] = -(X)[2]; \ + } while (0) + +#define Rz(t, X) \ + do \ + { \ + (X)[8] = 1.0; \ + (X)[2] = (X)[5] = (X)[6] = (X)[7] = 0.0; \ + (X)[0] = (X)[4] = cos(t); \ + (X)[3] = sin(t); \ + (X)[1] = -(X)[3]; \ + } while (0) + +/* astronomical arguments: f={l,l',F,D,OMG} (rad) ----------------------------*/ +static void ast_args(double t, double *f) +{ + static const double fc[][5] = {/* coefficients for iau 1980 nutation */ + {134.96340251, 1717915923.2178, 31.8792, 0.051635, -0.00024470}, + {357.52910918, 129596581.0481, -0.5532, 0.000136, -0.00001149}, + {93.27209062, 1739527262.8478, -12.7512, -0.001037, 0.00000417}, + {297.85019547, 1602961601.2090, -6.3706, 0.006593, -0.00003169}, + {125.04455501, -6962890.2665, 7.4722, 0.007702, -0.00005939}}; + double tt[4]; + int i, j; + + for (tt[0] = t, i = 1; i < 4; i++) + tt[i] = tt[i - 1] * t; + for (i = 0; i < 5; i++) + { + f[i] = fc[i][0] * 3600.0; + for (j = 0; j < 4; j++) + f[i] += fc[i][j + 1] * tt[j]; + f[i] = fmod(f[i] * AS2R, 2.0 * PI); + } +} +/* iau 1980 nutation ---------------------------------------------------------*/ +static void nut_iau1980(double t, const double *f, double *dpsi, double *deps) +{ + static const double nut[106][10] = { + {0, 0, 0, 0, 1, -6798.4, -171996, -174.2, 92025, 8.9}, + {0, 0, 2, -2, 2, 182.6, -13187, -1.6, 5736, -3.1}, + {0, 0, 2, 0, 2, 13.7, -2274, -0.2, 977, -0.5}, + {0, 0, 0, 0, 2, -3399.2, 2062, 0.2, -895, 0.5}, + {0, -1, 0, 0, 0, -365.3, -1426, 3.4, 54, -0.1}, + {1, 0, 0, 0, 0, 27.6, 712, 0.1, -7, 0.0}, + {0, 1, 2, -2, 2, 121.7, -517, 1.2, 224, -0.6}, + {0, 0, 2, 0, 1, 13.6, -386, -0.4, 200, 0.0}, + {1, 0, 2, 0, 2, 9.1, -301, 0.0, 129, -0.1}, + {0, -1, 2, -2, 2, 365.2, 217, -0.5, -95, 0.3}, + {-1, 0, 0, 2, 0, 31.8, 158, 0.0, -1, 0.0}, + {0, 0, 2, -2, 1, 177.8, 129, 0.1, -70, 0.0}, + {-1, 0, 2, 0, 2, 27.1, 123, 0.0, -53, 0.0}, + {1, 0, 0, 0, 1, 27.7, 63, 0.1, -33, 0.0}, + {0, 0, 0, 2, 0, 14.8, 63, 0.0, -2, 0.0}, + {-1, 0, 2, 2, 2, 9.6, -59, 0.0, 26, 0.0}, + {-1, 0, 0, 0, 1, -27.4, -58, -0.1, 32, 0.0}, + {1, 0, 2, 0, 1, 9.1, -51, 0.0, 27, 0.0}, + {-2, 0, 0, 2, 0, -205.9, -48, 0.0, 1, 0.0}, + {-2, 0, 2, 0, 1, 1305.5, 46, 0.0, -24, 0.0}, + {0, 0, 2, 2, 2, 7.1, -38, 0.0, 16, 0.0}, + {2, 0, 2, 0, 2, 6.9, -31, 0.0, 13, 0.0}, + {2, 0, 0, 0, 0, 13.8, 29, 0.0, -1, 0.0}, + {1, 0, 2, -2, 2, 23.9, 29, 0.0, -12, 0.0}, + {0, 0, 2, 0, 0, 13.6, 26, 0.0, -1, 0.0}, + {0, 0, 2, -2, 0, 173.3, -22, 0.0, 0, 0.0}, + {-1, 0, 2, 0, 1, 27.0, 21, 0.0, -10, 0.0}, + {0, 2, 0, 0, 0, 182.6, 17, -0.1, 0, 0.0}, + {0, 2, 2, -2, 2, 91.3, -16, 0.1, 7, 0.0}, + {-1, 0, 0, 2, 1, 32.0, 16, 0.0, -8, 0.0}, + {0, 1, 0, 0, 1, 386.0, -15, 0.0, 9, 0.0}, + {1, 0, 0, -2, 1, -31.7, -13, 0.0, 7, 0.0}, + {0, -1, 0, 0, 1, -346.6, -12, 0.0, 6, 0.0}, + {2, 0, -2, 0, 0, -1095.2, 11, 0.0, 0, 0.0}, + {-1, 0, 2, 2, 1, 9.5, -10, 0.0, 5, 0.0}, + {1, 0, 2, 2, 2, 5.6, -8, 0.0, 3, 0.0}, + {0, -1, 2, 0, 2, 14.2, -7, 0.0, 3, 0.0}, + {0, 0, 2, 2, 1, 7.1, -7, 0.0, 3, 0.0}, + {1, 1, 0, -2, 0, -34.8, -7, 0.0, 0, 0.0}, + {0, 1, 2, 0, 2, 13.2, 7, 0.0, -3, 0.0}, + {-2, 0, 0, 2, 1, -199.8, -6, 0.0, 3, 0.0}, + {0, 0, 0, 2, 1, 14.8, -6, 0.0, 3, 0.0}, + {2, 0, 2, -2, 2, 12.8, 6, 0.0, -3, 0.0}, + {1, 0, 0, 2, 0, 9.6, 6, 0.0, 0, 0.0}, + {1, 0, 2, -2, 1, 23.9, 6, 0.0, -3, 0.0}, + {0, 0, 0, -2, 1, -14.7, -5, 0.0, 3, 0.0}, + {0, -1, 2, -2, 1, 346.6, -5, 0.0, 3, 0.0}, + {2, 0, 2, 0, 1, 6.9, -5, 0.0, 3, 0.0}, + {1, -1, 0, 0, 0, 29.8, 5, 0.0, 0, 0.0}, + {1, 0, 0, -1, 0, 411.8, -4, 0.0, 0, 0.0}, + {0, 0, 0, 1, 0, 29.5, -4, 0.0, 0, 0.0}, + {0, 1, 0, -2, 0, -15.4, -4, 0.0, 0, 0.0}, + {1, 0, -2, 0, 0, -26.9, 4, 0.0, 0, 0.0}, + {2, 0, 0, -2, 1, 212.3, 4, 0.0, -2, 0.0}, + {0, 1, 2, -2, 1, 119.6, 4, 0.0, -2, 0.0}, + {1, 1, 0, 0, 0, 25.6, -3, 0.0, 0, 0.0}, + {1, -1, 0, -1, 0, -3232.9, -3, 0.0, 0, 0.0}, + {-1, -1, 2, 2, 2, 9.8, -3, 0.0, 1, 0.0}, + {0, -1, 2, 2, 2, 7.2, -3, 0.0, 1, 0.0}, + {1, -1, 2, 0, 2, 9.4, -3, 0.0, 1, 0.0}, + {3, 0, 2, 0, 2, 5.5, -3, 0.0, 1, 0.0}, + {-2, 0, 2, 0, 2, 1615.7, -3, 0.0, 1, 0.0}, + {1, 0, 2, 0, 0, 9.1, 3, 0.0, 0, 0.0}, + {-1, 0, 2, 4, 2, 5.8, -2, 0.0, 1, 0.0}, + {1, 0, 0, 0, 2, 27.8, -2, 0.0, 1, 0.0}, + {-1, 0, 2, -2, 1, -32.6, -2, 0.0, 1, 0.0}, + {0, -2, 2, -2, 1, 6786.3, -2, 0.0, 1, 0.0}, + {-2, 0, 0, 0, 1, -13.7, -2, 0.0, 1, 0.0}, + {2, 0, 0, 0, 1, 13.8, 2, 0.0, -1, 0.0}, + {3, 0, 0, 0, 0, 9.2, 2, 0.0, 0, 0.0}, + {1, 1, 2, 0, 2, 8.9, 2, 0.0, -1, 0.0}, + {0, 0, 2, 1, 2, 9.3, 2, 0.0, -1, 0.0}, + {1, 0, 0, 2, 1, 9.6, -1, 0.0, 0, 0.0}, + {1, 0, 2, 2, 1, 5.6, -1, 0.0, 1, 0.0}, + {1, 1, 0, -2, 1, -34.7, -1, 0.0, 0, 0.0}, + {0, 1, 0, 2, 0, 14.2, -1, 0.0, 0, 0.0}, + {0, 1, 2, -2, 0, 117.5, -1, 0.0, 0, 0.0}, + {0, 1, -2, 2, 0, -329.8, -1, 0.0, 0, 0.0}, + {1, 0, -2, 2, 0, 23.8, -1, 0.0, 0, 0.0}, + {1, 0, -2, -2, 0, -9.5, -1, 0.0, 0, 0.0}, + {1, 0, 2, -2, 0, 32.8, -1, 0.0, 0, 0.0}, + {1, 0, 0, -4, 0, -10.1, -1, 0.0, 0, 0.0}, + {2, 0, 0, -4, 0, -15.9, -1, 0.0, 0, 0.0}, + {0, 0, 2, 4, 2, 4.8, -1, 0.0, 0, 0.0}, + {0, 0, 2, -1, 2, 25.4, -1, 0.0, 0, 0.0}, + {-2, 0, 2, 4, 2, 7.3, -1, 0.0, 1, 0.0}, + {2, 0, 2, 2, 2, 4.7, -1, 0.0, 0, 0.0}, + {0, -1, 2, 0, 1, 14.2, -1, 0.0, 0, 0.0}, + {0, 0, -2, 0, 1, -13.6, -1, 0.0, 0, 0.0}, + {0, 0, 4, -2, 2, 12.7, 1, 0.0, 0, 0.0}, + {0, 1, 0, 0, 2, 409.2, 1, 0.0, 0, 0.0}, + {1, 1, 2, -2, 2, 22.5, 1, 0.0, -1, 0.0}, + {3, 0, 2, -2, 2, 8.7, 1, 0.0, 0, 0.0}, + {-2, 0, 2, 2, 2, 14.6, 1, 0.0, -1, 0.0}, + {-1, 0, 0, 0, 2, -27.3, 1, 0.0, -1, 0.0}, + {0, 0, -2, 2, 1, -169.0, 1, 0.0, 0, 0.0}, + {0, 1, 2, 0, 1, 13.1, 1, 0.0, 0, 0.0}, + {-1, 0, 4, 0, 2, 9.1, 1, 0.0, 0, 0.0}, + {2, 1, 0, -2, 0, 131.7, 1, 0.0, 0, 0.0}, + {2, 0, 0, 2, 0, 7.1, 1, 0.0, 0, 0.0}, + {2, 0, 2, -2, 1, 12.8, 1, 0.0, -1, 0.0}, + {2, 0, -2, 0, 1, -943.2, 1, 0.0, 0, 0.0}, + {1, -1, 0, -2, 0, -29.3, 1, 0.0, 0, 0.0}, + {-1, 0, 0, 1, 1, -388.3, 1, 0.0, 0, 0.0}, + {-1, -1, 0, 2, 1, 35.0, 1, 0.0, 0, 0.0}, + {0, 1, 0, 1, 0, 27.3, 1, 0.0, 0, 0.0}}; + double ang; + int i, j; + + *dpsi = *deps = 0.0; + + for (i = 0; i < 106; i++) + { + ang = 0.0; + for (j = 0; j < 5; j++) + ang += nut[i][j] * f[j]; + *dpsi += (nut[i][6] + nut[i][7] * t) * sin(ang); + *deps += (nut[i][8] + nut[i][9] * t) * cos(ang); + } + *dpsi *= 1E-4 * AS2R; /* 0.1 mas -> rad */ + *deps *= 1E-4 * AS2R; +} +/* eci to ecef transformation matrix ------------------------------------------- + * compute eci to ecef transformation matrix + * args : gtime_t tutc I time in utc + * double *erpv I erp values {xp,yp,ut1_utc,lod} (rad,rad,s,s/d) + * double *U O eci to ecef transformation matrix (3 x 3) + * double *gmst IO greenwich mean sidereal time (rad) + * (NULL: no output) + * return : none + * note : see ref [3] chap 5 + * not thread-safe + *-----------------------------------------------------------------------------*/ +extern void eci2ecef(gtime_t tutc, const double *erpv, double *U, double *gmst) +{ + const double ep2000[] = {2000, 1, 1, 12, 0, 0}; + static gtime_t tutc_; + static double U_[9], gmst_; + gtime_t tgps; + double eps, ze, th, z, t, t2, t3, dpsi, deps, gast, f[5]; + double R1[9], R2[9], R3[9], R[9], W[9], N[9], P[9], NP[9]; + int i; + + trace(4, "eci2ecef: tutc=%s\n", time_str(tutc, 3)); + + if (fabs(timediff(tutc, tutc_)) < 0.01) + { /* read cache */ + for (i = 0; i < 9; i++) + U[i] = U_[i]; + if (gmst) + *gmst = gmst_; + return; + } + tutc_ = tutc; + + /* terrestrial time */ + tgps = utc2gpst(tutc_); + t = (timediff(tgps, epoch2time(ep2000)) + 19.0 + 32.184) / 86400.0 / 36525.0; + t2 = t * t; + t3 = t2 * t; + + /* astronomical arguments */ + ast_args(t, f); + + /* iau 1976 precession */ + ze = (2306.2181 * t + 0.30188 * t2 + 0.017998 * t3) * AS2R; + th = (2004.3109 * t - 0.42665 * t2 - 0.041833 * t3) * AS2R; + z = (2306.2181 * t + 1.09468 * t2 + 0.018203 * t3) * AS2R; + eps = (84381.448 - 46.8150 * t - 0.00059 * t2 + 0.001813 * t3) * AS2R; + Rz(-z, R1); + Ry(th, R2); + Rz(-ze, R3); + matmul("NN", 3, 3, 3, 1.0, R1, R2, 0.0, R); + matmul("NN", 3, 3, 3, 1.0, R, R3, 0.0, P); /* P=Rz(-z)*Ry(th)*Rz(-ze) */ + + /* iau 1980 nutation */ + nut_iau1980(t, f, &dpsi, &deps); + Rx(-eps - deps, R1); + Rz(-dpsi, R2); + Rx(eps, R3); + matmul("NN", 3, 3, 3, 1.0, R1, R2, 0.0, R); + matmul("NN", 3, 3, 3, 1.0, R, R3, 0.0, N); /* N=Rx(-eps)*Rz(-dspi)*Rx(eps) */ + + /* greenwich aparent sidereal time (rad) */ + gmst_ = utc2gmst(tutc_, erpv[2]); + gast = gmst_ + dpsi * cos(eps); + gast += (0.00264 * sin(f[4]) + 0.000063 * sin(2.0 * f[4])) * AS2R; + + /* eci to ecef transformation matrix */ + Ry(-erpv[0], R1); + Rx(-erpv[1], R2); + Rz(gast, R3); + matmul("NN", 3, 3, 3, 1.0, R1, R2, 0.0, W); + matmul("NN", 3, 3, 3, 1.0, W, R3, 0.0, R); /* W=Ry(-xp)*Rx(-yp) */ + matmul("NN", 3, 3, 3, 1.0, N, P, 0.0, NP); + matmul("NN", 3, 3, 3, 1.0, R, NP, 0.0, U_); /* U=W*Rz(gast)*N*P */ + + for (i = 0; i < 9; i++) + U[i] = U_[i]; + if (gmst) + *gmst = gmst_; + + trace(5, "gmst=%.12f gast=%.12f\n", gmst_, gast); + trace(5, "P=\n"); + tracemat(5, P, 3, 3, 15, 12); + trace(5, "N=\n"); + tracemat(5, N, 3, 3, 15, 12); + trace(5, "W=\n"); + tracemat(5, W, 3, 3, 15, 12); + trace(5, "U=\n"); + tracemat(5, U, 3, 3, 15, 12); +} +/* decode antenna parameter field --------------------------------------------*/ +static int decodef(char *p, int n, double *v) +{ + int i; + + for (i = 0; i < n; i++) + v[i] = 0.0; + for (i = 0, p = strtok(p, " "); p && i < n; p = strtok(NULL, " ")) + { + v[i++] = atof(p) * 1E-3; + } + return i; +} +/* add antenna parameter -----------------------------------------------------*/ +// static void addpcv(const pcv_t *pcv, pcvs_t *pcvs) +//{ +// pcv_t *pcvs_pcv; +// +// if (pcvs->nmax<=pcvs->n) { +// pcvs->nmax+=256; +// if (!(pcvs_pcv=(pcv_t *)realloc(pcvs->pcv,sizeof(pcv_t)*pcvs->nmax))) { +// trace(1,"addpcv: memory allocation error\n"); +// free(pcvs->pcv); pcvs->pcv=NULL; pcvs->n=pcvs->nmax=0; +// return; +// } +// pcvs->pcv=pcvs_pcv; +// } +// pcvs->pcv[pcvs->n++]=*pcv; +// } +/* read ngs antenna parameter file -------------------------------------------*/ +// static int readngspcv(const char *file, pcvs_t *pcvs) +//{ +// FILE *fp; +// static const pcv_t pcv0={0}; +// pcv_t pcv; +// double neu[3]; +// int n=0; +// char buff[256]; +// +// if (!(fp=fopen(file,"r"))) { +// trace(2,"ngs pcv file open error: %s\n",file); +// return 0; +// } +// while (fgets(buff,sizeof(buff),fp)) { +// +// if (strlen(buff)>=62&&buff[61]=='|') continue; +// +// if (buff[0]!=' ') n=0; /* start line */ +// if (++n==1) { +// pcv=pcv0; +// strncpy(pcv.type,buff,61); pcv.type[61]='\0'; +// } +// else if (n==2) { +// if (decodef(buff,3,neu)<3) continue; +// pcv.off[0][0]=neu[1]; +// pcv.off[0][1]=neu[0]; +// pcv.off[0][2]=neu[2]; +// } +// else if (n==3) decodef(buff,10,pcv.var[0]); +// else if (n==4) decodef(buff,9,pcv.var[0]+10); +// else if (n==5) { +// if (decodef(buff,3,neu)<3) continue;; +// pcv.off[1][0]=neu[1]; +// pcv.off[1][1]=neu[0]; +// pcv.off[1][2]=neu[2]; +// } +// else if (n==6) decodef(buff,10,pcv.var[1]); +// else if (n==7) { +// decodef(buff,9,pcv.var[1]+10); +// addpcv(&pcv,pcvs); +// } +// } +// fclose(fp); +// +// return 1; +// } +/* read antex file ----------------------------------------------------------*/ +// static int readantex(const char *file, pcvs_t *pcvs) +//{ +// FILE *fp; +// static const pcv_t pcv0={0}; +// pcv_t pcv; +// double neu[3]; +// int i,f,freq=0,state=0,freqs[]={1,2,5,0}; +// char buff[256]; +// +// trace(3,"readantex: file=%s\n",file); +// +// if (!(fp=fopen(file,"r"))) { +// trace(2,"antex pcv file open error: %s\n",file); +// return 0; +// } +// while (fgets(buff,sizeof(buff),fp)) { +// +// if (strlen(buff)<60||strstr(buff+60,"COMMENT")) continue; +// +// if (strstr(buff+60,"START OF ANTENNA")) { +// pcv=pcv0; +// state=1; +// } +// if (strstr(buff+60,"END OF ANTENNA")) { +// addpcv(&pcv,pcvs); +// state=0; +// } +// if (!state) continue; +// +// if (strstr(buff+60,"TYPE / SERIAL NO")) { +// strncpy(pcv.type,buff ,20); pcv.type[20]='\0'; +// strncpy(pcv.code,buff+20,20); pcv.code[20]='\0'; +// if (!strncmp(pcv.code+3," ",8)) { +// pcv.sat=satid2no(pcv.code); +// } +// } +// else if (strstr(buff+60,"VALID FROM")) { +// if (!str2time(buff,0,43,&pcv.ts)) continue; +// } +// else if (strstr(buff+60,"VALID UNTIL")) { +// if (!str2time(buff,0,43,&pcv.te)) continue; +// } +// else if (strstr(buff+60,"START OF FREQUENCY")) { +// if (!pcv.sat&&buff[3]!='G') continue; /* only read rec ant for GPS */ +// if (sscanf(buff+4,"%d",&f)<1) continue; +// for (i=0;freqs[i];i++) if (freqs[i]==f) break; +// if (freqs[i]) freq=i+1; +// /* for Galileo E5b: save to E2, not E7 */ +// if (satsys(pcv.sat,NULL)==SYS_GAL&&f==7) freq=2; +// } +// else if (strstr(buff+60,"END OF FREQUENCY")) { +// freq=0; +// } +// else if (strstr(buff+60,"NORTH / EAST / UP")) { +// if (freq<1||NFREQn;i++) { +// pcv=pcvs->pcv+i; +// trace(4,"sat=%2d type=%20s code=%s off=%8.4f %8.4f %8.4f %8.4f %8.4f %8.4f\n", +// pcv->sat,pcv->type,pcv->code,pcv->off[0][0],pcv->off[0][1], +// pcv->off[0][2],pcv->off[1][0],pcv->off[1][1],pcv->off[1][2]); +// } +// return stat; +// } +/* search antenna parameter ---------------------------------------------------- + * read satellite antenna phase center position + * args : int sat I satellite number (0: receiver antenna) + * char *type I antenna type for receiver antenna + * gtime_t time I time to search parameters + * pcvs_t *pcvs IO antenna parameters + * return : antenna parameter (NULL: no antenna) + *-----------------------------------------------------------------------------*/ +// extern pcv_t *searchpcv(int sat, const char *type, gtime_t time, +// const pcvs_t *pcvs) +//{ +// pcv_t *pcv; +// char buff[MAXANT],*types[2],*p; +// int i,j,n=0; +// +// trace(4,"searchpcv: sat=%2d type=%s\n",sat,type); +// +// if (sat) { /* search satellite antenna */ +// for (i=0;in;i++) { +// pcv=pcvs->pcv+i; +// if (pcv->sat!=sat) continue; +// if (pcv->ts.time!=0&&timediff(pcv->ts,time)>0.0) continue; +// if (pcv->te.time!=0&&timediff(pcv->te,time)<0.0) continue; +// return pcv; +// } +// } +// else { +// strcpy(buff,type); +// for (p=strtok(buff," ");p&&n<2;p=strtok(NULL," ")) types[n++]=p; +// if (n<=0) return NULL; +// +// /* search receiver antenna with radome at first */ +// for (i=0;in;i++) { +// pcv=pcvs->pcv+i; +// for (j=0;jtype,types[j])) break; +// if (j>=n) return pcv; +// } +// /* search receiver antenna without radome */ +// for (i=0;in;i++) { +// pcv=pcvs->pcv+i; +// if (strstr(pcv->type,types[0])!=pcv->type) continue; +// +// trace(2,"pcv without radome is used type=%s\n",type); +// return pcv; +// } +// } +// return NULL; +// } +/* read station positions ------------------------------------------------------ + * read positions from station position file + * args : char *file I station position file containing + * lat(deg) lon(deg) height(m) name in a line + * char *rcvs I station name + * double *pos O station position {lat,lon,h} (rad/m) + * (all 0 if search error) + * return : none + *-----------------------------------------------------------------------------*/ +extern void readpos(const char *file, const char *rcv, double *pos) +{ + static double poss[2048][3]; + static char stas[2048][16]; + FILE *fp; + int i, j, len, np = 0; + char buff[256], str[256]; + + trace(3, "readpos: file=%s\n", file); + + if (!(fp = fopen(file, "r"))) + { + fprintf(stderr, "reference position file open error : %s\n", file); + return; + } + while (np < 2048 && fgets(buff, sizeof(buff), fp)) + { + if (buff[0] == '%' || buff[0] == '#') + continue; + if (sscanf(buff, "%lf %lf %lf %s", &poss[np][0], &poss[np][1], &poss[np][2], + str) < 4) + continue; + sprintf(stas[np++], "%.15s", str); + } + fclose(fp); + len = (int)strlen(rcv); + for (i = 0; i < np; i++) + { + if (strncmp(stas[i], rcv, len)) + continue; + for (j = 0; j < 3; j++) + pos[j] = poss[i][j]; + pos[0] *= D2R; + pos[1] *= D2R; + return; + } + pos[0] = pos[1] = pos[2] = 0.0; +} +/* read blq record -----------------------------------------------------------*/ +static int readblqrecord(FILE *fp, double *odisp) +{ + double v[11]; + char buff[256]; + int i, n = 0; + + while (fgets(buff, sizeof(buff), fp)) + { + if (!strncmp(buff, "$$", 2)) + continue; + if (sscanf(buff, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", + v, v + 1, v + 2, v + 3, v + 4, v + 5, v + 6, v + 7, v + 8, v + 9, v + 10) < 11) + continue; + for (i = 0; i < 11; i++) + odisp[n + i * 6] = v[i]; + if (++n == 6) + return 1; + } + return 0; +} +/* read blq ocean tide loading parameters -------------------------------------- + * read blq ocean tide loading parameters + * args : char *file I BLQ ocean tide loading parameter file + * char *sta I station name + * double *odisp O ocean tide loading parameters + * return : status (1:ok,0:file open error) + *-----------------------------------------------------------------------------*/ +extern int readblq(const char *file, const char *sta, double *odisp) +{ + FILE *fp; + char buff[256], staname[32] = "", name[32], *p; + + /* station name to upper case */ + (void)sscanf(sta, "%16s", staname); + for (p = staname; (*p = (char)toupper((int)(*p))); p++) + ; + + if (!(fp = fopen(file, "r"))) + { + trace(2, "blq file open error: file=%s\n", file); + return 0; + } + while (fgets(buff, sizeof(buff), fp)) + { + if (!strncmp(buff, "$$", 2) || strlen(buff) < 2) + continue; + + if (sscanf(buff + 2, "%16s", name) < 1) + continue; + for (p = name; (*p = (char)toupper((int)(*p))); p++) + ; + if (strcmp(name, staname)) + continue; + + /* read blq record */ + if (readblqrecord(fp, odisp)) + { + fclose(fp); + return 1; + } + } + fclose(fp); + trace(2, "no otl parameters: sta=%s file=%s\n", sta, file); + return 0; +} +/* read earth rotation parameters ---------------------------------------------- + * read earth rotation parameters + * args : char *file I IGS ERP file (IGS ERP ver.2) + * erp_t *erp O earth rotation parameters + * return : status (1:ok,0:file open error) + *-----------------------------------------------------------------------------*/ +extern int readerp(const char *file, erp_t *erp) +{ + FILE *fp; + erpd_t *erp_data; + double v[14] = {0}; + char buff[256]; + + trace(3, "readerp: file=%s\n", file); + + if (!(fp = fopen(file, "r"))) + { + trace(2, "erp file open error: file=%s\n", file); + return 0; + } + while (fgets(buff, sizeof(buff), fp)) + { + if (sscanf(buff, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", + v, v + 1, v + 2, v + 3, v + 4, v + 5, v + 6, v + 7, v + 8, v + 9, v + 10, v + 11, v + 12, v + 13) < 5) + { + continue; + } + if (erp->n >= erp->nmax) + { + erp->nmax = erp->nmax <= 0 ? 128 : erp->nmax * 2; + erp_data = (erpd_t *)realloc(erp->data, sizeof(erpd_t) * erp->nmax); + if (!erp_data) + { + free(erp->data); + erp->data = NULL; + erp->n = erp->nmax = 0; + fclose(fp); + return 0; + } + erp->data = erp_data; + } + erp->data[erp->n].mjd = v[0]; + erp->data[erp->n].xp = v[1] * 1E-6 * AS2R; + erp->data[erp->n].yp = v[2] * 1E-6 * AS2R; + erp->data[erp->n].ut1_utc = v[3] * 1E-7; + erp->data[erp->n].lod = v[4] * 1E-7; + erp->data[erp->n].xpr = v[12] * 1E-6 * AS2R; + erp->data[erp->n++].ypr = v[13] * 1E-6 * AS2R; + } + fclose(fp); + return 1; +} +/* get earth rotation parameter values ----------------------------------------- +* get earth rotation parameter values +* args : erp_t *erp I earth rotation parameters +* gtime_t time I time (gpst) +* double *erpv O erp values {xp,yp,ut1_utc,lod} (rad,rad,s,s/d) +* return : status (1:ok,0:error) +* ȡERPתֵ +* 3 +erp_t *erp I earth rotation parameters +gtime_t time I time (gpst) +double *erpv O erp values {xp,yp,ut1_utc,lod} (rad,rad,s,s/d) +: +int O (1:ok,0:error) +*-----------------------------------------------------------------------------*/ +extern int geterp(const erp_t *erp, gtime_t time, double *erpv) +{ + const double ep[] = {2000, 1, 1, 12, 0, 0}; + double mjd, day, a; + int i, j, k; + + trace(4, "geterp:\n"); + + if (erp->n <= 0) + return 0; + // 1㵱ǰʱERPʱIJֵ + mjd = 51544.5 + (timediff(gpst2utc(time), epoch2time(ep))) / 86400.0; + + // 2ǰʱERPʱ䣬ʱ + if (mjd <= erp->data[0].mjd) + { + day = mjd - erp->data[0].mjd; + erpv[0] = erp->data[0].xp + erp->data[0].xpr * day; + erpv[1] = erp->data[0].yp + erp->data[0].ypr * day; + erpv[2] = erp->data[0].ut1_utc - erp->data[0].lod * day; + erpv[3] = erp->data[0].lod; + return 1; + } + // 3ǰʱERPʱ䣬ʱ + if (mjd >= erp->data[erp->n - 1].mjd) + { + day = mjd - erp->data[erp->n - 1].mjd; + erpv[0] = erp->data[erp->n - 1].xp + erp->data[erp->n - 1].xpr * day; + erpv[1] = erp->data[erp->n - 1].yp + erp->data[erp->n - 1].ypr * day; + erpv[2] = erp->data[erp->n - 1].ut1_utc - erp->data[erp->n - 1].lod * day; + erpv[3] = erp->data[erp->n - 1].lod; + return 1; + } + // 4ǰʱERPʱ֮䣬ҵӽʱ䣬Ȼòֵ + for (j = 0, k = erp->n - 1; j < k - 1;) + { + i = (j + k) / 2; + if (mjd < erp->data[i].mjd) + k = i; + else + j = i; + } + if (erp->data[j].mjd == erp->data[j + 1].mjd) + { + a = 0.5; + } + else + { + a = (mjd - erp->data[j].mjd) / (erp->data[j + 1].mjd - erp->data[j].mjd); + } + erpv[0] = (1.0 - a) * erp->data[j].xp + a * erp->data[j + 1].xp; + erpv[1] = (1.0 - a) * erp->data[j].yp + a * erp->data[j + 1].yp; + erpv[2] = (1.0 - a) * erp->data[j].ut1_utc + a * erp->data[j + 1].ut1_utc; + erpv[3] = (1.0 - a) * erp->data[j].lod + a * erp->data[j + 1].lod; + return 1; +} +/* compare ephemeris ---------------------------------------------------------*/ +static int cmpeph(const void *p1, const void *p2) +{ + eph_t *q1 = (eph_t *)p1, *q2 = (eph_t *)p2; + return q1->ttr.time != q2->ttr.time ? (int)(q1->ttr.time - q2->ttr.time) : (q1->toe.time != q2->toe.time ? (int)(q1->toe.time - q2->toe.time) : q1->sat - q2->sat); +} +/* sort and unique ephemeris -------------------------------------------------*/ +static void uniqeph(nav_t *nav) +{ + eph_t *nav_eph; + int i, j; + + trace(3, "uniqeph: n=%d\n", nav->n); + + if (nav->n <= 0) + return; + + qsort(nav->eph, nav->n, sizeof(eph_t), cmpeph); + + for (i = 1, j = 0; i < nav->n; i++) + { + if (nav->eph[i].sat != nav->eph[j].sat || + nav->eph[i].iode != nav->eph[j].iode) + { + nav->eph[++j] = nav->eph[i]; + } + } + nav->n = j + 1; + + if (!(nav_eph = (eph_t *)realloc(nav->eph, sizeof(eph_t) * nav->n))) + { + trace(1, "uniqeph malloc error n=%d\n", nav->n); + free(nav->eph); + nav->eph = NULL; + nav->n = nav->nmax = 0; + return; + } + nav->eph = nav_eph; + nav->nmax = nav->n; + + trace(4, "uniqeph: n=%d\n", nav->n); +} +/* compare glonass ephemeris -------------------------------------------------*/ +static int cmpgeph(const void *p1, const void *p2) +{ + geph_t *q1 = (geph_t *)p1, *q2 = (geph_t *)p2; + return q1->tof.time != q2->tof.time ? (int)(q1->tof.time - q2->tof.time) : (q1->toe.time != q2->toe.time ? (int)(q1->toe.time - q2->toe.time) : q1->sat - q2->sat); +} +/* sort and unique glonass ephemeris -----------------------------------------*/ +static void uniqgeph(nav_t *nav) +{ + geph_t *nav_geph; + int i, j; + + trace(3, "uniqgeph: ng=%d\n", nav->ng); + + if (nav->ng <= 0) + return; + + qsort(nav->geph, nav->ng, sizeof(geph_t), cmpgeph); + + for (i = j = 0; i < nav->ng; i++) + { + if (nav->geph[i].sat != nav->geph[j].sat || + nav->geph[i].toe.time != nav->geph[j].toe.time || + nav->geph[i].svh != nav->geph[j].svh) + { + nav->geph[++j] = nav->geph[i]; + } + } + nav->ng = j + 1; + + if (!(nav_geph = (geph_t *)realloc(nav->geph, sizeof(geph_t) * nav->ng))) + { + trace(1, "uniqgeph malloc error ng=%d\n", nav->ng); + free(nav->geph); + nav->geph = NULL; + nav->ng = nav->ngmax = 0; + return; + } + nav->geph = nav_geph; + nav->ngmax = nav->ng; + + trace(4, "uniqgeph: ng=%d\n", nav->ng); +} +/* compare sbas ephemeris ----------------------------------------------------*/ +// static int cmpseph(const void *p1, const void *p2) +//{ +// seph_t *q1=(seph_t *)p1,*q2=(seph_t *)p2; +// return q1->tof.time!=q2->tof.time?(int)(q1->tof.time-q2->tof.time): +// (q1->t0.time!=q2->t0.time?(int)(q1->t0.time-q2->t0.time): +// q1->sat-q2->sat); +// } +/* sort and unique sbas ephemeris --------------------------------------------*/ +// static void uniqseph(nav_t *nav) +//{ +// seph_t *nav_seph; +// int i,j; +// +// trace(3,"uniqseph: ns=%d\n",nav->ns); +// +// if (nav->ns<=0) return; +// +// qsort(nav->seph,nav->ns,sizeof(seph_t),cmpseph); +// +// for (i=j=0;ins;i++) { +// if (nav->seph[i].sat!=nav->seph[j].sat|| +// nav->seph[i].t0.time!=nav->seph[j].t0.time) { +// nav->seph[++j]=nav->seph[i]; +// } +// } +// nav->ns=j+1; +// +// if (!(nav_seph=(seph_t *)realloc(nav->seph,sizeof(seph_t)*nav->ns))) { +// trace(1,"uniqseph malloc error ns=%d\n",nav->ns); +// free(nav->seph); nav->seph=NULL; nav->ns=nav->nsmax=0; +// return; +// } +// nav->seph=nav_seph; +// nav->nsmax=nav->ns; +// +// trace(4,"uniqseph: ns=%d\n",nav->ns); +// } +/* unique ephemerides ---------------------------------------------------------- + * unique ephemerides in navigation data and update carrier wave length + * args : nav_t *nav IO navigation data + * return : number of epochs + *-----------------------------------------------------------------------------*/ +extern void uniqnav(nav_t *nav) +{ + trace(3, "uniqnav: neph=%d ngeph=%d nseph=%d\n", nav->n, nav->ng, nav->ns); + + /* unique ephemeris */ + uniqeph(nav); + uniqgeph(nav); + // uniqseph(nav); +} +/* compare observation data -------------------------------------------------*/ +static int cmpobs(const void *p1, const void *p2) +{ + obsd_t *q1 = (obsd_t *)p1, *q2 = (obsd_t *)p2; + double tt = timediff(q1->time, q2->time); + if (fabs(tt) > DTTOL) + return tt < 0 ? -1 : 1; + if (q1->rcv != q2->rcv) + return (int)q1->rcv - (int)q2->rcv; + return (int)q1->sat - (int)q2->sat; +} +/* sort and unique observation data -------------------------------------------- + * sort and unique observation data by time, rcv, sat + * args : obs_t *obs IO observation data + * return : number of epochs + *-----------------------------------------------------------------------------*/ +extern int sortobs(obs_t *obs) +{ + int i, j, n; + + trace(3, "sortobs: nobs=%d\n", obs->n); + + if (obs->n <= 0) + return 0; + + qsort(obs->data, obs->n, sizeof(obsd_t), cmpobs); + + /* delete duplicated data */ + for (i = j = 0; i < obs->n; i++) + { + if (obs->data[i].sat != obs->data[j].sat || + obs->data[i].rcv != obs->data[j].rcv || + timediff(obs->data[i].time, obs->data[j].time) != 0.0) + { + obs->data[++j] = obs->data[i]; + } + } + obs->n = j + 1; + + for (i = n = 0; i < obs->n; i = j, n++) + { + for (j = i + 1; j < obs->n; j++) + { + if (timediff(obs->data[j].time, obs->data[i].time) > DTTOL) + break; + } + } + return n; +} +/* screen by time -------------------------------------------------------------- + * screening by time start, time end, and time interval + * args : gtime_t time I time + * gtime_t ts I time start (ts.time==0:no screening by ts) + * gtime_t te I time end (te.time==0:no screening by te) + * double tint I time interval (s) (0.0:no screen by tint) + * return : 1:on condition, 0:not on condition + *-----------------------------------------------------------------------------*/ +extern int screent(gtime_t time, gtime_t ts, gtime_t te, double tint) +{ + return (tint <= 0.0 || fmod(time2gpst(time, NULL) + DTTOL, tint) <= DTTOL * 2.0) && + (ts.time == 0 || timediff(time, ts) >= -DTTOL) && + (te.time == 0 || timediff(time, te) < DTTOL); +} +/* read/save navigation data --------------------------------------------------- + * save or load navigation data + * args : char file I file path + * nav_t nav O/I navigation data + * return : status (1:ok,0:no file) + *-----------------------------------------------------------------------------*/ +extern int readnav(const char *file, nav_t *nav) +{ + FILE *fp; + eph_t eph0 = {0}; + geph_t geph0 = {0}; + char buff[4096], *p; + long toe_time, tof_time, toc_time, ttr_time; + int i, sat, prn; + + trace(3, "loadnav: file=%s\n", file); + + if (!(fp = fopen(file, "r"))) + return 0; + + while (fgets(buff, sizeof(buff), fp)) + { + if (!strncmp(buff, "IONUTC", 6)) + { + for (i = 0; i < 8; i++) + nav->ion_gps[i] = 0.0; + for (i = 0; i < 8; i++) + nav->utc_gps[i] = 0.0; + (void)sscanf(buff, "IONUTC,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf", + &nav->ion_gps[0], &nav->ion_gps[1], &nav->ion_gps[2], &nav->ion_gps[3], + &nav->ion_gps[4], &nav->ion_gps[5], &nav->ion_gps[6], &nav->ion_gps[7], + &nav->utc_gps[0], &nav->utc_gps[1], &nav->utc_gps[2], &nav->utc_gps[3], + &nav->utc_gps[4]); + continue; + } + if ((p = strchr(buff, ','))) + *p = '\0'; + else + continue; + if (!(sat = satid2no(buff))) + continue; + if (satsys(sat, &prn) == SYS_GLO) + { + nav->geph[prn - 1] = geph0; + nav->geph[prn - 1].sat = sat; + toe_time = tof_time = 0; + (void)sscanf(p + 1, "%d,%d,%d,%d,%d,%ld,%ld,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf," + "%lf,%lf,%lf,%lf", + &nav->geph[prn - 1].iode, &nav->geph[prn - 1].frq, &nav->geph[prn - 1].svh, + &nav->geph[prn - 1].sva, &nav->geph[prn - 1].age, + &toe_time, &tof_time, + &nav->geph[prn - 1].pos[0], &nav->geph[prn - 1].pos[1], &nav->geph[prn - 1].pos[2], + &nav->geph[prn - 1].vel[0], &nav->geph[prn - 1].vel[1], &nav->geph[prn - 1].vel[2], + &nav->geph[prn - 1].acc[0], &nav->geph[prn - 1].acc[1], &nav->geph[prn - 1].acc[2], + &nav->geph[prn - 1].taun, &nav->geph[prn - 1].gamn, &nav->geph[prn - 1].dtaun); + nav->geph[prn - 1].toe.time = toe_time; + nav->geph[prn - 1].tof.time = tof_time; + } + else + { + nav->eph[sat - 1] = eph0; + nav->eph[sat - 1].sat = sat; + toe_time = toc_time = ttr_time = 0; + (void)sscanf(p + 1, "%d,%d,%d,%d,%ld,%ld,%ld,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf," + "%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%d,%d", + &nav->eph[sat - 1].iode, &nav->eph[sat - 1].iodc, &nav->eph[sat - 1].sva, + &nav->eph[sat - 1].svh, + &toe_time, &toc_time, &ttr_time, + &nav->eph[sat - 1].A, &nav->eph[sat - 1].e, &nav->eph[sat - 1].i0, + &nav->eph[sat - 1].OMG0, &nav->eph[sat - 1].omg, &nav->eph[sat - 1].M0, + &nav->eph[sat - 1].deln, &nav->eph[sat - 1].OMGd, &nav->eph[sat - 1].idot, + &nav->eph[sat - 1].crc, &nav->eph[sat - 1].crs, &nav->eph[sat - 1].cuc, + &nav->eph[sat - 1].cus, &nav->eph[sat - 1].cic, &nav->eph[sat - 1].cis, + &nav->eph[sat - 1].toes, &nav->eph[sat - 1].fit, &nav->eph[sat - 1].f0, + &nav->eph[sat - 1].f1, &nav->eph[sat - 1].f2, &nav->eph[sat - 1].tgd[0], + &nav->eph[sat - 1].code, &nav->eph[sat - 1].flag); + nav->eph[sat - 1].toe.time = toe_time; + nav->eph[sat - 1].toc.time = toc_time; + nav->eph[sat - 1].ttr.time = ttr_time; + } + } + fclose(fp); + return 1; +} +extern int savenav(const char *file, const nav_t *nav) +{ + FILE *fp; + int i; + char id[32]; + + trace(3, "savenav: file=%s\n", file); + + if (!(fp = fopen(file, "w"))) + return 0; + + for (i = 0; i < MAXSAT; i++) + { + if (nav->eph[i].ttr.time == 0) + continue; + satno2id(nav->eph[i].sat, id); + fprintf(fp, "%s,%d,%d,%d,%d,%d,%d,%d,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E," + "%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E," + "%.14E,%.14E,%.14E,%.14E,%.14E,%d,%d\n", + id, nav->eph[i].iode, nav->eph[i].iodc, nav->eph[i].sva, + nav->eph[i].svh, (int)nav->eph[i].toe.time, + (int)nav->eph[i].toc.time, (int)nav->eph[i].ttr.time, + nav->eph[i].A, nav->eph[i].e, nav->eph[i].i0, nav->eph[i].OMG0, + nav->eph[i].omg, nav->eph[i].M0, nav->eph[i].deln, nav->eph[i].OMGd, + nav->eph[i].idot, nav->eph[i].crc, nav->eph[i].crs, nav->eph[i].cuc, + nav->eph[i].cus, nav->eph[i].cic, nav->eph[i].cis, nav->eph[i].toes, + nav->eph[i].fit, nav->eph[i].f0, nav->eph[i].f1, nav->eph[i].f2, + nav->eph[i].tgd[0], nav->eph[i].code, nav->eph[i].flag); + } + for (i = 0; i < MAXPRNGLO; i++) + { + if (nav->geph[i].tof.time == 0) + continue; + satno2id(nav->geph[i].sat, id); + fprintf(fp, "%s,%d,%d,%d,%d,%d,%d,%d,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E," + "%.14E,%.14E,%.14E,%.14E,%.14E,%.14E\n", + id, nav->geph[i].iode, nav->geph[i].frq, nav->geph[i].svh, + nav->geph[i].sva, nav->geph[i].age, (int)nav->geph[i].toe.time, + (int)nav->geph[i].tof.time, + nav->geph[i].pos[0], nav->geph[i].pos[1], nav->geph[i].pos[2], + nav->geph[i].vel[0], nav->geph[i].vel[1], nav->geph[i].vel[2], + nav->geph[i].acc[0], nav->geph[i].acc[1], nav->geph[i].acc[2], + nav->geph[i].taun, nav->geph[i].gamn, nav->geph[i].dtaun); + } + /*fprintf(fp,"IONUTC,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E,%.14E," + "%.14E,%.14E,%.14E,%.0f", + nav->ion_gps[0],nav->ion_gps[1],nav->ion_gps[2],nav->ion_gps[3], + nav->ion_gps[4],nav->ion_gps[5],nav->ion_gps[6],nav->ion_gps[7], + nav->utc_gps[0],nav->utc_gps[1],nav->utc_gps[2],nav->utc_gps[3], + nav->utc_gps[4]);*/ + + fclose(fp); + return 1; +} +/* free observation data ------------------------------------------------------- + * free memory for observation data + * args : obs_t *obs IO observation data + * return : none + *-----------------------------------------------------------------------------*/ +extern void freeobs(obs_t *obs) +{ + free(obs->data); + obs->data = NULL; + obs->n = obs->nmax = 0; +} +/* free navigation data --------------------------------------------------------- + * free memory for navigation data + * args : nav_t *nav IO navigation data + * int opt I option (or of followings) + * (0x01: gps/qzs ephmeris, 0x02: glonass ephemeris, + * 0x04: sbas ephemeris, 0x08: precise ephemeris, + * 0x10: precise clock 0x20: almanac, + * 0x40: tec data) + * return : none + *-----------------------------------------------------------------------------*/ +extern void freenav(nav_t *nav, int opt) +{ + if (opt & 0x01) + { + free(nav->eph); + nav->eph = NULL; + nav->n = nav->nmax = 0; + } + if (opt & 0x02) + { + free(nav->geph); + nav->geph = NULL; + nav->ng = nav->ngmax = 0; + } + // if (opt&0x04) {free(nav->seph); nav->seph=NULL; nav->ns=nav->nsmax=0;} + // if (opt&0x08) {free(nav->peph); nav->peph=NULL; nav->ne=nav->nemax=0;} + // if (opt&0x10) {free(nav->pclk); nav->pclk=NULL; nav->nc=nav->ncmax=0;} + // if (opt&0x20) {free(nav->alm ); nav->alm =NULL; nav->na=nav->namax=0;} + // if (opt&0x40) {free(nav->tec ); nav->tec =NULL; nav->nt=nav->ntmax=0;} +} +/* debug trace functions -----------------------------------------------------*/ +#ifdef TRACE + +static FILE *fp_trace = NULL; /* file pointer of trace */ +static char file_trace[1024]; /* trace file */ +static int level_trace = 0; /* level of trace */ +static uint32_t tick_trace = 0; /* tick time at traceopen (ms) */ +static gtime_t time_trace = {0}; /* time at traceopen */ +static lock_t lock_trace; /* lock for trace */ + +static void traceswap(void) +{ + gtime_t time = utc2gpst(timeget()); + char path[1024]; + + lock(&lock_trace); + + if ((int)(time2gpst(time, NULL) / INT_SWAP_TRAC) == + (int)(time2gpst(time_trace, NULL) / INT_SWAP_TRAC)) + { + unlock(&lock_trace); + return; + } + time_trace = time; + + if (!reppath(file_trace, path, time, "", "")) + { + unlock(&lock_trace); + return; + } + if (fp_trace) + fclose(fp_trace); + + if (!(fp_trace = fopen(path, "w"))) + { + fp_trace = stderr; + } + unlock(&lock_trace); +} +extern void traceopen(const char *file) +{ + gtime_t time = utc2gpst(timeget()); + char path[1024]; + + reppath(file, path, time, "", ""); + if (!*path || !(fp_trace = fopen(path, "w"))) + fp_trace = stderr; + strcpy(file_trace, file); + tick_trace = tickget(); + time_trace = time; + initlock(&lock_trace); +} +extern void traceclose(void) +{ + if (fp_trace && fp_trace != stderr) + fclose(fp_trace); + fp_trace = NULL; + file_trace[0] = '\0'; +} +extern void tracelevel(int level) +{ + level_trace = level; +} +extern int gettracelevel(void) +{ + return level_trace; +} +extern void trace(int level, const char *format, ...) +{ + va_list ap; + + /* print error message to stderr */ + if (level <= 1) + { + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + } + if (!fp_trace || level > level_trace) + return; + traceswap(); + fprintf(fp_trace, "%d ", level); + va_start(ap, format); + vfprintf(fp_trace, format, ap); + va_end(ap); + fflush(fp_trace); +} +extern void tracet(int level, const char *format, ...) +{ + va_list ap; + + if (!fp_trace || level > level_trace) + return; + traceswap(); + fprintf(fp_trace, "%d %9.3f: ", level, (tickget() - tick_trace) / 1000.0); + va_start(ap, format); + vfprintf(fp_trace, format, ap); + va_end(ap); + fflush(fp_trace); +} +extern void tracemat(int level, const double *A, int n, int m, int p, int q) +{ + if (!fp_trace || level > level_trace) + return; + matfprint(A, n, m, p, q, fp_trace); + fflush(fp_trace); +} +extern void traceobs(int level, const obsd_t *obs, int n) +{ + char str[64], id[16]; + int i; + + if (!fp_trace || level > level_trace) + return; + for (i = 0; i < n; i++) + { + time2str(obs[i].time, str, 3); + satno2id(obs[i].sat, id); + fprintf(fp_trace, " (%2d) %s %-3s rcv%d %13.3f %13.3f %13.3f %13.3f %d %d %d %d %x %x %3.1f %3.1f\n", + i + 1, str, id, obs[i].rcv, obs[i].L[0], obs[i].L[1], obs[i].P[0], + obs[i].P[1], obs[i].LLI[0], obs[i].LLI[1], obs[i].code[0], + obs[i].code[1], obs[i].Lstd[0], obs[i].Pstd[0], obs[i].SNR[0] * SNR_UNIT, obs[i].SNR[1] * SNR_UNIT); + } + fflush(fp_trace); +} +extern void tracenav(int level, const nav_t *nav) +{ + char s1[64], s2[64], id[16]; + int i; + + if (!fp_trace || level > level_trace) + return; + for (i = 0; i < nav->n; i++) + { + time2str(nav->eph[i].toe, s1, 0); + time2str(nav->eph[i].ttr, s2, 0); + satno2id(nav->eph[i].sat, id); + fprintf(fp_trace, "(%3d) %-3s : %s %s %3d %3d %02x\n", i + 1, + id, s1, s2, nav->eph[i].iode, nav->eph[i].iodc, nav->eph[i].svh); + } + fprintf(fp_trace, "(ion) %9.4e %9.4e %9.4e %9.4e\n", nav->ion_gps[0], + nav->ion_gps[1], nav->ion_gps[2], nav->ion_gps[3]); + fprintf(fp_trace, "(ion) %9.4e %9.4e %9.4e %9.4e\n", nav->ion_gps[4], + nav->ion_gps[5], nav->ion_gps[6], nav->ion_gps[7]); + // fprintf(fp_trace,"(ion) %9.4e %9.4e %9.4e %9.4e\n",nav->ion_gal[0], + // nav->ion_gal[1],nav->ion_gal[2],nav->ion_gal[3]); +} +extern void tracegnav(int level, const nav_t *nav) +{ + char s1[64], s2[64], id[16]; + int i; + + if (!fp_trace || level > level_trace) + return; + for (i = 0; i < nav->ng; i++) + { + time2str(nav->geph[i].toe, s1, 0); + time2str(nav->geph[i].tof, s2, 0); + satno2id(nav->geph[i].sat, id); + fprintf(fp_trace, "(%3d) %-3s : %s %s %2d %2d %8.3f\n", i + 1, + id, s1, s2, nav->geph[i].frq, nav->geph[i].svh, nav->geph[i].taun * 1E6); + } +} +extern void tracehnav(int level, const nav_t *nav) +{ + // char s1[64],s2[64],id[16]; + // int i; + // + // if (!fp_trace||level>level_trace) return; + // for (i=0;ins;i++) { + // time2str(nav->seph[i].t0,s1,0); + // time2str(nav->seph[i].tof,s2,0); + // satno2id(nav->seph[i].sat,id); + // fprintf(fp_trace,"(%3d) %-3s : %s %s %2d %2d\n",i+1, + // id,s1,s2,nav->seph[i].svh,nav->seph[i].sva); + // } +} +extern void tracepeph(int level, const nav_t *nav) +{ + // char s[64],id[16]; + // int i,j; + // + // if (!fp_trace||level>level_trace) return; + // + // for (i=0;ine;i++) { + // time2str(nav->peph[i].time,s,0); + // for (j=0;jpeph[i].index,id, + // nav->peph[i].pos[j][0],nav->peph[i].pos[j][1], + // nav->peph[i].pos[j][2],nav->peph[i].pos[j][3]*1E9, + // nav->peph[i].std[j][0],nav->peph[i].std[j][1], + // nav->peph[i].std[j][2],nav->peph[i].std[j][3]*1E9); + // } + // } +} +extern void tracepclk(int level, const nav_t *nav) +{ + // char s[64],id[16]; + // int i,j; + // + // if (!fp_trace||level>level_trace) return; + // + // for (i=0;inc;i++) { + // time2str(nav->pclk[i].time,s,0); + // for (j=0;jpclk[i].index,id, + // nav->pclk[i].clk[j][0]*1E9,nav->pclk[i].std[j][0]*1E9); + // } + // } +} +extern void traceb(int level, const uint8_t *p, int n) +{ + int i; + if (!fp_trace || level > level_trace) + return; + for (i = 0; i < n; i++) + fprintf(fp_trace, "%02X%s", *p++, i % 8 == 7 ? " " : ""); + fprintf(fp_trace, "\n"); +} +#else +extern void traceopen(const char *file) +{ +} +extern void traceclose(void) {} +extern void tracelevel(int level) {} +extern void trace(int level, const char *format, ...) {} +extern void tracet(int level, const char *format, ...) {} +extern void tracemat(int level, const double *A, int n, int m, int p, int q) {} +extern void traceobs(int level, const obsd_t *obs, int n) {} +extern void tracenav(int level, const nav_t *nav) {} +extern void tracegnav(int level, const nav_t *nav) {} +extern void tracehnav(int level, const nav_t *nav) {} +extern void tracepeph(int level, const nav_t *nav) {} +extern void tracepclk(int level, const nav_t *nav) {} +extern void traceb(int level, const uint8_t *p, int n) {} + +#endif /* TRACE */ + +/* execute command ------------------------------------------------------------- + * execute command line by operating system shell + * args : char *cmd I command line + * return : execution status (0:ok,0>:error) + *-----------------------------------------------------------------------------*/ +extern int execcmd(const char *cmd) +{ +#ifdef WIN32 + PROCESS_INFORMATION info; + STARTUPINFO si = {0}; + DWORD stat; + char cmds[1024]; + + trace(3, "execcmd: cmd=%s\n", cmd); + + si.cb = sizeof(si); + sprintf(cmds, "cmd /c %s", cmd); + if (!CreateProcess(NULL, (LPTSTR)cmds, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, + NULL, &si, &info)) + return -1; + WaitForSingleObject(info.hProcess, INFINITE); + if (!GetExitCodeProcess(info.hProcess, &stat)) + stat = -1; + CloseHandle(info.hProcess); + CloseHandle(info.hThread); + return (int)stat; +#else + trace(3, "execcmd: cmd=%s\n", cmd); + + return system(cmd); +#endif +} + +/* replace string ------------------------------------------------------------*/ +static int repstr(char *str, const char *pat, const char *rep) +{ + int len = (int)strlen(pat); + char buff[1024] = {'\0'}, *p, *q, *r; + + for (p = str, r = buff; *p; p = q + len) + { + if (!(q = strstr(p, pat))) + break; + strncpy(r, p, q - p); + r += q - p; + r += sprintf(r, "%s", rep); + } + if (p <= str) + return 0; + strcpy(r, p); + strcpy(str, buff); + return 1; +} +/* replace keywords in file path ----------------------------------------------- + * replace keywords in file path with date, time, rover and base station id + * args : char *path I file path (see below) + * char *rpath O file path in which keywords replaced (see below) + * gtime_t time I time (gpst) (time.time==0: not replaced) + * char *rov I rover id string ("": not replaced) + * char *base I base station id string ("": not replaced) + * return : status (1:keywords replaced, 0:no valid keyword in the path, + * -1:no valid time) + * notes : the following keywords in path are replaced by date, time and name + * %Y -> yyyy : year (4 digits) (1900-2099) + * %y -> yy : year (2 digits) (00-99) + * %m -> mm : month (01-12) + * %d -> dd : day of month (01-31) + * %h -> hh : hours (00-23) + * %M -> mm : minutes (00-59) + * %S -> ss : seconds (00-59) + * %n -> ddd : day of year (001-366) + * %W -> wwww : gps week (0001-9999) + * %D -> d : day of gps week (0-6) + * %H -> h : hour code (a=0,b=1,c=2,...,x=23) + * %ha-> hh : 3 hours (00,03,06,...,21) + * %hb-> hh : 6 hours (00,06,12,18) + * %hc-> hh : 12 hours (00,12) + * %t -> mm : 15 minutes (00,15,30,45) + * %r -> rrrr : rover id + * %b -> bbbb : base station id + *-----------------------------------------------------------------------------*/ +extern int reppath(const char *path, char *rpath, gtime_t time, const char *rov, + const char *base) +{ + double ep[6], ep0[6] = {2000, 1, 1, 0, 0, 0}; + int week, dow, doy, stat = 0; + char rep[64]; + + strcpy(rpath, path); + + if (!strstr(rpath, "%")) + return 0; + if (*rov) + stat |= repstr(rpath, "%r", rov); + if (*base) + stat |= repstr(rpath, "%b", base); + if (time.time != 0) + { + time2epoch(time, ep); + ep0[0] = ep[0]; + dow = (int)floor(time2gpst(time, &week) / 86400.0); + doy = (int)floor(timediff(time, epoch2time(ep0)) / 86400.0) + 1; + sprintf(rep, "%02d", ((int)ep[3] / 3) * 3); + stat |= repstr(rpath, "%ha", rep); + sprintf(rep, "%02d", ((int)ep[3] / 6) * 6); + stat |= repstr(rpath, "%hb", rep); + sprintf(rep, "%02d", ((int)ep[3] / 12) * 12); + stat |= repstr(rpath, "%hc", rep); + sprintf(rep, "%04.0f", ep[0]); + stat |= repstr(rpath, "%Y", rep); + sprintf(rep, "%02.0f", fmod(ep[0], 100.0)); + stat |= repstr(rpath, "%y", rep); + sprintf(rep, "%02.0f", ep[1]); + stat |= repstr(rpath, "%m", rep); + sprintf(rep, "%02.0f", ep[2]); + stat |= repstr(rpath, "%d", rep); + sprintf(rep, "%02.0f", ep[3]); + stat |= repstr(rpath, "%h", rep); + sprintf(rep, "%02.0f", ep[4]); + stat |= repstr(rpath, "%M", rep); + sprintf(rep, "%02.0f", floor(ep[5])); + stat |= repstr(rpath, "%S", rep); + sprintf(rep, "%03d", doy); + stat |= repstr(rpath, "%n", rep); + sprintf(rep, "%04d", week); + stat |= repstr(rpath, "%W", rep); + sprintf(rep, "%d", dow); + stat |= repstr(rpath, "%D", rep); + sprintf(rep, "%c", 'a' + (int)ep[3]); + stat |= repstr(rpath, "%H", rep); + sprintf(rep, "%02d", ((int)ep[4] / 15) * 15); + stat |= repstr(rpath, "%t", rep); + } + else if (strstr(rpath, "%ha") || strstr(rpath, "%hb") || strstr(rpath, "%hc") || + strstr(rpath, "%Y") || strstr(rpath, "%y") || strstr(rpath, "%m") || + strstr(rpath, "%d") || strstr(rpath, "%h") || strstr(rpath, "%M") || + strstr(rpath, "%S") || strstr(rpath, "%n") || strstr(rpath, "%W") || + strstr(rpath, "%D") || strstr(rpath, "%H") || strstr(rpath, "%t")) + { + return -1; /* no valid time */ + } + return stat; +} +/* replace keywords in file path and generate multiple paths ------------------- + * replace keywords in file path with date, time, rover and base station id + * generate multiple keywords-replaced paths + * args : char *path I file path (see below) + * char *rpath[] O file paths in which keywords replaced + * int nmax I max number of output file paths + * gtime_t ts I time start (gpst) + * gtime_t te I time end (gpst) + * char *rov I rover id string ("": not replaced) + * char *base I base station id string ("": not replaced) + * return : number of replaced file paths + * notes : see reppath() for replacements of keywords. + * minimum interval of time replaced is 900s. + *-----------------------------------------------------------------------------*/ +extern int reppaths(const char *path, char *rpath[], int nmax, gtime_t ts, + gtime_t te, const char *rov, const char *base) +{ + gtime_t time; + double tow, tint = 86400.0; + int i, n = 0, week; + + trace(3, "reppaths: path =%s nmax=%d rov=%s base=%s\n", path, nmax, rov, base); + + if (ts.time == 0 || te.time == 0 || timediff(ts, te) > 0.0) + return 0; + + if (strstr(path, "%S") || strstr(path, "%M") || strstr(path, "%t")) + tint = 900.0; + else if (strstr(path, "%h") || strstr(path, "%H")) + tint = 3600.0; + + tow = time2gpst(ts, &week); + time = gpst2time(week, floor(tow / tint) * tint); + + while (timediff(time, te) <= 0.0 && n < nmax) + { + reppath(path, rpath[n], time, rov, base); + if (n == 0 || strcmp(rpath[n], rpath[n - 1])) + n++; + time = timeadd(time, tint); + } + for (i = 0; i < n; i++) + trace(3, "reppaths: rpath=%s\n", rpath[i]); + return n; +} +/* geometric distance ---------------------------------------------------------- + * compute geometric distance and receiver-to-satellite unit vector + * args : double *rs I satellilte position (ecef at transmission) (m) + * double *rr I receiver position (ecef at reception) (m) + * double *e O line-of-sight vector (ecef) + * return : geometric distance (m) (0>:error/no satellite position) + * notes : distance includes sagnac effect correction + *-----------------------------------------------------------------------------*/ +extern double geodist(const double *rs, const double *rr, double *e) +{ + double r; + int i; + + if (norm(rs, 3) < RE_WGS84) + return -1.0; + for (i = 0; i < 3; i++) + e[i] = rs[i] - rr[i]; + r = norm(e, 3); + for (i = 0; i < 3; i++) + e[i] /= r; + return r + OMGE * (rs[0] * rr[1] - rs[1] * rr[0]) / CLIGHT; +} +/* satellite azimuth/elevation angle ------------------------------------------- + * compute satellite azimuth/elevation angle + * args : double *pos I geodetic position {lat,lon,h} (rad,m) + * double *e I receiver-to-satellilte unit vevtor (ecef) + * double *azel IO azimuth/elevation {az,el} (rad) (NULL: no output) + * (0.0<=azel[0]<2*pi,-pi/2<=azel[1]<=pi/2) + * return : elevation angle (rad) + *-----------------------------------------------------------------------------*/ +extern double satazel(const double *pos, const double *e, double *azel) +{ + double az = 0.0, el = PI / 2.0, enu[3]; + + if (pos[2] > -RE_WGS84) + { + ecef2enu(pos, e, enu); + az = dot(enu, enu, 2) < 1E-12 ? 0.0 : atan2(enu[0], enu[1]); + if (az < 0.0) + az += 2 * PI; + el = asin(enu[2]); + } + if (azel) + { + azel[0] = az; + azel[1] = el; + } + return el; +} +/* compute dops ---------------------------------------------------------------- + * compute DOP (dilution of precision) + * args : int ns I number of satellites + * double *azel I satellite azimuth/elevation angle (rad) + * double elmin I elevation cutoff angle (rad) + * double *dop O DOPs {GDOP,PDOP,HDOP,VDOP} + * return : none + * notes : dop[0]-[3] return 0 in case of dop computation error + *-----------------------------------------------------------------------------*/ +#define SQRT(x) ((x) < 0.0 || (x) != (x) ? 0.0 : sqrt(x)) + +extern void dops(int ns, const double *azel, double elmin, double *dop) +{ + double H[4 * MAXSAT], Q[16], cosel, sinel; + int i, n; + + for (i = 0; i < 4; i++) + dop[i] = 0.0; + for (i = n = 0; i < ns && i < MAXSAT; i++) + { + if (azel[1 + i * 2] < elmin || azel[1 + i * 2] <= 0.0) + continue; + cosel = cos(azel[1 + i * 2]); + sinel = sin(azel[1 + i * 2]); + H[4 * n] = cosel * sin(azel[i * 2]); + H[1 + 4 * n] = cosel * cos(azel[i * 2]); + H[2 + 4 * n] = sinel; + H[3 + 4 * n++] = 1.0; + } + if (n < 4) + return; + + matmul("NT", 4, 4, n, 1.0, H, H, 0.0, Q); + if (!matinv(Q, 4)) + { + dop[0] = SQRT(Q[0] + Q[5] + Q[10] + Q[15]); /* GDOP */ + dop[1] = SQRT(Q[0] + Q[5] + Q[10]); /* PDOP */ + dop[2] = SQRT(Q[0] + Q[5]); /* HDOP */ + dop[3] = SQRT(Q[10]); /* VDOP */ + } +} +/* ionosphere model ------------------------------------------------------------ + * compute ionospheric delay by broadcast ionosphere model (klobuchar model) + * args : gtime_t t I time (gpst) + * double *ion I iono model parameters {a0,a1,a2,a3,b0,b1,b2,b3} + * double *pos I receiver position {lat,lon,h} (rad,m) + * double *azel I azimuth/elevation angle {az,el} (rad) + * return : ionospheric delay (L1) (m) + *-----------------------------------------------------------------------------*/ +extern double ionmodel(gtime_t t, const double *ion, const double *pos, + const double *azel) +{ + const double ion_default[] = {/* 2004/1/1 */ + 0.1118E-07, -0.7451E-08, -0.5961E-07, 0.1192E-06, + 0.1167E+06, -0.2294E+06, -0.1311E+06, 0.1049E+07}; + double tt, f, psi, phi, lam, amp, per, x; + int week; + + if (pos[2] < -1E3 || azel[1] <= 0) + return 0.0; + if (norm(ion, 8) <= 0.0) + ion = ion_default; + + /* earth centered angle (semi-circle) */ + psi = 0.0137 / (azel[1] / PI + 0.11) - 0.022; + + /* subionospheric latitude/longitude (semi-circle) */ + phi = pos[0] / PI + psi * cos(azel[0]); + if (phi > 0.416) + phi = 0.416; + else if (phi < -0.416) + phi = -0.416; + lam = pos[1] / PI + psi * sin(azel[0]) / cos(phi * PI); + + /* geomagnetic latitude (semi-circle) */ + phi += 0.064 * cos((lam - 1.617) * PI); + + /* local time (s) */ + tt = 43200.0 * lam + time2gpst(t, &week); + tt -= floor(tt / 86400.0) * 86400.0; /* 0<=tt<86400 */ + + /* slant factor */ + f = 1.0 + 16.0 * pow(0.53 - azel[1] / PI, 3.0); + + /* ionospheric delay */ + amp = ion[0] + phi * (ion[1] + phi * (ion[2] + phi * ion[3])); + per = ion[4] + phi * (ion[5] + phi * (ion[6] + phi * ion[7])); + amp = amp < 0.0 ? 0.0 : amp; + per = per < 72000.0 ? 72000.0 : per; + x = 2.0 * PI * (tt - 50400.0) / per; + + return CLIGHT * f * (fabs(x) < 1.57 ? 5E-9 + amp * (1.0 + x * x * (-0.5 + x * x / 24.0)) : 5E-9); +} +/* ionosphere mapping function ------------------------------------------------- + * compute ionospheric delay mapping function by single layer model + * args : double *pos I receiver position {lat,lon,h} (rad,m) + * double *azel I azimuth/elevation angle {az,el} (rad) + * return : ionospheric mapping function + *-----------------------------------------------------------------------------*/ +extern double ionmapf(const double *pos, const double *azel) +{ + if (pos[2] >= HION) + return 1.0; + return 1.0 / cos(asin((RE_WGS84 + pos[2]) / (RE_WGS84 + HION) * sin(PI / 2.0 - azel[1]))); +} +/* ionospheric pierce point position ------------------------------------------- + * compute ionospheric pierce point (ipp) position and slant factor + * args : double *pos I receiver position {lat,lon,h} (rad,m) + * double *azel I azimuth/elevation angle {az,el} (rad) + * double re I earth radius (km) + * double hion I altitude of ionosphere (km) + * double *posp O pierce point position {lat,lon,h} (rad,m) + * return : slant factor + * notes : see ref [2], only valid on the earth surface + * fixing bug on ref [2] A.4.4.10.1 A-22,23 + *-----------------------------------------------------------------------------*/ +extern double ionppp(const double *pos, const double *azel, double re, + double hion, double *posp) +{ + double cosaz, rp, ap, sinap, tanap; + + rp = re / (re + hion) * cos(azel[1]); + ap = PI / 2.0 - azel[1] - asin(rp); + sinap = sin(ap); + tanap = tan(ap); + cosaz = cos(azel[0]); + posp[0] = asin(sin(pos[0]) * cos(ap) + cos(pos[0]) * sinap * cosaz); + + if ((pos[0] > 70.0 * D2R && tanap * cosaz > tan(PI / 2.0 - pos[0])) || + (pos[0] < -70.0 * D2R && -tanap * cosaz > tan(PI / 2.0 + pos[0]))) + { + posp[1] = pos[1] + PI - asin(sinap * sin(azel[0]) / cos(posp[0])); + } + else + { + posp[1] = pos[1] + asin(sinap * sin(azel[0]) / cos(posp[0])); + } + return 1.0 / sqrt(1.0 - rp * rp); +} +/* troposphere model ----------------------------------------------------------- + * compute tropospheric delay by standard atmosphere and saastamoinen model + * args : gtime_t time I time + * double *pos I receiver position {lat,lon,h} (rad,m) + * double *azel I azimuth/elevation angle {az,el} (rad) + * double humi I relative humidity + * return : tropospheric delay (m) + *-----------------------------------------------------------------------------*/ +extern double tropmodel(gtime_t time, const double *pos, const double *azel, + double humi) +{ + const double temp0 = 15.0; /* temparature at sea level */ + double hgt, pres, temp, e, z, trph, trpw; + + if (pos[2] < -100.0 || 1E4 < pos[2] || azel[1] <= 0) + return 0.0; + + /* standard atmosphere */ + hgt = pos[2] < 0.0 ? 0.0 : pos[2]; + + pres = 1013.25 * pow(1.0 - 2.2557E-5 * hgt, 5.2568); + temp = temp0 - 6.5E-3 * hgt + 273.16; + e = 6.108 * humi * exp((17.15 * temp - 4684.0) / (temp - 38.45)); + + /* saastamoninen model */ + z = PI / 2.0 - azel[1]; + trph = 0.0022768 * pres / (1.0 - 0.00266 * cos(2.0 * pos[0]) - 0.00028 * hgt / 1E3) / cos(z); + trpw = 0.002277 * (1255.0 / temp + 0.05) * e / cos(z); + return trph + trpw; +} +#ifndef IERS_MODEL + +static double interpc(const double coef[], double lat) +{ + int i = (int)(lat / 15.0); + if (i < 1) + return coef[0]; + else if (i > 4) + return coef[4]; + return coef[i - 1] * (1.0 - lat / 15.0 + i) + coef[i] * (lat / 15.0 - i); +} +static double mapf(double el, double a, double b, double c) +{ + double sinel = sin(el); + return (1.0 + a / (1.0 + b / (1.0 + c))) / (sinel + (a / (sinel + b / (sinel + c)))); +} +static double nmf(gtime_t time, const double pos[], const double azel[], + double *mapfw) +{ + /* ref [5] table 3 */ + /* hydro-ave-a,b,c, hydro-amp-a,b,c, wet-a,b,c at latitude 15,30,45,60,75 */ + const double coef[][5] = { + {1.2769934E-3, 1.2683230E-3, 1.2465397E-3, 1.2196049E-3, 1.2045996E-3}, + {2.9153695E-3, 2.9152299E-3, 2.9288445E-3, 2.9022565E-3, 2.9024912E-3}, + {62.610505E-3, 62.837393E-3, 63.721774E-3, 63.824265E-3, 64.258455E-3}, + + {0.0000000E-0, 1.2709626E-5, 2.6523662E-5, 3.4000452E-5, 4.1202191E-5}, + {0.0000000E-0, 2.1414979E-5, 3.0160779E-5, 7.2562722E-5, 11.723375E-5}, + {0.0000000E-0, 9.0128400E-5, 4.3497037E-5, 84.795348E-5, 170.37206E-5}, + + {5.8021897E-4, 5.6794847E-4, 5.8118019E-4, 5.9727542E-4, 6.1641693E-4}, + {1.4275268E-3, 1.5138625E-3, 1.4572752E-3, 1.5007428E-3, 1.7599082E-3}, + {4.3472961E-2, 4.6729510E-2, 4.3908931E-2, 4.4626982E-2, 5.4736038E-2}}; + const double aht[] = {2.53E-5, 5.49E-3, 1.14E-3}; /* height correction */ + + double y, cosy, ah[3], aw[3], dm, el = azel[1], lat = pos[0] * R2D, hgt = pos[2]; + int i; + + if (el <= 0.0) + { + if (mapfw) + *mapfw = 0.0; + return 0.0; + } + /* year from doy 28, added half a year for southern latitudes */ + y = (time2doy(time) - 28.0) / 365.25 + (lat < 0.0 ? 0.5 : 0.0); + + cosy = cos(2.0 * PI * y); + lat = fabs(lat); + + for (i = 0; i < 3; i++) + { + ah[i] = interpc(coef[i], lat) - interpc(coef[i + 3], lat) * cosy; + aw[i] = interpc(coef[i + 6], lat); + } + /* ellipsoidal height is used instead of height above sea level */ + dm = (1.0 / sin(el) - mapf(el, aht[0], aht[1], aht[2])) * hgt / 1E3; + + if (mapfw) + *mapfw = mapf(el, aw[0], aw[1], aw[2]); + + return mapf(el, ah[0], ah[1], ah[2]) + dm; +} +#endif /* !IERS_MODEL */ + +/* troposphere mapping function ------------------------------------------------ + * compute tropospheric mapping function by NMF + * args : gtime_t t I time + * double *pos I receiver position {lat,lon,h} (rad,m) + * double *azel I azimuth/elevation angle {az,el} (rad) + * double *mapfw IO wet mapping function (NULL: not output) + * return : dry mapping function + * note : see ref [5] (NMF) and [9] (GMF) + * original JGR paper of [5] has bugs in eq.(4) and (5). the corrected + * paper is obtained from: + * ftp://web.haystack.edu/pub/aen/nmf/NMF_JGR.pdf + *-----------------------------------------------------------------------------*/ +extern double tropmapf(gtime_t time, const double pos[], const double azel[], + double *mapfw) +{ +#ifdef IERS_MODEL + const double ep[] = {2000, 1, 1, 12, 0, 0}; + double mjd, lat, lon, hgt, zd, gmfh, gmfw; +#endif + trace(4, "tropmapf: pos=%10.6f %11.6f %6.1f azel=%5.1f %4.1f\n", + pos[0] * R2D, pos[1] * R2D, pos[2], azel[0] * R2D, azel[1] * R2D); + + if (pos[2] < -1000.0 || pos[2] > 20000.0) + { + if (mapfw) + *mapfw = 0.0; + return 0.0; + } +#ifdef IERS_MODEL + mjd = 51544.5 + (timediff(time, epoch2time(ep))) / 86400.0; + lat = pos[0]; + lon = pos[1]; + hgt = pos[2] - geoidh(pos); /* height in m (mean sea level) */ + zd = PI / 2.0 - azel[1]; + + /* call GMF */ + gmf_(&mjd, &lat, &lon, &hgt, &zd, &gmfh, &gmfw); + + if (mapfw) + *mapfw = gmfw; + return gmfh; +#else + return nmf(time, pos, azel, mapfw); /* NMF */ +#endif +} +/* interpolate antenna phase center variation --------------------------------*/ +static double interpvar(double ang, const double *var) +{ + double a = ang / 5.0; /* ang=0-90 */ + int i = (int)a; + if (i < 0) + return var[0]; + else if (i >= 18) + return var[18]; + return var[i] * (1.0 - a + i) + var[i + 1] * (a - i); +} +/* receiver antenna model ------------------------------------------------------ + * compute antenna offset by antenna phase center parameters + * args : pcv_t *pcv I antenna phase center parameters + * double *del I antenna delta {e,n,u} (m) + * double *azel I azimuth/elevation for receiver {az,el} (rad) + * int opt I option (0:only offset,1:offset+pcv) + * double *dant O range offsets for each frequency (m) + * return : none + * notes : current version does not support azimuth dependent terms + *-----------------------------------------------------------------------------*/ +// extern void antmodel(const pcv_t *pcv, const double *del, const double *azel, +// int opt, double *dant) +//{ +// double e[3],off[3],cosel=cos(azel[1]); +// int i,j; +// +// trace(4,"antmodel: azel=%6.1f %4.1f opt=%d\n",azel[0]*R2D,azel[1]*R2D,opt); +// +// e[0]=sin(azel[0])*cosel; +// e[1]=cos(azel[0])*cosel; +// e[2]=sin(azel[1]); +// +// for (i=0;ioff[i][j]+del[j]; +// +// dant[i]=-dot(off,e,3)+(opt?interpvar(90.0-azel[1]*R2D,pcv->var[i]):0.0); +// } +// trace(2,"antmodel: dant=%6.3f %6.3f\n",dant[0],dant[1]); +// } +/* satellite antenna model ------------------------------------------------------ + * compute satellite antenna phase center parameters + * args : pcv_t *pcv I antenna phase center parameters + * double nadir I nadir angle for satellite (rad) + * double *dant O range offsets for each frequency (m) + * return : none + *-----------------------------------------------------------------------------*/ +// extern void antmodel_s(const pcv_t *pcv, double nadir, double *dant) +//{ +// int i; +// +// trace(4,"antmodel_s: nadir=%6.1f\n",nadir*R2D); +// +// for (i=0;ivar[i]); +// } +// trace(4,"antmodel_s: dant=%6.3f %6.3f\n",dant[0],dant[1]); +// } +/* sun and moon position in eci (ref [4] 5.1.1, 5.2.1) -----------------------*/ +static void sunmoonpos_eci(gtime_t tut, double *rsun, double *rmoon) +{ + const double ep2000[] = {2000, 1, 1, 12, 0, 0}; + double t, f[5], eps, Ms, ls, rs, lm, pm, rm, sine, cose, sinp, cosp, sinl, cosl; + + trace(4, "sunmoonpos_eci: tut=%s\n", time_str(tut, 3)); + + t = timediff(tut, epoch2time(ep2000)) / 86400.0 / 36525.0; + + /* astronomical arguments */ + ast_args(t, f); + + /* obliquity of the ecliptic */ + eps = 23.439291 - 0.0130042 * t; + sine = sin(eps * D2R); + cose = cos(eps * D2R); + + /* sun position in eci */ + if (rsun) + { + Ms = 357.5277233 + 35999.05034 * t; + ls = 280.460 + 36000.770 * t + 1.914666471 * sin(Ms * D2R) + 0.019994643 * sin(2.0 * Ms * D2R); + rs = AU * (1.000140612 - 0.016708617 * cos(Ms * D2R) - 0.000139589 * cos(2.0 * Ms * D2R)); + sinl = sin(ls * D2R); + cosl = cos(ls * D2R); + rsun[0] = rs * cosl; + rsun[1] = rs * cose * sinl; + rsun[2] = rs * sine * sinl; + + trace(5, "rsun =%.3f %.3f %.3f\n", rsun[0], rsun[1], rsun[2]); + } + /* moon position in eci */ + if (rmoon) + { + lm = 218.32 + 481267.883 * t + 6.29 * sin(f[0]) - 1.27 * sin(f[0] - 2.0 * f[3]) + + 0.66 * sin(2.0 * f[3]) + 0.21 * sin(2.0 * f[0]) - 0.19 * sin(f[1]) - 0.11 * sin(2.0 * f[2]); + pm = 5.13 * sin(f[2]) + 0.28 * sin(f[0] + f[2]) - 0.28 * sin(f[2] - f[0]) - + 0.17 * sin(f[2] - 2.0 * f[3]); + rm = RE_WGS84 / sin((0.9508 + 0.0518 * cos(f[0]) + 0.0095 * cos(f[0] - 2.0 * f[3]) + + 0.0078 * cos(2.0 * f[3]) + 0.0028 * cos(2.0 * f[0])) * + D2R); + sinl = sin(lm * D2R); + cosl = cos(lm * D2R); + sinp = sin(pm * D2R); + cosp = cos(pm * D2R); + rmoon[0] = rm * cosp * cosl; + rmoon[1] = rm * (cose * cosp * sinl - sine * sinp); + rmoon[2] = rm * (sine * cosp * sinl + cose * sinp); + + trace(5, "rmoon=%.3f %.3f %.3f\n", rmoon[0], rmoon[1], rmoon[2]); + } +} +/* sun and moon position ------------------------------------------------------- + * get sun and moon position in ecef + * args : gtime_t tut I time in ut1 + * double *erpv I erp value {xp,yp,ut1_utc,lod} (rad,rad,s,s/d) + * double *rsun IO sun position in ecef (m) (NULL: not output) + * double *rmoon IO moon position in ecef (m) (NULL: not output) + * double *gmst O gmst (rad) + * return : none + *-----------------------------------------------------------------------------*/ +extern void sunmoonpos(gtime_t tutc, const double *erpv, double *rsun, + double *rmoon, double *gmst) +{ + gtime_t tut; + double rs[3], rm[3], U[9], gmst_; + + trace(4, "sunmoonpos: tutc=%s\n", time_str(tutc, 3)); + + tut = timeadd(tutc, erpv[2]); /* utc -> ut1 */ + + /* sun and moon position in eci */ + sunmoonpos_eci(tut, rsun ? rs : NULL, rmoon ? rm : NULL); + + /* eci to ecef transformation matrix */ + eci2ecef(tutc, erpv, U, &gmst_); + + /* sun and moon postion in ecef */ + if (rsun) + matmul("NN", 3, 1, 3, 1.0, U, rs, 0.0, rsun); + if (rmoon) + matmul("NN", 3, 1, 3, 1.0, U, rm, 0.0, rmoon); + if (gmst) + *gmst = gmst_; +} +/* uncompress file ------------------------------------------------------------- + * uncompress (uncompress/unzip/uncompact hatanaka-compression/tar) file + * args : char *file I input file + * char *uncfile O uncompressed file + * return : status (-1:error,0:not compressed file,1:uncompress completed) + * note : creates uncompressed file in tempolary directory + * gzip, tar and crx2rnx commands have to be installed in commands path + *-----------------------------------------------------------------------------*/ +extern int rtk_uncompress(const char *file, char *uncfile) +{ + int stat = 0; + char *p, cmd[64 + 2048] = "", tmpfile[1024] = "", buff[1024], *fname, *dir = ""; + + trace(3, "rtk_uncompress: file=%s\n", file); + + strcpy(tmpfile, file); + if (!(p = strrchr(tmpfile, '.'))) + return 0; + + /* uncompress by gzip */ + if (!strcmp(p, ".z") || !strcmp(p, ".Z") || + !strcmp(p, ".gz") || !strcmp(p, ".GZ") || + !strcmp(p, ".zip") || !strcmp(p, ".ZIP")) + { + + strcpy(uncfile, tmpfile); + uncfile[p - tmpfile] = '\0'; + sprintf(cmd, "gzip -f -d -c \"%s\" > \"%s\"", tmpfile, uncfile); + + if (execcmd(cmd)) + { + remove(uncfile); + return -1; + } + strcpy(tmpfile, uncfile); + stat = 1; + } + /* extract tar file */ + if ((p = strrchr(tmpfile, '.')) && !strcmp(p, ".tar")) + { + + strcpy(uncfile, tmpfile); + uncfile[p - tmpfile] = '\0'; + strcpy(buff, tmpfile); + fname = buff; +#ifdef WIN32 + if ((p = strrchr(buff, '\\'))) + { + *p = '\0'; + dir = fname; + fname = p + 1; + } + sprintf(cmd, "set PATH=%%CD%%;%%PATH%% & cd /D \"%s\" & tar -xf \"%s\"", + dir, fname); +#else + if ((p = strrchr(buff, '/'))) + { + *p = '\0'; + dir = fname; + fname = p + 1; + } + sprintf(cmd, "tar -C \"%s\" -xf \"%s\"", dir, tmpfile); +#endif + if (execcmd(cmd)) + { + if (stat) + remove(tmpfile); + return -1; + } + if (stat) + remove(tmpfile); + stat = 1; + } + /* extract hatanaka-compressed file by cnx2rnx */ + else if ((p = strrchr(tmpfile, '.')) && + ((strlen(p) > 3 && (*(p + 3) == 'd' || *(p + 3) == 'D')) || + !strcmp(p, ".crx") || !strcmp(p, ".CRX"))) + { + + strcpy(uncfile, tmpfile); + uncfile[p - tmpfile + 3] = *(p + 3) == 'D' ? 'O' : 'o'; + sprintf(cmd, "crx2rnx < \"%s\" > \"%s\"", tmpfile, uncfile); + + if (execcmd(cmd)) + { + remove(uncfile); + if (stat) + remove(tmpfile); + return -1; + } + if (stat) + remove(tmpfile); + stat = 1; + } + trace(3, "rtk_uncompress: stat=%d\n", stat); + return stat; +} +/* dummy application functions for shared library ----------------------------*/ +#ifdef WIN_DLL +extern int showmsg(char *format, ...) +{ + return 0; +} +extern void settspan(gtime_t ts, gtime_t te) {} +extern void settime(gtime_t time) {} +#endif diff --git a/RTK/rtklib.h b/RTK/rtklib.h new file mode 100644 index 0000000..3532e02 --- /dev/null +++ b/RTK/rtklib.h @@ -0,0 +1,1732 @@ +/*------------------------------------------------------------------------------ + * rtklib.h : RTKLIB constants, types and function prototypes + * + * Copyright (C) 2007-2020 by T.TAKASU, All rights reserved. + * + * options : -DENAGLO enable GLONASS + * -DENAGAL enable Galileo + * -DENAQZS enable QZSS + * -DENACMP enable BeiDou + * -DENAIRN enable IRNSS + * -DNFREQ=n set number of obs codes/frequencies + * -DNEXOBS=n set number of extended obs codes + * -DMAXOBS=n set max number of obs data in an epoch + * -DWIN32 use WIN32 API + * -DWIN_DLL generate library as Windows DLL + * + * version : $Revision:$ $Date:$ + * history : 2007/01/13 1.0 rtklib ver.1.0.0 + * 2007/03/20 1.1 rtklib ver.1.1.0 + * 2008/07/15 1.2 rtklib ver.2.1.0 + * 2008/10/19 1.3 rtklib ver.2.1.1 + * 2009/01/31 1.4 rtklib ver.2.2.0 + * 2009/04/30 1.5 rtklib ver.2.2.1 + * 2009/07/30 1.6 rtklib ver.2.2.2 + * 2009/12/25 1.7 rtklib ver.2.3.0 + * 2010/07/29 1.8 rtklib ver.2.4.0 + * 2011/05/27 1.9 rtklib ver.2.4.1 + * 2013/03/28 1.10 rtklib ver.2.4.2 + * 2020/11/30 1.11 rtklib ver.2.4.3 b34 + *-----------------------------------------------------------------------------*/ +#define ENAGPS +// #define ENAGLO +// #define ENAGAL +#define ENACMP +// #define ENAQZS +//#define TRACE +// #define L5_TO_L2 +// #define ONLY_2FREQ +#define PAR + +#define USING_FILE_OPT +//#define STATIC + +#define STM32 + +#ifndef RTKLIB_H +#define RTKLIB_H +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef WIN32 +#include +#include +#else +#include +#include +#endif + + +/* constants -----------------------------------------------------------------*/ + +#define VER_RTKLIB "demo5" /* library version */ + +#define PATCH_LEVEL "b34e" /* patch level */ + +#define COPYRIGHT_RTKLIB \ + "Copyright (C) 2007-2020 T.Takasu\nAll rights reserved." +#define PI 3.1415926535897932 /* pi */ +#define D2R (PI / 180.0) /* deg to rad */ +#define R2D (180.0 / PI) /* rad to deg */ +#define CLIGHT 299792458.0 /* speed of light (m/s) */ +#define SC2RAD 3.1415926535898 /* semi-circle to radian (IS-GPS) */ +#define AU 149597870691.0 /* 1 AU (m) */ +#define AS2R (D2R / 3600.0) /* arc sec to radian */ + +#define OMGE 7.2921151467E-5 /* earth angular velocity (IS-GPS) (rad/s) */ + +#define RE_WGS84 6378137.0 /* earth semimajor axis (WGS84) (m) */ +#define FE_WGS84 (1.0 / 298.257223563) /* earth flattening (WGS84) */ + +#define HION 350000.0 /* ionosphere height (m) */ + +#define MAXFREQ 6 /* max NFREQ */ + +#define FREQL1 1.57542E9 /* L1/E1 frequency (Hz) */ +#define FREQL2 1.22760E9 /* L2 frequency (Hz) */ +#define FREQE5b 1.20714E9 /* E5b frequency (Hz) */ +#define FREQL5 1.17645E9 /* L5/E5a/B2a frequency (Hz) */ +#define FREQL6 1.27875E9 /* E6/L6 frequency (Hz) */ +#define FREQE5ab 1.191795E9 /* E5a+b frequency (Hz) */ +#define FREQs 2.492028E9 /* S frequency (Hz) */ +#define FREQ1_GLO 1.60200E9 /* GLONASS G1 base frequency (Hz) */ +#define DFRQ1_GLO 0.56250E6 /* GLONASS G1 bias frequency (Hz/n) */ +#define FREQ2_GLO 1.24600E9 /* GLONASS G2 base frequency (Hz) */ +#define DFRQ2_GLO 0.43750E6 /* GLONASS G2 bias frequency (Hz/n) */ +#define FREQ3_GLO 1.202025E9 /* GLONASS G3 frequency (Hz) */ +#define FREQ1a_GLO 1.600995E9 /* GLONASS G1a frequency (Hz) */ +#define FREQ2a_GLO 1.248060E9 /* GLONASS G2a frequency (Hz) */ +#define FREQ1_CMP 1.561098E9 /* BDS B1I frequency (Hz) */ +#define FREQ2_CMP 1.20714E9 /* BDS B2I/B2b frequency (Hz) */ +#define FREQ3_CMP 1.26852E9 /* BDS B3 frequency (Hz) */ + +#define EFACT_GPS 1.0 /* error factor: GPS */ +#define EFACT_GLO 1.5 /* error factor: GLONASS */ +#define EFACT_GAL 1.0 /* error factor: Galileo */ +#define EFACT_QZS 1.0 /* error factor: QZSS */ +#define EFACT_CMP 1.0 /* error factor: BeiDou */ +#define EFACT_IRN 1.5 /* error factor: IRNSS */ +#define EFACT_SBS 3.0 /* error factor: SBAS */ + +#define SYS_NONE 0x00 /* navigation system: none */ +#define SYS_GPS 0x01 /* navigation system: GPS */ +#define SYS_SBS 0x02 /* navigation system: SBAS */ +#define SYS_GLO 0x04 /* navigation system: GLONASS */ +#define SYS_GAL 0x08 /* navigation system: Galileo */ +#define SYS_QZS 0x10 /* navigation system: QZSS */ +#define SYS_CMP 0x20 /* navigation system: BeiDou */ +#define SYS_IRN 0x40 /* navigation system: IRNS */ +#define SYS_LEO 0x80 /* navigation system: LEO */ +#define SYS_ALL 0xFF /* navigation system: all */ + +#define TSYS_GPS 0 /* time system: GPS time */ +#define TSYS_UTC 1 /* time system: UTC */ +#define TSYS_GLO 2 /* time system: GLONASS time */ +#define TSYS_GAL 3 /* time system: Galileo time */ +#define TSYS_QZS 4 /* time system: QZSS time */ +#define TSYS_CMP 5 /* time system: BeiDou time */ +#define TSYS_IRN 6 /* time system: IRNSS time */ + +#ifndef NFREQ +#define NFREQ 3 /* number of carrier frequencies */ +#endif +#define NFREQGLO 2 /* number of carrier frequencies of GLONASS */ + +#ifndef NEXOBS +#define NEXOBS 0 /* number of extended obs codes */ +#endif + +#define SNR_UNIT 0.001 /* SNR unit (dBHz) */ + +#define MINPRNGPS 1 /* min satellite PRN number of GPS */ +#define MAXPRNGPS 32 /* max satellite PRN number of GPS */ +#define NSATGPS (MAXPRNGPS - MINPRNGPS + 1) /* number of GPS satellites */ +#define NSYSGPS 1 + +#ifdef ENAGLO +#define MINPRNGLO 1 /* min satellite slot number of GLONASS */ +#define MAXPRNGLO 27 /* max satellite slot number of GLONASS */ +#define NSATGLO (MAXPRNGLO - MINPRNGLO + 1) /* number of GLONASS satellites */ +#define NSYSGLO 1 +#else +#define MINPRNGLO 0 +#define MAXPRNGLO 0 +#define NSATGLO 0 +#define NSYSGLO 0 +#endif +#ifdef ENAGAL +#define MINPRNGAL 1 /* min satellite PRN number of Galileo */ +#define MAXPRNGAL 36 /* max satellite PRN number of Galileo */ +#define NSATGAL (MAXPRNGAL - MINPRNGAL + 1) /* number of Galileo satellites */ +#define NSYSGAL 1 +#else +#define MINPRNGAL 0 +#define MAXPRNGAL 0 +#define NSATGAL 0 +#define NSYSGAL 0 +#endif +#ifdef ENAQZS +#define MINPRNQZS 193 /* min satellite PRN number of QZSS */ +#define MAXPRNQZS 202 /* max satellite PRN number of QZSS */ +#define MINPRNQZS_S 183 /* min satellite PRN number of QZSS L1S */ +#define MAXPRNQZS_S 191 /* max satellite PRN number of QZSS L1S */ +#define NSATQZS (MAXPRNQZS - MINPRNQZS + 1) /* number of QZSS satellites */ +#define NSYSQZS 1 +#else +#define MINPRNQZS 0 +#define MAXPRNQZS 0 +#define MINPRNQZS_S 0 +#define MAXPRNQZS_S 0 +#define NSATQZS 0 +#define NSYSQZS 0 +#endif +#ifdef ENACMP +#define MINPRNCMP 1 /* min satellite sat number of BeiDou */ +#define MAXPRNCMP 46 /* max satellite sat number of BeiDou */ +#define NSATCMP (MAXPRNCMP - MINPRNCMP + 1) /* number of BeiDou satellites */ +#define NSYSCMP 1 +#else +#define MINPRNCMP 0 +#define MAXPRNCMP 0 +#define NSATCMP 0 +#define NSYSCMP 0 +#endif +#ifdef ENAIRN +#define MINPRNIRN 1 /* min satellite sat number of IRNSS */ +#define MAXPRNIRN 14 /* max satellite sat number of IRNSS */ +#define NSATIRN (MAXPRNIRN - MINPRNIRN + 1) /* number of IRNSS satellites */ +#define NSYSIRN 1 +#else +#define MINPRNIRN 0 +#define MAXPRNIRN 0 +#define NSATIRN 0 +#define NSYSIRN 0 +#endif +#ifdef ENALEO +#define MINPRNLEO 1 /* min satellite sat number of LEO */ +#define MAXPRNLEO 10 /* max satellite sat number of LEO */ +#define NSATLEO (MAXPRNLEO - MINPRNLEO + 1) /* number of LEO satellites */ +#define NSYSLEO 1 +#else +#define MINPRNLEO 0 +#define MAXPRNLEO 0 +#define NSATLEO 0 +#define NSYSLEO 0 +#endif +#define NSYS (NSYSGPS + NSYSGLO + NSYSGAL + NSYSQZS + NSYSCMP + NSYSIRN + NSYSLEO) /* number of systems */ + +#define MINPRNSBS 120 /* min satellite PRN number of SBAS */ +#define MAXPRNSBS 158 /* max satellite PRN number of SBAS */ +//#define NSATSBS (MAXPRNSBS-MINPRNSBS+1) /* number of SBAS satellites */ +#define NSATSBS 0 +#define MAXSAT (NSATGPS + NSATGLO + NSATGAL + NSATQZS + NSATCMP + NSATIRN + NSATSBS + NSATLEO) +//#define MAXSAT 32 +/* max satellite number (1 to MAXSAT) */ +#define MAXSTA 255 + +#ifndef MAXOBS +#define MAXOBS 32 /* max number of obs in an epoch 96*/ +#endif +#define MAXRCV 2 /* max receiver number (1 to MAXRCV) 64 */ +#define MAXOBSTYPE 64 /* max number of obs type in RINEX */ +#ifdef OBS_100HZ +#define DTTOL 0.005 /* tolerance of time difference (s) */ +#else +#define DTTOL 0.025 /* tolerance of time difference (s) */ +#endif +#define MAXDTOE 7200.0 /* max time difference to GPS Toe (s) */ +#define MAXDTOE_QZS 7200.0 /* max time difference to QZSS Toe (s) */ +#define MAXDTOE_GAL 14400.0 /* max time difference to Galileo Toe (s) */ +#define MAXDTOE_CMP 21600.0 /* max time difference to BeiDou Toe (s) */ +#define MAXDTOE_GLO 1800.0 /* max time difference to GLONASS Toe (s) */ +#define MAXDTOE_IRN 7200.0 /* max time difference to IRNSS Toe (s) */ +#define MAXDTOE_SBS 360.0 /* max time difference to SBAS Toe (s) */ +#define MAXDTOE_S 86400.0 /* max time difference to ephem toe (s) for other */ +#define MAXGDOP 300.0 /* max GDOP */ + +#define INT_SWAP_TRAC 86400.0 /* swap interval of trace file (s) */ +#define INT_SWAP_STAT 86400.0 /* swap interval of solution status file (s) */ + +#define MAXEXFILE 1024 /* max number of expanded files */ +#define MAXSBSAGEF 30.0 /* max age of SBAS fast correction (s) */ +#define MAXSBSAGEL 1800.0 /* max age of SBAS long term corr (s) */ +#define MAXSBSURA 8 /* max URA of SBAS satellite */ +#define MAXBAND 10 /* max SBAS band of IGP */ +#define MAXNIGP 201 /* max number of IGP in SBAS band */ +#define MAXNGEO 4 /* max number of GEO satellites */ +#define MAXCOMMENT 100 /* max number of RINEX comments */ +#define MAXSTRPATH 1024 /* max length of stream path */ +#define MAXSTRMSG 1024 /* max length of stream message */ +#define MAXSTRRTK 8 /* max number of stream in RTK server */ +#define MAXSBSMSG 32 /* max number of SBAS msg in RTK server */ +#define MAXSOLMSG 8191 /* max length of solution message */ +#define MAXRAWLEN 16384 /* max length of receiver raw message */ +#define MAXERRMSG 4096 /* max length of error/warning message */ +#define MAXANT 64 /* max length of station name/antenna type */ +#define MAXSOLBUF 1 /* max number of solution buffer 256*/ +#define MAXOBSBUF 1 /* max number of observation data buffer 128*/ +#define MAXNRPOS 16 /* max number of reference positions */ +#define MAXLEAPS 64 /* max number of leap seconds table */ +#define MAXGISLAYER 32 /* max number of GIS data layers */ +#define MAXRCVCMD 4096 /* max length of receiver commands */ + +#define RNX2VER 2.10 /* RINEX ver.2 default output version */ +#define RNX3VER 3.00 /* RINEX ver.3 default output version */ + +#define OBSTYPE_PR 0x01 /* observation type: pseudorange */ +#define OBSTYPE_CP 0x02 /* observation type: carrier-phase */ +#define OBSTYPE_DOP 0x04 /* observation type: doppler-freq */ +#define OBSTYPE_SNR 0x08 /* observation type: SNR */ +#define OBSTYPE_ALL 0xFF /* observation type: all */ + +#define FREQTYPE_L1 0x01 /* frequency type: L1/E1/B1 */ +#define FREQTYPE_L2 0x02 /* frequency type: L2/E5b/B2 */ +#define FREQTYPE_L3 0x04 /* frequency type: L5/E5a/L3 */ +#define FREQTYPE_L4 0x08 /* frequency type: L6/E6/B3 */ +#define FREQTYPE_L5 0x10 /* frequency type: E5ab */ +#define FREQTYPE_ALL 0xFF /* frequency type: all */ + +#define CODE_NONE 0 /* obs code: none or unknown */ +#define CODE_L1C 1 /* obs code: L1C/A,G1C/A,E1C (GPS,GLO,GAL,QZS,SBS) */ +#define CODE_L1P 2 /* obs code: L1P,G1P,B1P (GPS,GLO,BDS) */ +#define CODE_L1W 3 /* obs code: L1 Z-track (GPS) */ +#define CODE_L1Y 4 /* obs code: L1Y (GPS) */ +#define CODE_L1M 5 /* obs code: L1M (GPS) */ +#define CODE_L1N 6 /* obs code: L1codeless,B1codeless (GPS,BDS) */ +#define CODE_L1S 7 /* obs code: L1C(D) (GPS,QZS) */ +#define CODE_L1L 8 /* obs code: L1C(P) (GPS,QZS) */ +#define CODE_L1E 9 /* (not used) */ +#define CODE_L1A 10 /* obs code: E1A,B1A (GAL,BDS) */ +#define CODE_L1B 11 /* obs code: E1B (GAL) */ +#define CODE_L1X 12 /* obs code: E1B+C,L1C(D+P),B1D+P (GAL,QZS,BDS) */ +#define CODE_L1Z 13 /* obs code: E1A+B+C,L1S (GAL,QZS) */ +#define CODE_L2C 14 /* obs code: L2C/A,G1C/A (GPS,GLO) */ +#define CODE_L2D 15 /* obs code: L2 L1C/A-(P2-P1) (GPS) */ +#define CODE_L2S 16 /* obs code: L2C(M) (GPS,QZS) */ +#define CODE_L2L 17 /* obs code: L2C(L) (GPS,QZS) */ +#define CODE_L2X 18 /* obs code: L2C(M+L),B1_2I+Q (GPS,QZS,BDS) */ +#define CODE_L2P 19 /* obs code: L2P,G2P (GPS,GLO) */ +#define CODE_L2W 20 /* obs code: L2 Z-track (GPS) */ +#define CODE_L2Y 21 /* obs code: L2Y (GPS) */ +#define CODE_L2M 22 /* obs code: L2M (GPS) */ +#define CODE_L2N 23 /* obs code: L2codeless (GPS) */ +#define CODE_L5I 24 /* obs code: L5I,E5aI (GPS,GAL,QZS,SBS) */ +#define CODE_L5Q 25 /* obs code: L5Q,E5aQ (GPS,GAL,QZS,SBS) */ +#define CODE_L5X 26 /* obs code: L5I+Q,E5aI+Q,L5B+C,B2aD+P (GPS,GAL,QZS,IRN,SBS,BDS) */ +#define CODE_L7I 27 /* obs code: E5bI,B2bI (GAL,BDS) */ +#define CODE_L7Q 28 /* obs code: E5bQ,B2bQ (GAL,BDS) */ +#define CODE_L7X 29 /* obs code: E5bI+Q,B2bI+Q (GAL,BDS) */ +#define CODE_L6A 30 /* obs code: E6A,B3A (GAL,BDS) */ +#define CODE_L6B 31 /* obs code: E6B (GAL) */ +#define CODE_L6C 32 /* obs code: E6C (GAL) */ +#define CODE_L6X 33 /* obs code: E6B+C,LEXS+L,B3I+Q (GAL,QZS,BDS) */ +#define CODE_L6Z 34 /* obs code: E6A+B+C,L6D+E (GAL,QZS) */ +#define CODE_L6S 35 /* obs code: L6S (QZS) */ +#define CODE_L6L 36 /* obs code: L6L (QZS) */ +#define CODE_L8I 37 /* obs code: E5abI (GAL) */ +#define CODE_L8Q 38 /* obs code: E5abQ (GAL) */ +#define CODE_L8X 39 /* obs code: E5abI+Q,B2abD+P (GAL,BDS) */ +#define CODE_L2I 40 /* obs code: B1_2I (BDS) */ +#define CODE_L2Q 41 /* obs code: B1_2Q (BDS) */ +#define CODE_L6I 42 /* obs code: B3I (BDS) */ +#define CODE_L6Q 43 /* obs code: B3Q (BDS) */ +#define CODE_L3I 44 /* obs code: G3I (GLO) */ +#define CODE_L3Q 45 /* obs code: G3Q (GLO) */ +#define CODE_L3X 46 /* obs code: G3I+Q (GLO) */ +#define CODE_L1I 47 /* obs code: B1I (BDS) (obsolute) */ +#define CODE_L1Q 48 /* obs code: B1Q (BDS) (obsolute) */ +#define CODE_L5A 49 /* obs code: L5A SPS (IRN) */ +#define CODE_L5B 50 /* obs code: L5B RS(D) (IRN) */ +#define CODE_L5C 51 /* obs code: L5C RS(P) (IRN) */ +#define CODE_L9A 52 /* obs code: SA SPS (IRN) */ +#define CODE_L9B 53 /* obs code: SB RS(D) (IRN) */ +#define CODE_L9C 54 /* obs code: SC RS(P) (IRN) */ +#define CODE_L9X 55 /* obs code: SB+C (IRN) */ +#define CODE_L1D 56 /* obs code: B1D (BDS) */ +#define CODE_L5D 57 /* obs code: L5D(L5S),B2aD (QZS,BDS) */ +#define CODE_L5P 58 /* obs code: L5P(L5S),B2aP (QZS,BDS) */ +#define CODE_L5Z 59 /* obs code: L5D+P(L5S) (QZS) */ +#define CODE_L6E 60 /* obs code: L6E (QZS) */ +#define CODE_L7D 61 /* obs code: B2bD (BDS) */ +#define CODE_L7P 62 /* obs code: B2bP (BDS) */ +#define CODE_L7Z 63 /* obs code: B2bD+P (BDS) */ +#define CODE_L8D 64 /* obs code: B2abD (BDS) */ +#define CODE_L8P 65 /* obs code: B2abP (BDS) */ +#define CODE_L4A 66 /* obs code: G1aL1OCd (GLO) */ +#define CODE_L4B 67 /* obs code: G1aL1OCd (GLO) */ +#define CODE_L4X 68 /* obs code: G1al1OCd+p (GLO) */ +#define MAXCODE 68 /* max number of obs code */ + +#define PMODE_SINGLE 0 /* positioning mode: single */ +#define PMODE_DGPS 1 /* positioning mode: DGPS/DGNSS */ +#define PMODE_KINEMA 2 /* positioning mode: kinematic */ +#define PMODE_STATIC 3 /* positioning mode: static */ +#define PMODE_STATIC_START 4 /* positioning mode: static */ +#define PMODE_MOVEB 5 /* positioning mode: moving-base */ +#define PMODE_FIXED 6 /* positioning mode: fixed */ +// #define PMODE_PPP_KINEMA 7 /* positioning mode: PPP-kinemaric */ +// #define PMODE_PPP_STATIC 8 /* positioning mode: PPP-static */ +// #define PMODE_PPP_FIXED 9 /* positioning mode: PPP-fixed */ + +#define SOLF_LLH 0 /* solution format: lat/lon/height */ +#define SOLF_XYZ 1 /* solution format: x/y/z-ecef */ +#define SOLF_ENU 2 /* solution format: e/n/u-baseline */ +#define SOLF_NMEA 3 /* solution format: NMEA-183 */ +#define SOLF_STAT 4 /* solution format: solution status */ +#define SOLF_GSIF 5 /* solution format: GSI F1/F2 */ + +#define SOLQ_NONE 0 /* solution status: no solution */ +#define SOLQ_FIX 1 /* solution status: fix */ +#define SOLQ_FLOAT 2 /* solution status: float */ +#define SOLQ_SBAS 3 /* solution status: SBAS */ +#define SOLQ_DGPS 4 /* solution status: DGPS/DGNSS */ +#define SOLQ_SINGLE 5 /* solution status: single */ +#define SOLQ_PPP 6 /* solution status: PPP */ +#define SOLQ_DR 7 /* solution status: dead reconing */ +#define MAXSOLQ 7 /* max number of solution status */ + +#define TIMES_GPST 0 /* time system: gps time */ +#define TIMES_UTC 1 /* time system: utc */ +#define TIMES_JST 2 /* time system: jst */ + +#define IONOOPT_OFF 0 /* ionosphere option: correction off */ +#define IONOOPT_BRDC 1 /* ionosphere option: broadcast model */ +#define IONOOPT_SBAS 2 /* ionosphere option: SBAS model */ +#define IONOOPT_IFLC 3 /* ionosphere option: L1/L2 or L1/L5 iono-free LC */ +#define IONOOPT_EST 4 /* ionosphere option: estimation */ +#define IONOOPT_TEC 5 /* ionosphere option: IONEX TEC model */ +#define IONOOPT_QZS 6 /* ionosphere option: QZSS broadcast model */ +#define IONOOPT_STEC 8 /* ionosphere option: SLANT TEC model */ + +#define TROPOPT_OFF 0 /* troposphere option: correction off */ +#define TROPOPT_SAAS 1 /* troposphere option: Saastamoinen model */ +#define TROPOPT_SBAS 2 /* troposphere option: SBAS model */ +#define TROPOPT_EST 3 /* troposphere option: ZTD estimation */ +#define TROPOPT_ESTG 4 /* troposphere option: ZTD+grad estimation */ +#define TROPOPT_ZTD 5 /* troposphere option: ZTD correction */ + +#define EPHOPT_BRDC 0 /* ephemeris option: broadcast ephemeris */ +#define EPHOPT_PREC 1 /* ephemeris option: precise ephemeris */ +#define EPHOPT_SBAS 2 /* ephemeris option: broadcast + SBAS */ +#define EPHOPT_SSRAPC 3 /* ephemeris option: broadcast + SSR_APC */ +#define EPHOPT_SSRCOM 4 /* ephemeris option: broadcast + SSR_COM */ + +#define ARMODE_OFF 0 /* AR mode: off */ +#define ARMODE_CONT 1 /* AR mode: continuous */ +#define ARMODE_INST 2 /* AR mode: instantaneous */ +#define ARMODE_FIXHOLD 3 /* AR mode: fix and hold */ +#define ARMODE_WLNL 4 /* AR mode: wide lane/narrow lane */ +#define ARMODE_TCAR 5 /* AR mode: triple carrier ar */ + +#define GLO_ARMODE_OFF 0 /* GLO AR mode: off */ +#define GLO_ARMODE_ON 1 /* GLO AR mode: on */ +#define GLO_ARMODE_AUTOCAL 2 /* GLO AR mode: autocal */ +#define GLO_ARMODE_FIXHOLD 3 /* GLO AR mode: fix and hold */ + +#define SBSOPT_LCORR 1 /* SBAS option: long term correction */ +#define SBSOPT_FCORR 2 /* SBAS option: fast correction */ +#define SBSOPT_ICORR 4 /* SBAS option: ionosphere correction */ +#define SBSOPT_RANGE 8 /* SBAS option: ranging */ + +#define POSOPT_POS 0 /* pos option: LLH/XYZ */ +#define POSOPT_SINGLE 1 /* pos option: average of single pos */ +#define POSOPT_FILE 2 /* pos option: read from pos file */ +#define POSOPT_RINEX 3 /* pos option: rinex header pos */ +#define POSOPT_RTCM 4 /* pos option: rtcm/raw station pos */ + +#define STR_NONE 0 /* stream type: none */ +#define STR_SERIAL 1 /* stream type: serial */ +#define STR_FILE 2 /* stream type: file */ +#define STR_TCPSVR 3 /* stream type: TCP server */ +#define STR_TCPCLI 4 /* stream type: TCP client */ +#define STR_NTRIPSVR 5 /* stream type: NTRIP server */ +#define STR_NTRIPCLI 6 /* stream type: NTRIP client */ +#define STR_FTP 7 /* stream type: ftp */ +#define STR_HTTP 8 /* stream type: http */ +#define STR_NTRIPCAS 9 /* stream type: NTRIP caster */ +#define STR_UDPSVR 10 /* stream type: UDP server */ +#define STR_UDPCLI 11 /* stream type: UDP server */ +#define STR_MEMBUF 12 /* stream type: memory buffer */ + +#define STRFMT_RTCM2 0 /* stream format: RTCM 2 */ +#define STRFMT_RTCM3 1 /* stream format: RTCM 3 */ +#define STRFMT_OEM4 2 /* stream format: NovAtel OEMV/4 */ +#define STRFMT_CNAV 3 /* stream format: ComNav */ +#define STRFMT_UBX 4 /* stream format: u-blox LEA-*T */ +#define STRFMT_SBP 5 /* stream format: Swift Navigation SBP */ +#define STRFMT_CRES 6 /* stream format: Hemisphere */ +#define STRFMT_STQ 7 /* stream format: SkyTraq S1315F */ +#define STRFMT_JAVAD 8 /* stream format: JAVAD GRIL/GREIS */ +#define STRFMT_NVS 9 /* stream format: NVS NVC08C */ +#define STRFMT_BINEX 10 /* stream format: BINEX */ +#define STRFMT_RT17 11 /* stream format: Trimble RT17 */ +#define STRFMT_SEPT 12 /* stream format: Septentrio */ +#define STRFMT_TERSUS 13 /* stream format: TERSUS */ +#define STRFMT_RINEX 14 /* stream format: RINEX */ +#define STRFMT_SP3 15 /* stream format: SP3 */ +#define STRFMT_RNXCLK 16 /* stream format: RINEX CLK */ +#define STRFMT_SBAS 17 /* stream format: SBAS messages */ +#define STRFMT_NMEA 18 /* stream format: NMEA 0183 */ +#define MAXRCVFMT 13 /* max number of receiver format */ + +#define STR_MODE_R 0x1 /* stream mode: read */ +#define STR_MODE_W 0x2 /* stream mode: write */ +#define STR_MODE_RW 0x3 /* stream mode: read/write */ + +#define GEOID_EMBEDDED 0 /* geoid model: embedded geoid */ +#define GEOID_EGM96_M150 1 /* geoid model: EGM96 15x15" */ +#define GEOID_EGM2008_M25 2 /* geoid model: EGM2008 2.5x2.5" */ +#define GEOID_EGM2008_M10 3 /* geoid model: EGM2008 1.0x1.0" */ +#define GEOID_GSI2000_M15 4 /* geoid model: GSI geoid 2000 1.0x1.5" */ +#define GEOID_RAF09 5 /* geoid model: IGN RAF09 for France 1.5"x2" */ + +#define COMMENTH "%" /* comment line indicator for solution */ +#define MSG_DISCONN "$_DISCONNECT\r\n" /* disconnect message */ + +#define DLOPT_FORCE 0x01 /* download option: force download existing */ +#define DLOPT_KEEPCMP 0x02 /* download option: keep compressed file */ +#define DLOPT_HOLDERR 0x04 /* download option: hold on error file */ +#define DLOPT_HOLDLST 0x08 /* download option: hold on listing file */ + +#define LLI_SLIP 0x01 /* LLI: cycle-slip */ +#define LLI_HALFC 0x02 /* LLI: half-cycle not resovled */ +#define LLI_BOCTRK 0x04 /* LLI: boc tracking of mboc signal */ +#define LLI_HALFA 0x40 /* LLI: half-cycle added */ +#define LLI_HALFS 0x80 /* LLI: half-cycle subtracted */ + +#define P2_5 0.03125 /* 2^-5 */ +#define P2_6 0.015625 /* 2^-6 */ +#define P2_11 4.882812500000000E-04 /* 2^-11 */ +#define P2_15 3.051757812500000E-05 /* 2^-15 */ +#define P2_17 7.629394531250000E-06 /* 2^-17 */ +#define P2_19 1.907348632812500E-06 /* 2^-19 */ +#define P2_20 9.536743164062500E-07 /* 2^-20 */ +#define P2_21 4.768371582031250E-07 /* 2^-21 */ +#define P2_23 1.192092895507810E-07 /* 2^-23 */ +#define P2_24 5.960464477539063E-08 /* 2^-24 */ +#define P2_27 7.450580596923828E-09 /* 2^-27 */ +#define P2_29 1.862645149230957E-09 /* 2^-29 */ +#define P2_30 9.313225746154785E-10 /* 2^-30 */ +#define P2_31 4.656612873077393E-10 /* 2^-31 */ +#define P2_32 2.328306436538696E-10 /* 2^-32 */ +#define P2_33 1.164153218269348E-10 /* 2^-33 */ +#define P2_35 2.910383045673370E-11 /* 2^-35 */ +#define P2_38 3.637978807091710E-12 /* 2^-38 */ +#define P2_39 1.818989403545856E-12 /* 2^-39 */ +#define P2_40 9.094947017729280E-13 /* 2^-40 */ +#define P2_43 1.136868377216160E-13 /* 2^-43 */ +#define P2_48 3.552713678800501E-15 /* 2^-48 */ +#define P2_50 8.881784197001252E-16 /* 2^-50 */ +#define P2_55 2.775557561562891E-17 /* 2^-55 */ + +//#ifdef WIN32 +//#define thread_t HANDLE +//#define lock_t CRITICAL_SECTION +//#define initlock(f) InitializeCriticalSection(f) +//#define lock(f) EnterCriticalSection(f) +//#define unlock(f) LeaveCriticalSection(f) +//#define FILEPATHSEP '\\' +//#else +//#define thread_t pthread_t +//#define lock_t pthread_mutex_t +//#define initlock(f) pthread_mutex_init(f, NULL) +//#define lock(f) pthread_mutex_lock(f) +//#define unlock(f) pthread_mutex_unlock(f) +#define FILEPATHSEP '/' +//#endif + +/* type definitions ----------------------------------------------------------*/ +typedef struct +{ /* time struct */ + time_t time; /* time (s) expressed by standard time_t */ + double sec; /* fraction of second under 1 s */ +} gtime_t; +typedef struct +{ /* observation data record */ + gtime_t time; /* receiver sampling time (GPST) */ + uint8_t sat, rcv; /* satellite/receiver number */ + uint16_t SNR[NFREQ + NEXOBS]; /* signal strength (0.001 dBHz) */ + uint8_t LLI[NFREQ + NEXOBS]; /* loss of lock indicator */ + uint8_t code[NFREQ + NEXOBS]; /* code indicator (CODE_???) */ + double L[NFREQ + NEXOBS]; /* observation data carrier-phase (cycle) */ + double P[NFREQ + NEXOBS]; /* observation data pseudorange (m) */ + float D[NFREQ + NEXOBS]; /* observation data doppler frequency (Hz) */ + int timevalid; /* time is valid (Valid GNSS fix) for time mark */ + gtime_t eventime; /* time of event (GPST) */ + uint8_t Lstd[NFREQ + NEXOBS]; /* stdev of carrier phase (0.004 cycles) */ + uint8_t Pstd[NFREQ + NEXOBS]; /* stdev of pseudorange (0.01*2^(n+5) meters) */ + uint8_t freq; /* GLONASS frequency channel (0-13) */ +} obsd_t; +typedef struct +{ /* observation data */ + int n, nmax; /* number of obervation data/allocated */ + int flag; /* epoch flag (0:ok,1:power failure,>1:event flag) */ + int rcvcount; /* count of rcv event */ + int tmcount; /* time mark count */ + obsd_t *data; /* observation data records */ +} obs_t; +typedef struct +{ /* earth rotation parameter data type */ + double mjd; /* mjd (days) */ + double xp, yp; /* pole offset (rad) */ + double xpr, ypr; /* pole offset rate (rad/day) */ + double ut1_utc; /* ut1-utc (s) */ + double lod; /* length of day (s/day) */ +} erpd_t; +typedef struct +{ /* earth rotation parameter type */ + int n, nmax; /* number and max number of data */ + erpd_t *data; /* earth rotation parameter data */ +} erp_t; +// typedef struct +// { /* antenna parameter type */ +// int sat; /* satellite number (0:receiver) */ +// char type[MAXANT]; /* antenna type */ +// char code[MAXANT]; /* serial number or satellite code */ +// gtime_t ts, te; /* valid time start and end */ +// double off[NFREQ][3]; /* phase center offset e/n/u or x/y/z (m) */ +// double var[NFREQ][19]; /* phase center variation (m) */ +// /* el=90,85,...,0 or nadir=0,1,2,3,... (deg) */ +// } pcv_t; +// typedef struct +// { /* antenna parameters type */ +// int n, nmax; /* number of data/allocated */ +// pcv_t *pcv; /* antenna parameters data */ +// } pcvs_t; +// typedef struct { /* almanac type */ +// int sat; /* satellite number */ +// int svh; /* sv health (0:ok) */ +// int svconf; /* as and sv config */ +// int week; /* GPS/QZS: gps week, GAL: galileo week */ +// gtime_t toa; /* Toa */ +// /* SV orbit parameters */ +// double A,e,i0,OMG0,omg,M0,OMGd; +// double toas; /* Toa (s) in week */ +// double f0,f1; /* SV clock parameters (af0,af1) */ +// } alm_t; +typedef struct +{ /* GPS/QZS/GAL broadcast ephemeris type */ + int sat; /* satellite number */ + int iode, iodc; /* IODE,IODC */ + int sva; /* SV accuracy (URA index) */ + int svh; /* SV health (0:ok) */ + int week; /* GPS/QZS: gps week, GAL: galileo week */ + int code; /* GPS/QZS: code on L2 */ + /* GAL: data source defined as rinex 3.03 */ + /* BDS: data source (0:unknown,1:B1I,2:B1Q,3:B2I,4:B2Q,5:B3I,6:B3Q) */ + int flag; /* GPS/QZS: L2 P data flag */ + /* BDS: nav type (0:unknown,1:IGSO/MEO,2:GEO) */ + gtime_t toe, toc, ttr; /* Toe,Toc,T_trans */ + /* SV orbit parameters */ + /*toc??????????????????? time of clock + toe????????????????????? ????????????? time of ephemeris*/ + double A, e, i0, OMG0, omg, M0, deln, OMGd, idot; + double crc, crs, cuc, cus, cic, cis; + double toes; /* Toe (s) in week */ + double fit; /* fit interval (h) */ + double f0, f1, f2; /* SV clock parameters (af0,af1,af2) */ + double tgd[6]; /* group delay parameters */ + /* GPS/QZS:tgd[0]=TGD */ + /* GAL:tgd[0]=BGD_E1E5a,tgd[1]=BGD_E1E5b */ + /* CMP:tgd[0]=TGD_B1I ,tgd[1]=TGD_B2I/B2b,tgd[2]=TGD_B1Cp */ + /* tgd[3]=TGD_B2ap,tgd[4]=ISC_B1Cd ,tgd[5]=ISC_B2ad */ + double Adot, ndot; /* Adot,ndot for CNAV */ +} eph_t; +typedef struct +{ /* GLONASS broadcast ephemeris type */ + int sat; /* satellite number */ + int iode; /* IODE (0-6 bit of tb field) */ + int frq; /* satellite frequency number */ + int svh, sva, age; /* satellite health, accuracy, age of operation */ + gtime_t toe; /* epoch of epherides (gpst) */ + gtime_t tof; /* message frame time (gpst) */ + double pos[3]; /* satellite position (ecef) (m) */ + double vel[3]; /* satellite velocity (ecef) (m/s) */ + double acc[3]; /* satellite acceleration (ecef) (m/s^2) */ + double taun, gamn; /* SV clock bias (s)/relative freq bias */ + double dtaun; /* delay between L1 and L2 (s) */ +} geph_t; +// typedef struct { /* precise ephemeris type */ +// gtime_t time; /* time (GPST) */ +// int index; /* ephemeris index for multiple files */ +// double pos[MAXSAT][4]; /* satellite position/clock (ecef) (m|s) */ +// float std[MAXSAT][4]; /* satellite position/clock std (m|s) */ +// double vel[MAXSAT][4]; /* satellite velocity/clk-rate (m/s|s/s) */ +// float vst[MAXSAT][4]; /* satellite velocity/clk-rate std (m/s|s/s) */ +// float cov[MAXSAT][3]; /* satellite position covariance (m^2) */ +// float vco[MAXSAT][3]; /* satellite velocity covariance (m^2) */ +// } peph_t; +// typedef struct { /* precise clock type */ +// gtime_t time; /* time (GPST) */ +// int index; /* clock index for multiple files */ +// double clk[MAXSAT][1]; /* satellite clock (s) */ +// float std[MAXSAT][1]; /* satellite clock std (s) */ +// } pclk_t; +// typedef struct { /* SBAS ephemeris type */ +// int sat; /* satellite number */ +// gtime_t t0; /* reference epoch time (GPST) */ +// gtime_t tof; /* time of message frame (GPST) */ +// int sva; /* SV accuracy (URA index) */ +// int svh; /* SV health (0:ok) */ +// double pos[3]; /* satellite position (m) (ecef) */ +// double vel[3]; /* satellite velocity (m/s) (ecef) */ +// double acc[3]; /* satellite acceleration (m/s^2) (ecef) */ +// double af0,af1; /* satellite clock-offset/drift (s,s/s) */ +// } seph_t; +// typedef struct { /* NORAL TLE data type */ +// char name [32]; /* common name */ +// char alias[32]; /* alias name */ +// char satno[16]; /* satellilte catalog number */ +// char satclass; /* classification */ +// char desig[16]; /* international designator */ +// gtime_t epoch; /* element set epoch (UTC) */ +// double ndot; /* 1st derivative of mean motion */ +// double nddot; /* 2st derivative of mean motion */ +// double bstar; /* B* drag term */ +// int etype; /* element set type */ +// int eleno; /* element number */ +// double inc; /* orbit inclination (deg) */ +// double OMG; /* right ascension of ascending node (deg) */ +// double ecc; /* eccentricity */ +// double omg; /* argument of perigee (deg) */ +// double M; /* mean anomaly (deg) */ +// double n; /* mean motion (rev/day) */ +// int rev; /* revolution number at epoch */ +// } tled_t; +// typedef struct { /* NORAD TLE (two line element) type */ +// int n,nmax; /* number/max number of two line element data */ +// tled_t *data; /* NORAD TLE data */ +// } tle_t; +// typedef struct { /* TEC grid type */ +// gtime_t time; /* epoch time (GPST) */ +// int ndata[3]; /* TEC grid data size {nlat,nlon,nhgt} */ +// double rb; /* earth radius (km) */ +// double lats[3]; /* latitude start/interval (deg) */ +// double lons[3]; /* longitude start/interval (deg) */ +// double hgts[3]; /* heights start/interval (km) */ +// double *data; /* TEC grid data (tecu) */ +// float *rms; /* RMS values (tecu) */ +// } tec_t; +// typedef struct { /* SBAS message type */ +// int week,tow; /* receiption time */ +// uint8_t prn,rcv; /* SBAS satellite PRN,receiver number */ +// uint8_t msg[29]; /* SBAS message (226bit) padded by 0 */ +// } sbsmsg_t; +// typedef struct { /* SBAS messages type */ +// int n,nmax; /* number of SBAS messages/allocated */ +// sbsmsg_t *msgs; /* SBAS messages */ +// } sbs_t; +// typedef struct { /* SBAS fast correction type */ +// gtime_t t0; /* time of applicability (TOF) */ +// double prc; /* pseudorange correction (PRC) (m) */ +// double rrc; /* range-rate correction (RRC) (m/s) */ +// double dt; /* range-rate correction delta-time (s) */ +// int iodf; /* IODF (issue of date fast corr) */ +// int16_t udre; /* UDRE+1 */ +// int16_t ai; /* degradation factor indicator */ +// } sbsfcorr_t; +// typedef struct { /* SBAS long term satellite error correction type */ +// gtime_t t0; /* correction time */ +// int iode; /* IODE (issue of date ephemeris) */ +// double dpos[3]; /* delta position (m) (ecef) */ +// double dvel[3]; /* delta velocity (m/s) (ecef) */ +// double daf0,daf1; /* delta clock-offset/drift (s,s/s) */ +// } sbslcorr_t; +// typedef struct { /* SBAS satellite correction type */ +// int sat; /* satellite number */ +// sbsfcorr_t fcorr; /* fast correction */ +// sbslcorr_t lcorr; /* long term correction */ +// } sbssatp_t; +// typedef struct { /* SBAS satellite corrections type */ +// int iodp; /* IODP (issue of date mask) */ +// int nsat; /* number of satellites */ +// int tlat; /* system latency (s) */ +// sbssatp_t sat[MAXSAT]; /* satellite correction */ +// } sbssat_t; +// typedef struct { /* SBAS ionospheric correction type */ +// gtime_t t0; /* correction time */ +// int16_t lat,lon; /* latitude/longitude (deg) */ +// int16_t give; /* GIVI+1 */ +// float delay; /* vertical delay estimate (m) */ +// } sbsigp_t; +// typedef struct { /* IGP band type */ +// int16_t x; /* longitude/latitude (deg) */ +// const int16_t *y; /* latitudes/longitudes (deg) */ +// uint8_t bits; /* IGP mask start bit */ +// uint8_t bite; /* IGP mask end bit */ +// } sbsigpband_t; +// typedef struct { /* SBAS ionospheric corrections type */ +// int iodi; /* IODI (issue of date ionos corr) */ +// int nigp; /* number of igps */ +// sbsigp_t igp[MAXNIGP]; /* ionospheric correction */ +// } sbsion_t; +typedef struct +{ /* DGPS/GNSS correction type */ + gtime_t t0; /* correction time */ + double prc; /* pseudorange correction (PRC) (m) */ + double rrc; /* range rate correction (RRC) (m/s) */ + int iod; /* issue of data (IOD) */ + double udre; /* UDRE */ +} dgps_t; +// typedef struct { /* SSR correction type */ +// gtime_t t0[6]; /* epoch time (GPST) {eph,clk,hrclk,ura,bias,pbias} */ +// double udi[6]; /* SSR update interval (s) */ +// int iod[6]; /* iod ssr {eph,clk,hrclk,ura,bias,pbias} */ +// int iode; /* issue of data */ +// int iodcrc; /* issue of data crc for beidou/sbas */ +// int ura; /* URA indicator */ +// int refd; /* sat ref datum (0:ITRF,1:regional) */ +// double deph [3]; /* delta orbit {radial,along,cross} (m) */ +// double ddeph[3]; /* dot delta orbit {radial,along,cross} (m/s) */ +// double dclk [3]; /* delta clock {c0,c1,c2} (m,m/s,m/s^2) */ +// double hrclk; /* high-rate clock corection (m) */ +// float cbias[MAXCODE]; /* code biases (m) */ +// double pbias[MAXCODE]; /* phase biases (m) */ +// float stdpb[MAXCODE]; /* std-dev of phase biases (m) */ +// double yaw_ang,yaw_rate; /* yaw angle and yaw rate (deg,deg/s) */ +// uint8_t update; /* update flag (0:no update,1:update) */ +// } ssr_t; +typedef struct +{ /* navigation data type */ + int n, nmax; /* number of broadcast ephemeris */ + int ng, ngmax; /* number of glonass ephemeris */ + int ns, nsmax; /* number of sbas ephemeris */ + int ne, nemax; /* number of precise ephemeris */ + int nc, ncmax; /* number of precise clock */ + int na, namax; /* number of almanac data */ + // int nt,ntmax; /* number of tec grid data */ + eph_t *eph; /* GPS/QZS/GAL/BDS/IRN ephemeris */ + geph_t *geph; /* GLONASS ephemeris */ + // seph_t *seph; /* SBAS ephemeris */ + // peph_t *peph; /* precise ephemeris */ + // pclk_t *pclk; /* precise clock */ + // alm_t *alm; /* almanac data */ + // tec_t *tec; /* tec grid data */ + erp_t erp; /* earth rotation parameters */ + double utc_gps[8]; /* GPS delta-UTC parameters {A0,A1,Tot,WNt,dt_LS,WN_LSF,DN,dt_LSF} */ + // double utc_glo[8]; /* GLONASS UTC time parameters {tau_C,tau_GPS} */ + // double utc_gal[8]; /* Galileo UTC parameters */ + // double utc_qzs[8]; /* QZS UTC parameters */ + // double utc_cmp[8]; /* BeiDou UTC parameters */ + // double utc_irn[9]; /* IRNSS UTC parameters {A0,A1,Tot,...,dt_LSF,A2} */ + // double utc_sbs[4]; /* SBAS UTC parameters */ + double ion_gps[8]; /* GPS iono model parameters {a0,a1,a2,a3,b0,b1,b2,b3} */ + // double ion_gal[4]; /* Galileo iono model parameters {ai0,ai1,ai2,0} */ + // double ion_qzs[8]; /* QZSS iono model parameters {a0,a1,a2,a3,b0,b1,b2,b3} */ + // double ion_cmp[8]; /* BeiDou iono model parameters {a0,a1,a2,a3,b0,b1,b2,b3} */ + // double ion_irn[8]; /* IRNSS iono model parameters {a0,a1,a2,a3,b0,b1,b2,b3} */ + int glo_fcn[32]; /* GLONASS FCN + 8 */ + double cbias[MAXSAT][3]; /* satellite DCB (0:P1-P2,1:P1-C1,2:P2-C2) (m) */ + double rbias[MAXRCV][2][3]; /* receiver DCB (0:P1-P2,1:P1-C1,2:P2-C2) (m) */ + // pcv_t pcvs[MAXSAT]; /* satellite antenna pcv */ + // sbssat_t sbssat; /* SBAS satellite corrections */ + // sbsion_t sbsion[MAXBAND+1]; /* SBAS ionosphere corrections */ + // dgps_t dgps[MAXSAT]; /* DGPS corrections */ + // ssr_t ssr[MAXSAT]; /* SSR corrections */ +} nav_t; +typedef struct +{ /* station parameter type */ + char name[MAXANT]; /* marker name */ + char marker[MAXANT]; /* marker number */ + char antdes[MAXANT]; /* antenna descriptor */ + char antsno[MAXANT]; /* antenna serial number */ + char rectype[MAXANT]; /* receiver type descriptor */ + char recver[MAXANT]; /* receiver firmware version */ + char recsno[MAXANT]; /* receiver serial number */ + int antsetup; /* antenna setup id */ + int itrf; /* ITRF realization year */ + int deltype; /* antenna delta type (0:enu,1:xyz) */ + double pos[3]; /* station position (ecef) (m) */ + double del[3]; /* antenna position delta (e/n/u or x/y/z) (m) */ + double hgt; /* antenna height (m) */ + int glo_cp_align; /* GLONASS code-phase alignment (0:no,1:yes) */ + double glo_cp_bias[4]; /* GLONASS code-phase biases {1C,1P,2C,2P} (m) */ +} sta_t; +typedef struct +{ /* solution type */ + gtime_t time; /* time (GPST) */ + gtime_t eventime; /* time of event (GPST) */ + double rr[6]; /* position/velocity (m|m/s) */ + /* {x,y,z,vx,vy,vz} or {e,n,u,ve,vn,vu} */ + float qr[6]; /* position variance/covariance (m^2) */ + /* {c_xx,c_yy,c_zz,c_xy,c_yz,c_zx} or */ + /* {c_ee,c_nn,c_uu,c_en,c_nu,c_ue} */ + float qv[6]; /* velocity variance/covariance (m^2/s^2) */ + double dtr[6]; /* receiver clock bias to time systems (s) */ + uint8_t type; /* type (0:xyz-ecef,1:enu-baseline) */ + uint8_t stat; /* solution status (SOLQ_???) */ + uint8_t ns; /* number of valid satellites */ + float age; /* age of differential (s) */ + float ratio; /* AR ratio factor for valiation */ + float prev_ratio1; /* previous initial AR ratio factor for validation */ + float prev_ratio2; /* previous final AR ratio factor for validation */ + float thres; /* AR ratio threshold for valiation */ +} sol_t; +// typedef struct +// { /* solution buffer type */ +// int n, nmax; /* number of solution/max number of buffer */ +// int cyclic; /* cyclic buffer flag */ +// int start, end; /* start/end index */ +// gtime_t time; /* current solution time */ +// sol_t *data; /* solution data */ +// double rb[3]; /* reference position {x,y,z} (ecef) (m) */ +// uint8_t buff[MAXSOLMSG + 1]; /* message buffer */ +// int nb; /* number of byte in message buffer */ +// } solbuf_t; +typedef struct +{ /* solution status type */ + gtime_t time; /* time (GPST) */ + uint8_t sat; /* satellite number */ + uint8_t frq; /* frequency (1:L1,2:L2,...) */ + float az, el; /* azimuth/elevation angle (rad) */ + float resp; /* pseudorange residual (m) */ + float resc; /* carrier-phase residual (m) */ + uint8_t flag; /* flags: (vsat<<5)+(slip<<3)+fix */ + uint16_t snr; /* signal strength (*SNR_UNIT dBHz) */ + uint16_t lock; /* lock counter */ + uint16_t outc; /* outage counter */ + uint16_t slipc; /* slip counter */ + uint16_t rejc; /* reject counter */ +} solstat_t; +typedef struct +{ /* solution status buffer type */ + int n, nmax; /* number of solution/max number of buffer */ + solstat_t *data; /* solution status data */ +} solstatbuf_t; +typedef struct +{ /* RTCM control struct type */ + int staid; /* station id */ + int stah; /* station health */ + int seqno; /* sequence number for rtcm 2 or iods msm */ + // int outtype; /* output message type */ + gtime_t time; /* message time */ + gtime_t time_s; /* message start time */ + obs_t obs; /* observation data (uncorrected) */ + nav_t nav; /* satellite ephemerides */ + sta_t sta; /* station parameters */ + // dgps_t *dgps; /* output of dgps corrections */ + // ssr_t ssr[MAXSAT]; /* output of ssr corrections */ + // char msg[128]; /* special message */ + // char msgtype[256]; /* last message type */ + char msmtype[7][128]; /* msm signal types */ + int obsflag; /* obs data complete flag (1:ok,0:not complete) */ + int ephsat; /* input ephemeris satellite number */ + int ephset; /* input ephemeris set (0-1) */ + double cp[MAXSAT][NFREQ + NEXOBS]; /* carrier-phase measurement */ + uint16_t lock[MAXSAT][NFREQ + NEXOBS]; /* lock time */ + uint16_t loss[MAXSAT][NFREQ + NEXOBS]; /* loss of lock count */ + gtime_t lltime[MAXSAT][NFREQ + NEXOBS]; /* last lock time */ + int nbyte; /* number of bytes in message buffer */ + int nbit; /* number of bits in word buffer */ + int len; /* message length (bytes) */ + uint8_t buff[1200]; /* message buffer */ + // uint32_t word; /* word buffer for rtcm 2 */ + // uint32_t nmsg2[100]; /* message count of RTCM 2 (1-99:1-99,0:other) */ + uint32_t nmsg3[400]; /* message count of RTCM 3 (1-299:1001-1299,300-329:4070-4099,0:ohter) */ + // char opt[256]; /* RTCM dependent options */ +} rtcm_t; +// typedef struct { /* RINEX control struct type */ +// gtime_t time; /* message time */ +// double ver; /* RINEX version */ +// char type; /* RINEX file type ('O','N',...) */ +// int sys; /* navigation system */ +// int tsys; /* time system */ +// char tobs[8][MAXOBSTYPE][4]; /* rinex obs types */ +// obs_t obs; /* observation data */ +// nav_t nav; /* navigation data */ +// sta_t sta; /* station info */ +// int ephsat; /* input ephemeris satellite number */ +// int ephset; /* input ephemeris set (0-1) */ +// char opt[256]; /* rinex dependent options */ +// } rnxctr_t; +// typedef struct { /* download URL type */ +// char type[32]; /* data type */ +// char path[1024]; /* URL path */ +// char dir [1024]; /* local directory */ +// double tint; /* time interval (s) */ +// } url_t; +typedef struct +{ /* option type */ + const char *name; /* option name */ + int format; /* option format (0:int,1:double,2:string,3:enum) */ + void *var; /* pointer to option variable */ + const char *comment; /* option comment/enum labels/unit */ +} opt_t; +typedef struct +{ /* SNR mask type */ + int ena[2]; /* enable flag {rover,base} */ + double mask[NFREQ][9]; /* mask (dBHz) at 5,10,...85 deg */ +} snrmask_t; +typedef struct +{ /* processing options type */ + int mode; /* positioning mode (PMODE_???) */ + int soltype; /* solution type (0:forward,1:backward,2:combined) */ + int nf; /* number of frequencies (1:L1,2:L1+L2,3:L1+L2+L5) */ + int navsys; /* navigation system */ + double elmin; /* elevation mask angle (rad) */ + snrmask_t snrmask; /* SNR mask */ + int sateph; /* satellite ephemeris/clock (EPHOPT_???) */ + int modear; /* AR mode (0:off,1:continuous,2:instantaneous,3:fix and hold,4:ppp-ar) */ + int glomodear; /* GLONASS AR mode (0:off,1:on,2:auto cal,3:ext cal) */ + int gpsmodear; /* GPS AR mode, debug/learning only (0:off,1:on) */ + int bdsmodear; /* BeiDou AR mode (0:off,1:on) */ + int arfilter; /* AR filtering to reject bad sats (0:off,1:on) */ + int maxout; /* obs outage count to reset bias */ + int minlock; /* min lock count to fix ambiguity */ + int minfixsats; /* min sats to fix integer ambiguities */ + int minholdsats; /* min sats to hold integer ambiguities */ + int mindropsats; /* min sats to drop sats in AR */ + int minfix; /* min fix count to hold ambiguity */ + int armaxiter; /* max iteration to resolve ambiguity */ + int ionoopt; /* ionosphere option (IONOOPT_???) */ + int tropopt; /* troposphere option (TROPOPT_???) */ + int dynamics; /* dynamics model (0:none,1:velociy,2:accel) */ + int tidecorr; /* earth tide correction (0:off,1:solid,2:solid+otl+pole) */ + int niter; /* number of filter iteration */ + int codesmooth; /* code smoothing window size (0:none) */ + int intpref; /* interpolate reference obs (for post mission) */ + int sbascorr; /* SBAS correction options */ + int sbassatsel; /* SBAS satellite selection (0:all) */ + int rovpos; /* rover position for fixed mode */ + int refpos; /* base position for relative mode */ + /* (0:pos in prcopt, 1:average of single pos, */ + /* 2:read from file, 3:rinex header, 4:rtcm pos) */ + double eratio[NFREQ]; /* code/phase error ratio */ + double err[8]; /* observation error terms */ + /* [reserved,constant,elevation,baseline,doppler,snr-max,snr, rcv_std] */ + double std[3]; /* initial-state std [0]bias,[1]iono [2]trop */ + double prn[6]; /* process-noise std [0]bias,[1]iono [2]trop [3]acch [4]accv [5] pos */ + double sclkstab; /* satellite clock stability (sec/sec) */ + double thresar[8]; /* AR validation threshold */ + double elmaskar; /* elevation mask of AR for rising satellite (deg) */ + double elmaskhold; /* elevation mask to hold ambiguity (deg) */ + double thresslip; /* slip threshold of geometry-free phase (m) */ + double thresdop; /* slip threshold of doppler (m) */ + double varholdamb; /* variance for fix-and-hold psuedo measurements (cycle^2) */ + double gainholdamb; /* gain used for GLO and SBAS sats to adjust ambiguity */ + double maxtdiff; /* max difference of time (sec) */ + double maxinno; /* reject threshold of innovation (m) */ + double maxgdop; /* reject threshold of gdop */ + double baseline[2]; /* baseline length constraint {const,sigma} (m) */ + double ru[3]; /* rover position for fixed mode {x,y,z} (ecef) (m) */ + double rb[3]; /* base position for relative mode {x,y,z} (ecef) (m) */ + char anttype[2][MAXANT]; /* antenna types {rover,base} */ + double antdel[2][3]; /* antenna delta {{rov_e,rov_n,rov_u},{ref_e,ref_n,ref_u}} */ + // pcv_t pcvr[2]; /* receiver antenna parameters {rov,base} */ + uint8_t exsats[MAXSAT]; /* excluded satellites (1:excluded,2:included) */ + int maxaveep; /* max averaging epoches */ + int initrst; /* initialize by restart */ + int outsingle; /* output single by dgps/float/fix/ppp outage */ + char rnxopt[2][256]; /* rinex options {rover,base} */ + int posopt[6]; /* positioning options */ + int syncsol; /* solution sync mode (0:off,1:on) */ + double odisp[2][6 * 11]; /* ocean tide loading parameters {rov,base} */ + int freqopt; /* disable L2-AR */ + char pppopt[256]; /* ppp option */ +} prcopt_t; +typedef struct +{ /* solution options type */ + int posf; /* solution format (SOLF_???) */ + int times; /* time system (TIMES_???) */ + int timef; /* time format (0:sssss.s,1:yyyy/mm/dd hh:mm:ss.s) */ + int timeu; /* time digits under decimal point */ + int degf; /* latitude/longitude format (0:ddd.ddd,1:ddd mm ss) */ + int outhead; /* output header (0:no,1:yes) */ + int outopt; /* output processing options (0:no,1:yes) */ + int outvel; /* output velocity options (0:no,1:yes) */ + int datum; /* datum (0:WGS84,1:Tokyo) */ + int height; /* height (0:ellipsoidal,1:geodetic) */ + int geoid; /* geoid model (0:EGM96,1:JGD2000) */ + int solstatic; /* solution of static mode (0:all,1:single) */ + int sstat; /* solution statistics level (0:off,1:states,2:residuals) */ + int trace; /* debug trace level (0:off,1-5:debug) */ + double nmeaintv[2]; /* nmea output interval (s) (<0:no,0:all) */ + /* nmeaintv[0]:gprmc,gpgga,nmeaintv[1]:gpgsv */ + char sep[64]; /* field separator */ + char prog[64]; /* program name */ + double maxsolstd; /* max std-dev for solution output (m) (0:all) */ +} solopt_t; +// typedef struct { /* file options type */ +// char satantp[MAXSTRPATH]; /* satellite antenna parameters file */ +// char rcvantp[MAXSTRPATH]; /* receiver antenna parameters file */ +// char stapos [MAXSTRPATH]; /* station positions file */ +// char geoid [MAXSTRPATH]; /* external geoid data file */ +// char iono [MAXSTRPATH]; /* ionosphere data file */ +// char dcb [MAXSTRPATH]; /* dcb data file */ +// char eop [MAXSTRPATH]; /* eop data file */ +// char blq [MAXSTRPATH]; /* ocean tide loading blq file */ +// char tempdir[MAXSTRPATH]; /* ftp/http temporaly directory */ +// char geexe [MAXSTRPATH]; /* google earth exec file */ +// char solstat[MAXSTRPATH]; /* solution statistics file */ +// char trace [MAXSTRPATH]; /* debug trace file */ +// } filopt_t; +// typedef struct { /* RINEX options type */ +// gtime_t ts,te; /* time start/end */ +// double tint; /* time interval (s) */ +// double ttol; /* time tolerance (s) */ +// double tunit; /* time unit for multiple-session (s) */ +// int rnxver; /* RINEX version (x100) */ +// int navsys; /* navigation system */ +// int obstype; /* observation type */ +// int freqtype; /* frequency type */ +// char mask[7][64]; /* code mask {GPS,GLO,GAL,QZS,SBS,CMP,IRN} */ +// char staid [32]; /* station id for rinex file name */ +// char prog [32]; /* program */ +// char runby [32]; /* run-by */ +// char marker[64]; /* marker name */ +// char markerno[32]; /* marker number */ +// char markertype[32]; /* marker type (ver.3) */ +// char name[2][32]; /* observer/agency */ +// char rec [3][32]; /* receiver #/type/vers */ +// char ant [3][32]; /* antenna #/type */ +// double apppos[3]; /* approx position x/y/z */ +// double antdel[3]; /* antenna delta h/e/n */ +// double glo_cp_bias[4]; /* GLONASS code-phase biases (m) */ +// char comment[MAXCOMMENT][64]; /* comments */ +// char rcvopt[256]; /* receiver dependent options */ +// uint8_t exsats[MAXSAT]; /* excluded satellites */ +// int glofcn[32]; /* glonass fcn+8 */ +// int outiono; /* output iono correction */ +// int outtime; /* output time system correction */ +// int outleaps; /* output leap seconds */ +// int autopos; /* auto approx position */ +// int phshift; /* phase shift correction */ +// int halfcyc; /* half cycle correction */ +// int sep_nav; /* separated nav files */ +// gtime_t tstart; /* first obs time */ +// gtime_t tend; /* last obs time */ +// gtime_t trtcm; /* approx log start time for rtcm */ +// char tobs[7][MAXOBSTYPE][4]; /* obs types {GPS,GLO,GAL,QZS,SBS,CMP,IRN} */ +// double shift[7][MAXOBSTYPE]; /* phase shift (cyc) {GPS,GLO,GAL,QZS,SBS,CMP,IRN} */ +// int nobs[7]; /* number of obs types {GPS,GLO,GAL,QZS,SBS,CMP,IRN} */ +// } rnxopt_t; +typedef struct +{ /* satellite status type */ + uint8_t sys; /* navigation system */ + uint8_t vs; /* valid satellite flag single */ + double azel[2]; /* azimuth/elevation angles {az,el} (rad) */ + double resp[NFREQ]; /* residuals of pseudorange (m) */ + double resc[NFREQ]; /* residuals of carrier-phase (m) */ + double icbias[NFREQ]; /* glonass IC bias (cycles) */ + uint8_t vsat[NFREQ]; /* valid satellite flag */ + uint16_t snr_rover[NFREQ]; /* rover signal strength (0.25 dBHz) */ + uint16_t snr_base[NFREQ]; /* base signal strength (0.25 dBHz) */ + uint8_t fix[NFREQ]; /* ambiguity fix flag (1:fix,2:float,3:hold) */ + uint8_t slip[NFREQ]; /* cycle-slip flag */ + uint8_t half[NFREQ]; /* half-cycle valid flag */ + int lock[NFREQ]; /* lock counter of phase */ + uint32_t outc[NFREQ]; /* obs outage counter of phase */ + uint32_t slipc[NFREQ]; /* cycle-slip counter */ + uint32_t rejc[NFREQ]; /* reject counter */ + double gf[NFREQ - 1]; /* geometry-free phase (m) */ + double mw[NFREQ - 1]; /* MW-LC (m) */ + double phw; /* phase windup (cycle) */ + gtime_t pt[2][NFREQ]; /* previous carrier-phase time */ + double ph[2][NFREQ]; /* previous carrier-phase observable (cycle) */ +} ssat_t; +typedef struct +{ /* ambiguity control type */ + gtime_t epoch[4]; /* last epoch */ + int n[4]; /* number of epochs */ + double LC[4]; /* linear combination average */ + double LCv[4]; /* linear combination variance */ + int fixcnt; /* fix count */ + char flags[MAXSAT]; /* fix flags */ +} ambc_t; +// RTK??????? +typedef struct +{ /* RTK control/result type */ + sol_t sol; /* RTK solution */ + double rb[6]; /* base position/velocity (ecef) (m|m/s) */ + int nx, na; /* number of float states/fixed states */ + double tt; /* time difference between current and previous (s) */ + double *x, *P; /* float states and their covariance */ + double *xa, *Pa; /* fixed states and their covariance */ + int nfix; /* number of continuous fixes of ambiguity */ + int excsat; /* index of next satellite to be excluded for partial ambiguity resolution */ + int nb_ar; /* number of ambiguities used for AR last epoch */ + double com_bias; /* phase bias common between all sats (used to be distributed to all sats */ + char holdamb; /* set if fix-and-hold has occurred at least once */ + ambc_t ambc[MAXSAT]; /* ambiguity control */ + ssat_t ssat[MAXSAT]; /* satellite status */ + int neb; /* bytes in error message buffer */ + // char errbuf[MAXERRMSG]; /* error message buffer */ + prcopt_t opt; /* processing options */ + int initial_mode; /* initial positioning mode */ +} rtk_t; +// typedef struct { /* receiver raw data control type */ +// gtime_t time; /* message time */ +// gtime_t tobs[MAXSAT][NFREQ+NEXOBS]; /* observation data time */ +// obs_t obs; /* observation data */ +// obs_t obuf; /* observation data buffer */ +// nav_t nav; /* satellite ephemerides */ +// sta_t sta; /* station parameters */ +// int ephsat; /* update satelle of ephemeris (0:no satellite) */ +// int ephset; /* update set of ephemeris (0-1) */ +// // sbsmsg_t sbsmsg; /* SBAS message */ +// char msgtype[256]; /* last message type */ +// uint8_t subfrm[MAXSAT][380]; /* subframe buffer */ +// double lockt[MAXSAT][NFREQ+NEXOBS]; /* lock time (s) */ +// unsigned char lockflag[MAXSAT][NFREQ+NEXOBS]; /* used for carrying forward cycle slip */ +// double icpp[MAXSAT],off[MAXSAT],icpc; /* carrier params for ss2 */ +// double prCA[MAXSAT],dpCA[MAXSAT]; /* L1/CA pseudrange/doppler for javad */ +// uint8_t halfc[MAXSAT][NFREQ+NEXOBS]; /* half-cycle add flag */ +// char freqn[MAXOBS]; /* frequency number for javad */ +// int nbyte; /* number of bytes in message buffer */ +// int len; /* message length (bytes) */ +// int iod; /* issue of data */ +// int tod; /* time of day (ms) */ +// int tbase; /* time base (0:gpst,1:utc(usno),2:glonass,3:utc(su) */ +// int flag; /* general purpose flag */ +// int outtype; /* output message type */ +// uint8_t buff[MAXRAWLEN]; /* message buffer */ +// char opt[256]; /* receiver dependent options */ +// int format; /* receiver stream format */ +// void *rcv_data; /* receiver dependent data */ +// } raw_t; +typedef struct +{ /* stream type */ + int type; /* type (STR_???) */ + int mode; /* mode (STR_MODE_?) */ + int state; /* state (-1:error,0:close,1:open) */ + uint32_t inb, inr; /* input bytes/rate */ + uint32_t outb, outr; /* output bytes/rate */ + uint32_t tick_i; /* input tick tick */ + uint32_t tick_o; /* output tick */ + uint32_t tact; /* active tick */ + uint32_t inbt, outbt; /* input/output bytes at tick */ +// lock_t lock; /* lock flag */ + void *port; /* type dependent port control struct */ + char path[MAXSTRPATH]; /* stream path */ + char msg[MAXSTRMSG]; /* stream message */ +} stream_t; +// typedef struct { /* stream converter type */ +// int itype,otype; /* input and output stream type */ +// int nmsg; /* number of output messages */ +// int msgs[32]; /* output message types */ +// double tint[32]; /* output message intervals (s) */ +// uint32_t tick[32]; /* cycle tick of output message */ +// int ephsat[32]; /* satellites of output ephemeris */ +// int stasel; /* station info selection (0:remote,1:local) */ +// rtcm_t rtcm; /* rtcm input data buffer */ +// raw_t raw; /* raw input data buffer */ +// rtcm_t out; /* rtcm output data buffer */ +// } strconv_t; +// typedef struct { /* stream server type */ +// int state; /* server state (0:stop,1:running) */ +// int cycle; /* server cycle (ms) */ +// int buffsize; /* input/monitor buffer size (bytes) */ +// int nmeacycle; /* NMEA request cycle (ms) (0:no) */ +// int relayback; /* relay back of output streams (0:no) */ +// int nstr; /* number of streams (1 input + (nstr-1) outputs */ +// int npb; /* data length in peek buffer (bytes) */ +// char cmds_periodic[16][MAXRCVCMD]; /* periodic commands */ +// double nmeapos[3]; /* NMEA request position (ecef) (m) */ +// uint8_t *buff; /* input buffers */ +// uint8_t *pbuf; /* peek buffer */ +// uint32_t tick; /* start tick */ +// stream_t stream[16]; /* input/output streams */ +// stream_t strlog[16]; /* return log streams */ +// // strconv_t *conv[16]; /* stream converter */ +// thread_t thread; /* server thread */ +// lock_t lock; /* lock flag */ +// } strsvr_t; +typedef struct +{ /* RTK server type */ + int state; /* server state (0:stop,1:running) */ + int cycle; /* processing cycle (ms) */ + int nmeacycle; /* NMEA request cycle (ms) (0:no req) */ + int nmeareq; /* NMEA request (0:no,1:nmeapos,2:single sol) */ + double nmeapos[3]; /* NMEA request position (ecef) (m) */ + int buffsize; /* input buffer size (bytes) */ + int format[2]; /* input format {rov,base} */ + solopt_t solopt[2]; /* output solution options {sol1,sol2} */ + int navsel; /* ephemeris select (0:all,1:rover,2:base,3) */ + int nsbs; /* number of sbas message */ + int nsol; /* number of solution buffer */ + rtk_t rtk; /* RTK control/result struct */ + int nb[2]; /* bytes in input buffers {rov,base} */ + int nsb[2]; /* bytes in soulution buffers */ + int npb[2]; /* bytes in input peek buffers */ + uint8_t *buff[2]; /* input buffers {rov,base} */ + uint8_t *sbuf[2]; /* output buffers {sol1,sol2} */ + uint8_t *pbuf[2]; /* peek buffers {rov,base} */ + sol_t solbuf[MAXSOLBUF]; /* solution buffer */ + uint32_t nmsg[2][10]; /* input message counts */ + // raw_t raw [2]; /* receiver raw control {rov,base} */ + rtcm_t rtcm[2]; /* RTCM control {rov,base} */ + // gtime_t ftime[2]; /* download time {rov,base} */ + // char files[2][MAXSTRPATH]; /* download paths {rov,base} */ + obs_t obs[2][MAXOBSBUF]; /* observation data {rov,base} */ + nav_t nav; /* navigation data */ + // sbsmsg_t sbsmsg[MAXSBSMSG]; /* SBAS message buffer */ + stream_t stream[8]; /* streams {rov,base,corr,sol1,sol2,logr,logb,logc} */ + // stream_t *moni; /* monitor stream */ + uint32_t tick; /* start tick */ +// thread_t thread; /* server thread */ + int cputime; /* CPU time (ms) for a processing cycle */ + int prcout; /* missing observation data count */ + int nave; /* number of averaging base pos */ + double rb_ave[3]; /* averaging base pos */ + // char cmds_periodic[2][MAXRCVCMD]; /* periodic commands */ + // char cmd_reset[MAXRCVCMD]; /* reset command */ + double bl_reset; /* baseline length to reset (km) */ +// lock_t lock; /* lock flag */ +} rtksvr_t; +// typedef struct { /* GIS data point type */ +// double pos[3]; /* point data {lat,lon,height} (rad,m) */ +// } gis_pnt_t; +// typedef struct { /* GIS data polyline type */ +// int npnt; /* number of points */ +// double bound[4]; /* boundary {lat0,lat1,lon0,lon1} */ +// double *pos; /* position data (3 x npnt) */ +// } gis_poly_t; +// typedef struct { /* GIS data polygon type */ +// int npnt; /* number of points */ +// double bound[4]; /* boundary {lat0,lat1,lon0,lon1} */ +// double *pos; /* position data (3 x npnt) */ +// } gis_polygon_t; +// typedef struct gisd_tag { /* GIS data list type */ +// int type; /* data type (1:point,2:polyline,3:polygon) */ +// void *data; /* data body */ +// struct gisd_tag *next; /* pointer to next */ +// } gisd_t; +// typedef struct { /* GIS type */ +// char name[MAXGISLAYER][256]; /* name */ +// int flag[MAXGISLAYER]; /* flag */ +// gisd_t *data[MAXGISLAYER]; /* gis data list */ +// double bound[4]; /* boundary {lat0,lat1,lon0,lon1} */ +// } gis_t; +typedef void fatalfunc_t(const char *); /* fatal callback function type */ +/* global variables ----------------------------------------------------------*/ +extern const double chisqr[]; /* chi-sqr(n) table (alpha=0.001) */ +extern const prcopt_t prcopt_default; /* default positioning options */ +extern const solopt_t solopt_default; /* default solution output options */ +extern const char *formatstrs[]; /* stream format strings */ +extern opt_t sysopts[]; /* system options table */ +/* satellites, systems, codes functions --------------------------------------*/ + int satno(int sys, int prn); + int satsys(int sat, int *prn); + int satid2no(const char *id); + void satno2id(int sat, char *id); + uint8_t obs2code(const char *obs); + char *code2obs(uint8_t code); + double code2freq(int sys, uint8_t code, int fcn); + double sat2freq(int sat, uint8_t code, const nav_t *nav); + int code2idx(int sys, uint8_t code); + int satexclude(int sat, double var, int svh, const prcopt_t *opt); + int testsnr(int base, int freq, double el, double snr, + const snrmask_t *mask); + void setcodepri(int sys, int idx, const char *pri); + int getcodepri(int sys, uint8_t code, const char *opt); +/* matrix and vector functions -----------------------------------------------*/ + double *mat(int n, int m); + int *imat(int n, int m); + double *zeros(int n, int m); + double *eye(int n); + double dot(const double *a, const double *b, int n); + double norm(const double *a, int n); + void cross3(const double *a, const double *b, double *c); + int normv3(const double *a, double *b); + void matcpy(double *A, const double *B, int n, int m); + void matmul(const char *tr, int n, int k, int m, double alpha, + const double *A, const double *B, double beta, double *C); + int matinv(double *A, int n); + int solve(const char *tr, const double *A, const double *Y, int n, + int m, double *X); + int lsq(const double *A, const double *y, int n, int m, double *x, + double *Q); + int filter(double *x, double *P, const double *H, const double *v, + const double *R, int n, int m); + int smoother(const double *xf, const double *Qf, const double *xb, + const double *Qb, int n, double *xs, double *Qs); + void matprint(const double *A, int n, int m, int p, int q); + void matfprint(const double *A, int n, int m, int p, int q, FILE *fp); + void add_fatal(fatalfunc_t *func); +/* time and string functions -------------------------------------------------*/ + double str2num(const char *s, int i, int n); + int str2time(const char *s, int i, int n, gtime_t *t); + void time2str(gtime_t t, char *str, int n); + gtime_t epoch2time(const double *ep); + void time2epoch(gtime_t t, double *ep); + void time2epoch_n(gtime_t t, double *ep, int n); + gtime_t gpst2time(int week, double sec); + double time2gpst(gtime_t t, int *week); + gtime_t gst2time(int week, double sec); + double time2gst(gtime_t t, int *week); + gtime_t bdt2time(int week, double sec); + double time2bdt(gtime_t t, int *week); + char *time_str(gtime_t t, int n); + gtime_t timeadd(gtime_t t, double sec); + double timediff(gtime_t t1, gtime_t t2); + gtime_t gpst2utc(gtime_t t); + gtime_t utc2gpst(gtime_t t); + gtime_t gpst2bdt(gtime_t t); + gtime_t bdt2gpst(gtime_t t); + gtime_t timeget(void); + void timeset(gtime_t t); + void timereset(void); + double time2doy(gtime_t t); + double utc2gmst(gtime_t t, double ut1_utc); + int read_leaps(const char *file); + int adjgpsweek(int week); + uint32_t tickget(void); + void sleepms(int ms); + int reppath(const char *path, char *rpath, gtime_t time, const char *rov, + const char *base); + int reppaths(const char *path, char *rpaths[], int nmax, gtime_t ts, + gtime_t te, const char *rov, const char *base); +/* coordinates transformation ------------------------------------------------*/ + void ecef2pos(const double *r, double *pos); + void pos2ecef(const double *pos, double *r); + void ecef2enu(const double *pos, const double *r, double *e); + void enu2ecef(const double *pos, const double *e, double *r); + void covenu(const double *pos, const double *P, double *Q); + void covecef(const double *pos, const double *Q, double *P); + void xyz2enu(const double *pos, double *E); + void eci2ecef(gtime_t tutc, const double *erpv, double *U, double *gmst); + void deg2dms(double deg, double *dms, int ndec); + double dms2deg(const double *dms); +/* input and output functions ------------------------------------------------*/ +// void readpos(const char *file, const char *rcv, double *pos); + int sortobs(obs_t *obs); + void uniqnav(nav_t *nav); + int screent(gtime_t time, gtime_t ts, gtime_t te, double tint); + void freeobs(obs_t *obs); + void freenav(nav_t *nav, int opt); + int geterp(const erp_t *erp, gtime_t time, double *val); +// int readnav(const char *file, nav_t *nav); +// int savenav(const char *file, const nav_t *nav); +// int readblq(const char *file, const char *sta, double *odisp); +// int readerp(const char *file, erp_t *erp); +/* debug trace functions -----------------------------------------------------*/ + void traceopen(const char *file); + void traceclose(void); + void tracelevel(int level); + void trace(int level, const char *format, ...); + void tracet(int level, const char *format, ...); + void tracemat(int level, const double *A, int n, int m, int p, int q); + void traceobs(int level, const obsd_t *obs, int n); + void tracenav(int level, const nav_t *nav); + void tracegnav(int level, const nav_t *nav); + void tracehnav(int level, const nav_t *nav); + void tracepeph(int level, const nav_t *nav); + void tracepclk(int level, const nav_t *nav); + void traceb(int level, const uint8_t *p, int n); + int gettracelevel(void); +/* platform dependent functions ----------------------------------------------*/ + int execcmd(const char *cmd); + int expath(const char *path, char *paths[], int nmax); + void createdir(const char *path); +/* positioning models --------------------------------------------------------*/ + double satazel(const double *pos, const double *e, double *azel); + double geodist(const double *rs, const double *rr, double *e); + void dops(int ns, const double *azel, double elmin, double *dop); +/* atmosphere models ---------------------------------------------------------*/ + double ionmodel(gtime_t t, const double *ion, const double *pos, + const double *azel); + double ionmapf(const double *pos, const double *azel); + double ionppp(const double *pos, const double *azel, double re, + double hion, double *pppos); + double tropmodel(gtime_t time, const double *pos, const double *azel, + double humi); + double tropmapf(gtime_t time, const double *pos, const double *azel, + double *mapfw); + int iontec(gtime_t time, const nav_t *nav, const double *pos, + const double *azel, int opt, double *delay, double *var); +// void readtec(const char *file, nav_t *nav, int opt); + int ionocorr(gtime_t time, const nav_t *nav, int sat, const double *pos, + const double *azel, int ionoopt, double *ion, double *var); + int tropcorr(gtime_t time, const nav_t *nav, const double *pos, + const double *azel, int tropopt, double *trp, double *var); +/* antenna models ------------------------------------------------------------*/ +// int readpcv(const char *file, pcvs_t *pcvs); +// pcv_t *searchpcv(int sat, const char *type, gtime_t time, +// const pcvs_t *pcvs); +// void antmodel(const pcv_t *pcv, const double *del, const double *azel, +// int opt, double *dant); +// void antmodel_s(const pcv_t *pcv, double nadir, double *dant); +/* earth tide models ---------------------------------------------------------*/ + void sunmoonpos(gtime_t tutc, const double *erpv, double *rsun, + double *rmoon, double *gmst); + void tidedisp(gtime_t tutc, const double *rr, int opt, const erp_t *erp, + const double *odisp, double *dr); +/* geiod models --------------------------------------------------------------*/ + int opengeoid(int model, const char *file); + void closegeoid(void); + double geoidh(const double *pos); +/* datum transformation ------------------------------------------------------*/ +// int loaddatump(const char *file); +// int tokyo2jgd(double *pos); +// int jgd2tokyo(double *pos); +/* ephemeris and clock functions ---------------------------------------------*/ + double eph2clk(gtime_t time, const eph_t *eph); + double geph2clk(gtime_t time, const geph_t *geph); +// double seph2clk(gtime_t time, const seph_t *seph); + void eph2pos(gtime_t time, const eph_t *eph, double *rs, double *dts, + double *var); + void geph2pos(gtime_t time, const geph_t *geph, double *rs, double *dts, + double *var); +// void seph2pos(gtime_t time, const seph_t *seph, double *rs, double *dts, +// double *var); +// int peph2pos(gtime_t time, int sat, const nav_t *nav, int opt, +// double *rs, double *dts, double *var); +// void satantoff(gtime_t time, const double *rs, int sat, const nav_t *nav, +// double *dant); + int satpos(gtime_t time, gtime_t teph, int sat, int ephopt, + const nav_t *nav, double *rs, double *dts, double *var, + int *svh); + void satposs(gtime_t time, const obsd_t *obs, int n, const nav_t *nav, + int sateph, double *rs, double *dts, double *var, int *svh); + void setseleph(int sys, int sel); + int getseleph(int sys); +// void readsp3(const char *file, nav_t *nav, int opt); +// int readsap(const char *file, gtime_t time, nav_t *nav); +// int readdcb(const char *file, nav_t *nav, const sta_t *sta); +// int readfcb(const char *file, nav_t *nav); +// void alm2pos(gtime_t time, const alm_t *alm, double *rs, double *dts); +// int tle_read(const char *file, tle_t *tle); +// int tle_name_read(const char *file, tle_t *tle); +// int tle_pos(gtime_t time, const char *name, const char *satno, +// const char *desig, const tle_t *tle, const erp_t *erp, +// double *rs); +/* receiver raw data functions -----------------------------------------------*/ + uint32_t getbitu(const uint8_t *buff, int pos, int len); + int32_t getbits(const uint8_t *buff, int pos, int len); + void setbitu(uint8_t *buff, int pos, int len, uint32_t data); + void setbits(uint8_t *buff, int pos, int len, int32_t data); + uint32_t rtk_crc32(const uint8_t *buff, int len); + uint32_t rtk_crc24q(const uint8_t *buff, int len); + uint16_t rtk_crc16(const uint8_t *buff, int len); +// int decode_word (uint32_t word, uint8_t *data); +// int decode_frame(const uint8_t *buff, eph_t *eph, alm_t *alm, +// double *ion, double *utc); +// int test_glostr(const uint8_t *buff); +// int decode_glostr(const uint8_t *buff, geph_t *geph, double *utc); +// int decode_bds_d1(const uint8_t *buff, eph_t *eph, double *ion, +// double *utc); +// int decode_bds_d2(const uint8_t *buff, eph_t *eph, double *utc); +// int decode_gal_inav(const uint8_t *buff, eph_t *eph, double *ion, +// double *utc); +// int decode_gal_fnav(const uint8_t *buff, eph_t *eph, double *ion, +// double *utc); +// int decode_irn_nav(const uint8_t *buff, eph_t *eph, double *ion, +// double *utc); +// int init_raw (raw_t *raw, int format); +// void free_raw (raw_t *raw); +// int input_raw (raw_t *raw, int format, uint8_t data); +// int input_rawf (raw_t *raw, int format, FILE *fp); +// int update_cmr (raw_t *raw, rtksvr_t *svr, obs_t *obs); +// int input_ubx (raw_t *raw, uint8_t data); +// int input_ubxf (raw_t *raw, FILE *fp); +// int input_oem4 (raw_t *raw, uint8_t data); +// int input_cnav (raw_t *raw, uint8_t data); +// int input_sbp (raw_t *raw, uint8_t data); +// int input_cres (raw_t *raw, uint8_t data); +// int input_stq (raw_t *raw, uint8_t data); +// int input_javad (raw_t *raw, uint8_t data); +// int input_nvs (raw_t *raw, uint8_t data); +// int input_bnx (raw_t *raw, uint8_t data); +// int input_rt17 (raw_t *raw, uint8_t data); +// int input_sbf (raw_t *raw, uint8_t data); +// int input_tersus(raw_t *raw, uint8_t data); +// int input_oem4f (raw_t *raw, FILE *fp); +// int input_cnavf (raw_t *raw, FILE *fp); +// int input_sbpf (raw_t *raw, FILE *fp); +// int input_cresf (raw_t *raw, FILE *fp); +// int input_stqf (raw_t *raw, FILE *fp); +// int input_javadf(raw_t *raw, FILE *fp); +// int input_nvsf (raw_t *raw, FILE *fp); +// int input_bnxf (raw_t *raw, FILE *fp); +// int input_rt17f (raw_t *raw, FILE *fp); +// int input_sbff (raw_t *raw, FILE *fp); +// int input_tersusf(raw_t *raw, FILE *fp); +// int gen_ubx (const char *msg, uint8_t *buff); +// int gen_stq (const char *msg, uint8_t *buff); +// int gen_nvs (const char *msg, uint8_t *buff); +/* rtcm functions ------------------------------------------------------------*/ + int init_rtcm(rtcm_t *rtcm); + int init_rtcm_static(rtcm_t *rtcm, char index); + void free_rtcm(rtcm_t *rtcm); + int input_rtcm3(rtcm_t *rtcm, uint8_t data); +// int input_rtcm3f(rtcm_t *rtcm, FILE *fp); +// int input_rtcm2 (rtcm_t *rtcm, uint8_t data); +// int input_rtcm2f(rtcm_t *rtcm, FILE *fp); +// int gen_rtcm2 (rtcm_t *rtcm, int type, int sync); +// int gen_rtcm3 (rtcm_t *rtcm, int type, int subtype, int sync); +/* solution functions --------------------------------------------------------*/ +// void initsolbuf(solbuf_t *solbuf, int cyclic, int nmax); +// void freesolbuf(solbuf_t *solbuf); +// void freesolstatbuf(solstatbuf_t *solstatbuf); +// sol_t *getsol(solbuf_t *solbuf, int index); +// int addsol(solbuf_t *solbuf, const sol_t *sol); +// int readsol (char *files[], int nfile, solbuf_t *sol); +// int readsolt(char *files[], int nfile, gtime_t ts, gtime_t te, +// double tint, int qflag, solbuf_t *sol); +// int readsolstat(char *files[], int nfile, solstatbuf_t *statbuf); +// int readsolstatt(char *files[], int nfile, gtime_t ts, gtime_t te, +// double tint, solstatbuf_t *statbuf); +// int inputsol(uint8_t data, gtime_t ts, gtime_t te, double tint, +// int qflag, const solopt_t *opt, solbuf_t *solbuf); + int outprcopts(uint8_t *buff, const prcopt_t *opt); + int outsolheads(uint8_t *buff, const solopt_t *opt); + int outsols(uint8_t *buff, const sol_t *sol, const double *rb, + const solopt_t *opt); + int outsolexs(uint8_t *buff, const sol_t *sol, const ssat_t *ssat, + const solopt_t *opt); + void outprcopt(FILE *fp, const prcopt_t *opt); + void outsolhead(FILE *fp, const solopt_t *opt); + void outsol(FILE *fp, const sol_t *sol, const double *rb, + const solopt_t *opt); + void outsolex(FILE *fp, const sol_t *sol, const ssat_t *ssat, + const solopt_t *opt); + int outnmea_rmc(uint8_t *buff, const sol_t *sol); + int outnmea_gga(uint8_t *buff, const sol_t *sol); + int outnmea_gsa(uint8_t *buff, const sol_t *sol, + const ssat_t *ssat); + int outnmea_gsv(uint8_t *buff, const sol_t *sol, + const ssat_t *ssat); +// /* google earth kml converter ------------------------------------------------*/ +// int convkml(const char *infile, const char *outfile, gtime_t ts, +// gtime_t te, double tint, int qflg, double *offset, +// int tcolor, int pcolor, int outalt, int outtime); +// /* gpx converter -------------------------------------------------------------*/ +// int convgpx(const char *infile, const char *outfile, gtime_t ts, +// gtime_t te, double tint, int qflg, double *offset, +// int outtrk, int outpnt, int outalt, int outtime); +/* sbas functions ------------------------------------------------------------*/ +// int sbsreadmsg (const char *file, int sel, sbs_t *sbs); +// int sbsreadmsgt(const char *file, int sel, gtime_t ts, gtime_t te, +// sbs_t *sbs); +// void sbsoutmsg(FILE *fp, sbsmsg_t *sbsmsg); +// int sbsdecodemsg(gtime_t time, int prn, const uint32_t *words, +// sbsmsg_t *sbsmsg); +// int sbsupdatecorr(const sbsmsg_t *msg, nav_t *nav); +// int sbssatcorr(gtime_t time, int sat, const nav_t *nav, double *rs, +// double *dts, double *var); +// int sbsioncorr(gtime_t time, const nav_t *nav, const double *pos, +// const double *azel, double *delay, double *var); +// double sbstropcorr(gtime_t time, const double *pos, const double *azel, +// double *var); +/* options functions ---------------------------------------------------------*/ + opt_t *searchopt(const char *name, const opt_t *opts); + int str2opt(opt_t *opt, const char *str); + int opt2str(const opt_t *opt, char *str); + int opt2buf(const opt_t *opt, char *buff); + int loadopts(const char *file, opt_t *opts); + int saveopts(const char *file, const char *mode, const char *comment, + const opt_t *opts); + void resetsysopts(void); +// void getsysopts(prcopt_t *popt, solopt_t *sopt, filopt_t *fopt); +// void setsysopts(const prcopt_t *popt, const solopt_t *sopt, +// const filopt_t *fopt); + void getsysopts(prcopt_t *popt, solopt_t *sopt); + void setsysopts(const prcopt_t *popt, const solopt_t *sopt); +/* stream data input and output functions ------------------------------------*/ + void strinitcom(void); + void strinit(stream_t *stream); + void strlock(stream_t *stream); + void strunlock(stream_t *stream); + int stropen(stream_t *stream, int type, int mode, const char *path); + void strclose(stream_t *stream); + int strread(stream_t *stream, uint8_t *buff, int n); + int strwrite(stream_t *stream, uint8_t *buff, int n); + void strsync(stream_t *stream1, stream_t *stream2); + int strstat(stream_t *stream, char *msg); + int strstatx(stream_t *stream, char *msg); + void strsum(stream_t *stream, int *inb, int *inr, int *outb, int *outr); + void strsetopt(const int *opt); + gtime_t strgettime(stream_t *stream); + void strsendnmea(stream_t *stream, const sol_t *sol); + void strsendcmd(stream_t *stream, const char *cmd); + void strsettimeout(stream_t *stream, int toinact, int tirecon); + void strsetdir(const char *dir); + void strsetproxy(const char *addr); +/* integer ambiguity resolution ----------------------------------------------*/ + int lambda(rtk_t *rtk, int n, int m, const double *a, const double *Q, double *F, + double *s); + int lambda_reduction(int n, const double *Q, double *Z); + int lambda_search(int n, int m, const double *a, const double *Q, + double *F, double *s); + int parlambda(rtk_t *rtk, int n, int m, const double *a, const double *Q, double *F, double *s); +/* standard positioning ------------------------------------------------------*/ + int pntpos(const obsd_t *obs, int n, const nav_t *nav, + const prcopt_t *opt, sol_t *sol, double *azel, + ssat_t *ssat, char *msg); +/* precise positioning -------------------------------------------------------*/ + void rtkinit(rtk_t *rtk, const prcopt_t *opt); + void rtkfree(rtk_t *rtk); + int rtkpos(rtk_t *rtk, const obsd_t *obs, int nobs, const nav_t *nav); +extern int rtkpos_static(rtk_t *rtk, obsd_t *obs[], int n, const nav_t *nav, char nr1, char nu1); +// int rtkopenstat(const char *file, int level); +// void rtkclosestat(void); +// int rtkoutstat(rtk_t *rtk, char *buff); +// /* precise point positioning -------------------------------------------------*/ +// void pppos(rtk_t *rtk, const obsd_t *obs, int n, const nav_t *nav); +// int pppnx(const prcopt_t *opt); +// int pppoutstat(rtk_t *rtk, char *buff); +// int ppp_ar(rtk_t *rtk, const obsd_t *obs, int n, int *exc, +// const nav_t *nav, const double *azel, double *x, double *P); +/* post-processing positioning -----------------------------------------------*/ +// int postpos(gtime_t ts, gtime_t te, double ti, double tu, +// const prcopt_t *popt, const solopt_t *sopt, +// const filopt_t *fopt, char **infile, int n, char *outfile, +// const char *rov, const char *base); + int postpos(gtime_t ts, gtime_t te, double ti, double tu, + const prcopt_t *popt, const solopt_t *sopt, + char **infile, int n, char *outfile, + const char *rov, const char *base); +/* stream server functions ---------------------------------------------------*/ +// void strsvrinit (strsvr_t *svr, int nout); +// int strsvrstart(strsvr_t *svr, int *opts, int *strs, char **paths, +// char **logs, strconv_t **conv, char **cmds, +// char **cmds_priodic, const double *nmeapos); +// void strsvrstop (strsvr_t *svr, char **cmds); +// void strsvrstat (strsvr_t *svr, int *stat, int *log_stat, int *byte, +// int *bps, char *msg); +// strconv_t *strconvnew(int itype, int otype, const char *msgs, int staid, +// int stasel, const char *opt); +// void strconvfree(strconv_t *conv); +/* rtk server functions ------------------------------------------------------*/ + int rtksvrinit(rtksvr_t *svr); + void rtksvrfree(rtksvr_t *svr); + int rtksvrstart(rtksvr_t *svr, int cycle, int buffsize, int *strs, + char **paths, int *formats, int navsel, char **cmds, + char **cmds_periodic, char **rcvopts, int nmeacycle, + int nmeareq, const double *nmeapos, prcopt_t *prcopt, + solopt_t *solopt, stream_t *moni, char *errmsg); + void rtksvrstop(rtksvr_t *svr, char **cmds); + int rtksvropenstr(rtksvr_t *svr, int index, int str, const char *path, + const solopt_t *solopt); + void rtksvrclosestr(rtksvr_t *svr, int index); + void rtksvrlock(rtksvr_t *svr); + void rtksvrunlock(rtksvr_t *svr); + int rtksvrostat(rtksvr_t *svr, int type, gtime_t *time, int *sat, + double *az, double *el, int **snr, int *vsat); + void rtksvrsstat(rtksvr_t *svr, int *sstat, char *msg); + int rtksvrmark(rtksvr_t *svr, const char *name, const char *comment); +// /* downloader functions ------------------------------------------------------*/ +// int dl_readurls(const char *file, char **types, int ntype, url_t *urls, +// int nmax); +// int dl_readstas(const char *file, char **stas, int nmax); +// int dl_exec(gtime_t ts, gtime_t te, double ti, int seqnos, int seqnoe, +// const url_t *urls, int nurl, char **stas, int nsta, +// const char *dir, const char *usr, const char *pwd, +// const char *proxy, int opts, char *msg, FILE *fp); +// void dl_test(gtime_t ts, gtime_t te, double ti, const url_t *urls, +// int nurl, char **stas, int nsta, const char *dir, +// int ncol, int datefmt, FILE *fp); +/* GIS data functions --------------------------------------------------------*/ +// int gis_read(const char *file, gis_t *gis, int layer); +// void gis_free(gis_t *gis); +/* application defined functions ---------------------------------------------*/ +extern int showmsg(const char *format, ...); +extern void settspan(gtime_t ts, gtime_t te); +extern void settime(gtime_t time); + +#endif /* RTKLIB_H */ diff --git a/RTK/static_ram.c b/RTK/static_ram.c new file mode 100644 index 0000000..2144e69 --- /dev/null +++ b/RTK/static_ram.c @@ -0,0 +1,36 @@ +#include "rtklib.h" + +#ifdef STATIC +/* number of parameters (pos,ionos,tropos,hw-bias,phase-bias,real,estimated) */ +#define NX 87 +#define NR 9 +/* global variables ----------------------------------------------------------*/ +rtksvr_t svr; /* rtk server struct */ +prcopt_t prcopt; /* processing options */ +solopt_t solopt[2] = {{0}}; /* solution options */ + +/* rtkpos.c */ +double rtk_x[NX] = {0.0}; /* NX*8 = B */ +double rtk_P[NX * NX] = {0.0}; /* NX*NX*8 = B */ +double rtk_xa[NR] = {0.0}; /* NR*8 = B */ +double rtk_Pa[NR * NR] = {0.0}; /* NR*NR*8 = B */ + +/* rtksvr.c */ +eph_t svr_eph[MAXSAT]; +#ifdef ENAGLO +geph_t svr_geph[NSATGLO]; +#endif +#ifdef ENASBS +seph_t svr_seph[NSATSBS]; +#endif +obsd_t svr_obsd[2][MAXOBS]; + +/* rtcm.c */ +obsd_t RTCM_obsd_r[MAXOBS]; +obsd_t RTCM_obsd_b[MAXOBS]; +eph_t RTCM_eph_r[MAXSAT]; +#ifdef ENAGLO +geph_t RTCM_geph[MAXPRNGLO]; +#endif + +#endif \ No newline at end of file diff --git a/applications/main.c b/applications/main.c index 9790df1..393c82b 100644 --- a/applications/main.c +++ b/applications/main.c @@ -13,23 +13,33 @@ #include #include #include +#include +#include +#include "user_uart.h" + /* defined the LED0 pin: PF9 */ #define LED0_PIN GET_PIN(F, 9) int main(void) { - /* set LED0 pin mode to output */ - rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT); - LOG_I("main log"); + uart3_init(); + + rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT); while (1) { rt_pin_write(LED0_PIN, PIN_HIGH); rt_thread_mdelay(500); rt_pin_write(LED0_PIN, PIN_LOW); rt_thread_mdelay(500); -// LOG_I("log test"); } } +void test_entry() +{ +// const char testbuff[] = "test massage!!!"; +// rt_device_write(serial3,0,testbuff,strlen(testbuff)); +} +MSH_CMD_EXPORT(test_entry,test_entry); + diff --git a/rt-thread/components/utilities/ulog/backend/ulog_file_be.c b/rt-thread/components/utilities/ulog/backend/ulog_file_be.c new file mode 100644 index 0000000..7dd4e96 --- /dev/null +++ b/rt-thread/components/utilities/ulog/backend/ulog_file_be.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-01-07 ChenYong first version + */ + +#include +#include +#include + +#include +#include "ulog_file.h" + +#define ULOG_FILE_BE_NAME "file" + +#ifndef ULOG_FILE_ROOT_PATH +#define ULOG_FILE_ROOT_PATH "/logs" +#endif +#ifndef ULOG_FILE_NAME_BASE +#define ULOG_FILE_NAME_BASE "ulog.log" +#endif + +#ifndef ULOG_FILE_MAX_NUM +#define ULOG_FILE_MAX_NUM 5 +#endif +#ifndef ULOG_FILE_MAX_SIZE +#define ULOG_FILE_MAX_SIZE (1024 * 512) +#endif + +#define ULOG_FILE_PATH_LEN 128 + +#if defined(ULOG_ASYNC_OUTPUT_THREAD_STACK) && (ULOG_ASYNC_OUTPUT_THREAD_STACK < 2048) +#error "The value of ULOG_ASYNC_OUTPUT_THREAD_STACK must be greater than 2048." +#endif + +static struct ulog_backend ulog_file; +static char g_file_path[ULOG_FILE_PATH_LEN] = {0}; +static int g_file_fd = -1; + +/* rotate the log file xxx.log.n-1 => xxx.log.n, and xxx.log => xxx.log.0 */ +static rt_bool_t ulog_file_rotate(void) +{ +#define SUFFIX_LEN 10 + /* mv xxx.log.n-1 => xxx.log.n, and xxx.log => xxx.log.0 */ + static char old_path[ULOG_FILE_PATH_LEN], new_path[ULOG_FILE_PATH_LEN]; + int index = 0, err = 0, file_fd = 0; + size_t base_len = 0; + rt_bool_t result = RT_FALSE; + + rt_memcpy(old_path, g_file_path, ULOG_FILE_PATH_LEN); + rt_memcpy(new_path, g_file_path, ULOG_FILE_PATH_LEN); + base_len = rt_strlen(ULOG_FILE_ROOT_PATH) + rt_strlen(ULOG_FILE_NAME_BASE) + 1; + + if (g_file_fd >= 0) + { + close(g_file_fd); + } + + for (index = ULOG_FILE_MAX_NUM - 2; index >= 0; --index) + { + rt_snprintf(old_path + base_len, SUFFIX_LEN, index ? ".%d" : "", index - 1); + rt_snprintf(new_path + base_len, SUFFIX_LEN, ".%d", index); + /* remove the old file */ + if ((file_fd = open(new_path, O_RDONLY)) >= 0) + { + close(file_fd); + unlink(new_path); + } + /* change the new log file to old file name */ + if ((file_fd = open(old_path , O_RDONLY)) >= 0) + { + close(file_fd); + err = rename(old_path, new_path); + } + + if (err < 0) + { + result = RT_FALSE; + goto __exit; + } + } + +__exit: + /* reopen the file */ + g_file_fd = open(g_file_path, O_CREAT | O_RDWR | O_APPEND); + + return result; +} + +static void ulog_file_backend_output(struct ulog_backend *backend, rt_uint32_t level, + const char *tag, rt_bool_t is_raw, const char *log, size_t len) +{ + size_t file_size = 0; + + /* check log file directory */ + if (access(ULOG_FILE_ROOT_PATH, 0) < 0) + { + mkdir(ULOG_FILE_ROOT_PATH, 0); + } + + if (g_file_fd < 0) + { + rt_snprintf(g_file_path, ULOG_FILE_PATH_LEN, "%s/%s", ULOG_FILE_ROOT_PATH, ULOG_FILE_NAME_BASE); + g_file_fd = open(g_file_path, O_CREAT | O_RDWR); + if (g_file_fd < 0) + { + rt_kprintf("ulog file(%s) open failed.", g_file_path); + return; + } + } + + file_size = lseek(g_file_fd, 0, SEEK_END); + if (file_size > ULOG_FILE_MAX_SIZE) + { + if (!ulog_file_rotate()) + { + return; + } + } + + write(g_file_fd, log, len); + /* flush file cache */ + fsync(g_file_fd); +} + +/* initialize the ulog file backend */ +int ulog_file_backend_init(void) +{ + ulog_file.output = ulog_file_backend_output; + ulog_backend_register(&ulog_file, ULOG_FILE_BE_NAME, RT_FALSE); + return 0; +} + + +/* uninitialize the ulog file backend */ +int ulog_file_backend_deinit(void) +{ + if (g_file_fd >= 0) + { + close(g_file_fd); + g_file_fd = -1; + } + ulog_backend_unregister(&ulog_file); + return 0; +} diff --git a/rt-thread/components/utilities/ulog_file/LICENSE b/rt-thread/components/utilities/ulog_file/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/rt-thread/components/utilities/ulog_file/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/rt-thread/components/utilities/ulog_file/README.md b/rt-thread/components/utilities/ulog_file/README.md new file mode 100644 index 0000000..8df7144 --- /dev/null +++ b/rt-thread/components/utilities/ulog_file/README.md @@ -0,0 +1,63 @@ +# 基于文件系统的 ulog 插件 + +## 1、介绍 + +该软件包基于 ulog 组件,主要实现 ulog 文件系统后端工功能,并且支持配置参数存储功能 。 + +支持功能如下: + +- 支持 ulog 日志存储到文件后端; + +- 支持设置日志文件名,最大数量和大小; +- 支持日志文件循环存储功能; + +### 1.1 许可证 + +本软件包遵循 Apache 2.0 许可,详见 `LICENSE` 文件。 + +### 1.2 依赖 + +- RT-Thread ulog 组件 + +## 2、如何打开 + +使用本软件包需要在 RT-Thread 的包管理器中选择它,具体路径如下: + +```c +RT-Thread online packages + tools packages ---> + [*] ulog_file: The ulog file backend by filesystem. + (/logs) The root path of the saved file + (ulog.log) The base name of the saved file + (5) The maximum number of the saved file + (524288) The maximum size of a file + Version (latest) ---> +``` + +- **The root path of the saved file**:日志文件保存的根路径; +- **The base name of the saved file**:日志文件的基础文件名,文件名格式 `ulog.log.x`; +- **The maximum number of the saved file**:配置这日志文件最大数量; +- **The maximum size of a file**:配置单个日志文件最大长度; + +## 3、使用说明 + +### 3.1 文件后端初始化 + +```c +int ulog_file_backend_init(void); +``` + +需要在应用层调用 `ulog_file_backend_init()` 初始化函数,即可初始化 ulog 日志文件后端,开启日志输出到文件系统指定文件中; + +### 3.1 文件后端取消初始化 + +```c +int ulog_file_backend_deinit(void); +``` + +需要在应用层调用 `ulog_file_backend_deinit()` 函数,可以注销 ulog 文件后端,取消日志输出到文件系统指定文件中; + +## 4、联系方式 + +- 维护:ChenYong +- 主页: \ No newline at end of file diff --git a/rt-thread/components/utilities/ulog_file/SConscript b/rt-thread/components/utilities/ulog_file/SConscript new file mode 100644 index 0000000..5c6a241 --- /dev/null +++ b/rt-thread/components/utilities/ulog_file/SConscript @@ -0,0 +1,13 @@ +Import('RTT_ROOT') +Import('rtconfig') +from building import * + +objs = [] +cwd = GetCurrentDir() +list = os.listdir(cwd) +src = Glob('*.c') +CPPPATH = [cwd, str(Dir('#'))] + +group = DefineGroup('ulog_file', src, depend = ['PKG_USING_ULOG_FILE'], CPPPATH = CPPPATH) + +Return('group') diff --git a/rt-thread/components/utilities/ulog_file/ulog_file.h b/rt-thread/components/utilities/ulog_file/ulog_file.h new file mode 100644 index 0000000..848637b --- /dev/null +++ b/rt-thread/components/utilities/ulog_file/ulog_file.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-01-07 ChenYong first version + */ + +#ifndef _ULOG_FILE_H_ +#define _ULOG_FILE_H_ + +#define ULOG_FILE_SW_VERSION "1.0.0" +#define ULOG_FILE_SW_VERSION_NUM 0x0100000 + +int ulog_file_backend_init(void); +int ulog_file_backend_deinit(void); + +#endif /* _ULOG_FILE_H_ */ diff --git a/rtconfig.h b/rtconfig.h index 9980b6c..4c49bfc 100644 --- a/rtconfig.h +++ b/rtconfig.h @@ -168,8 +168,14 @@ #define RT_USING_ULOG #define ULOG_OUTPUT_LVL_D #define ULOG_OUTPUT_LVL 7 +#define ULOG_USING_ISR_LOG #define ULOG_ASSERT_ENABLE #define ULOG_LINE_BUF_SIZE 128 +#define ULOG_USING_ASYNC_OUTPUT +#define ULOG_ASYNC_OUTPUT_BUF_SIZE 2048 +#define ULOG_ASYNC_OUTPUT_BY_THREAD +#define ULOG_ASYNC_OUTPUT_THREAD_STACK 1024 +#define ULOG_ASYNC_OUTPUT_THREAD_PRIORITY 30 /* log format */ @@ -235,6 +241,12 @@ /* tools packages */ +#define PKG_USING_ULOG_FILE +#define ULOG_FILE_ROOT_PATH "/logs" +#define ULOG_FILE_NAME_BASE "ulog.log" +#define ULOG_FILE_MAX_NUM 5 +#define ULOG_FILE_MAX_SIZE 524288 +#define PKG_USING_ULOG_FILE_V100 /* end of tools packages */ /* system packages */ @@ -293,6 +305,7 @@ /* Onboard Peripheral Drivers */ #define BSP_USING_USB_TO_USART +#define BSP_USING_COM3 #define BSP_USING_SRAM /* Enable File System */ @@ -307,6 +320,8 @@ #define BSP_USING_GPIO #define BSP_USING_UART #define BSP_USING_UART1 +#define BSP_USING_UART3 +#define BSP_UART3_RX_USING_DMA #define BSP_USING_ONCHIP_RTC #define BSP_RTC_USING_LSE #define BSP_USING_SDIO diff --git a/user_uart/user_uart.c b/user_uart/user_uart.c new file mode 100644 index 0000000..bdd3608 --- /dev/null +++ b/user_uart/user_uart.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-06-14 fize the first version + */ +#include "user_uart.h" + + + +static rt_err_t uart3_tx_complete(rt_device_t dev, void *buffer) +{ + //todo: uart3_tx_complete sem: do nothing for now. + //since dma for tx not enabled,so this callback will not be called at any time. + LOG_I("massage sent %s",strlen(buffer)); + return RT_EOK; +} + +//dev 豸ص +//size ݴСص +//still in ISR func,so can only use ulog at asynchronous mode. +static rt_err_t uart3_rx_complete(rt_device_t dev, rt_size_t size) +{ + char testbuff[20]; + uart3_simpack.rx_num=size; + rt_sem_release(&uart3_simpack.rx_sem); + rt_device_read(serial3,0,testbuff, size); + // can only use ulog at asynchronous mode. + LOG_I("massage received : %s",testbuff); + return RT_EOK; +} + +rt_device_t uart3_init(void) +{ + struct serial_configure config; + + serial3 = rt_device_find(USER_UART_NAME); + if (serial3 == RT_NULL) + { + LOG_E("could not find device: %s", USER_UART_NAME); + return RT_NULL; + } + config.baud_rate = BAUD_RATE_115200; //޸IJΪ 115200 + config.data_bits = DATA_BITS_8; //λ 8 + config.stop_bits = STOP_BITS_1; //ֹͣλ 1 + config.bufsz = 2048; //޸Ļ buff size Ϊ 2048 + config.parity = PARITY_NONE; //żУλ + rt_device_control(serial3, RT_DEVICE_CTRL_CONFIG, &config); + if ((rt_device_set_tx_complete(serial3, uart3_tx_complete) || rt_device_set_rx_indicate(serial3, uart3_rx_complete)) + != RT_EOK) + { + LOG_E("could not set %s 's rx|tx callback func", USER_UART_NAME); + return RT_NULL; + } + //do not ust dma for rx and tx at same time + if ( rt_device_open(serial3, RT_DEVICE_FLAG_INT_TX |RT_DEVICE_FLAG_DMA_RX|RT_DEVICE_OFLAG_RDWR )) + { + LOG_E("could not open device: %s", USER_UART_NAME); + return RT_NULL; + } + rt_sem_init(&uart3_simpack.rx_sem, "rx3_sem", 0, RT_IPC_FLAG_PRIO); + rt_sem_init(&uart3_simpack.tx_sem, "tx3_sem", 0, RT_IPC_FLAG_PRIO); + return serial3; +} + diff --git a/user_uart/user_uart.h b/user_uart/user_uart.h new file mode 100644 index 0000000..6d2a4ef --- /dev/null +++ b/user_uart/user_uart.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-06-14 С the first version + */ +#ifndef APPLICATIONS_USER_UART_USER_UART_H_ +#define APPLICATIONS_USER_UART_USER_UART_H_ + +#include +#include +#include +#include + +#define USER_UART_NAME "uart3" + +#define READ_SERIAL3(args...) rt_device_read(serial3,0,args,args) + +rt_device_t serial3; + +struct uart_simpack +{ + rt_size_t rx_num; + rt_size_t tx_num; + struct rt_semaphore rx_sem; /* ڽϢź */ + struct rt_semaphore tx_sem; /* ڷϢź */ +}; +typedef struct uart_simpack uart_simpack; + + +uart_simpack uart3_simpack; + +rt_device_t uart3_init(void); + +#endif /* APPLICATIONS_USER_UART_USER_UART_H_ */