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_ */