diff options
192 files changed, 9000 insertions, 3494 deletions
diff --git a/.checkpatch.conf b/.checkpatch.conf new file mode 100644 index 0000000..591ff65 --- /dev/null +++ b/.checkpatch.conf @@ -0,0 +1 @@ +--exclude ^firmware/atmel_softpack_libraries/.*$ diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..5d4791c --- /dev/null +++ b/.clang-format @@ -0,0 +1,563 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# clang-format configuration file. Intended for clang-format >= 4. +# +# For more information, see: +# +# Documentation/process/clang-format.rst +# https://clang.llvm.org/docs/ClangFormat.html +# https://clang.llvm.org/docs/ClangFormatStyleOptions.html +# +--- +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +#AlignEscapedNewlines: Left # Unknown to clang-format-4.0 +AlignOperands: true +AlignTrailingComments: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + #AfterExternBlock: false # Unknown to clang-format-5.0 + BeforeCatch: false + BeforeElse: false + IndentBraces: false + #SplitEmptyFunction: true # Unknown to clang-format-4.0 + #SplitEmptyRecord: true # Unknown to clang-format-4.0 + #SplitEmptyNamespace: true # Unknown to clang-format-4.0 +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +#BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0 +BreakBeforeTernaryOperators: false +BreakConstructorInitializersBeforeComma: false +#BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0 +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: false +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +#CompactNamespaces: false # Unknown to clang-format-4.0 +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 8 +ContinuationIndentWidth: 8 +Cpp11BracedListStyle: false +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +#FixNamespaceComments: false # Unknown to clang-format-4.0 + +# Taken from: +# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ \ +# | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \ +# | sort | uniq +ForEachMacros: + - 'apei_estatus_for_each_section' + - 'ata_for_each_dev' + - 'ata_for_each_link' + - '__ata_qc_for_each' + - 'ata_qc_for_each' + - 'ata_qc_for_each_raw' + - 'ata_qc_for_each_with_internal' + - 'ax25_for_each' + - 'ax25_uid_for_each' + - '__bio_for_each_bvec' + - 'bio_for_each_bvec' + - 'bio_for_each_bvec_all' + - 'bio_for_each_integrity_vec' + - '__bio_for_each_segment' + - 'bio_for_each_segment' + - 'bio_for_each_segment_all' + - 'bio_list_for_each' + - 'bip_for_each_vec' + - 'bitmap_for_each_clear_region' + - 'bitmap_for_each_set_region' + - 'blkg_for_each_descendant_post' + - 'blkg_for_each_descendant_pre' + - 'blk_queue_for_each_rl' + - 'bond_for_each_slave' + - 'bond_for_each_slave_rcu' + - 'bpf_for_each_spilled_reg' + - 'btree_for_each_safe128' + - 'btree_for_each_safe32' + - 'btree_for_each_safe64' + - 'btree_for_each_safel' + - 'card_for_each_dev' + - 'cgroup_taskset_for_each' + - 'cgroup_taskset_for_each_leader' + - 'cpufreq_for_each_entry' + - 'cpufreq_for_each_entry_idx' + - 'cpufreq_for_each_valid_entry' + - 'cpufreq_for_each_valid_entry_idx' + - 'css_for_each_child' + - 'css_for_each_descendant_post' + - 'css_for_each_descendant_pre' + - 'device_for_each_child_node' + - 'displayid_iter_for_each' + - 'dma_fence_chain_for_each' + - 'do_for_each_ftrace_op' + - 'drm_atomic_crtc_for_each_plane' + - 'drm_atomic_crtc_state_for_each_plane' + - 'drm_atomic_crtc_state_for_each_plane_state' + - 'drm_atomic_for_each_plane_damage' + - 'drm_client_for_each_connector_iter' + - 'drm_client_for_each_modeset' + - 'drm_connector_for_each_possible_encoder' + - 'drm_for_each_bridge_in_chain' + - 'drm_for_each_connector_iter' + - 'drm_for_each_crtc' + - 'drm_for_each_crtc_reverse' + - 'drm_for_each_encoder' + - 'drm_for_each_encoder_mask' + - 'drm_for_each_fb' + - 'drm_for_each_legacy_plane' + - 'drm_for_each_plane' + - 'drm_for_each_plane_mask' + - 'drm_for_each_privobj' + - 'drm_mm_for_each_hole' + - 'drm_mm_for_each_node' + - 'drm_mm_for_each_node_in_range' + - 'drm_mm_for_each_node_safe' + - 'flow_action_for_each' + - 'for_each_acpi_dev_match' + - 'for_each_active_dev_scope' + - 'for_each_active_drhd_unit' + - 'for_each_active_iommu' + - 'for_each_aggr_pgid' + - 'for_each_available_child_of_node' + - 'for_each_bio' + - 'for_each_board_func_rsrc' + - 'for_each_bvec' + - 'for_each_card_auxs' + - 'for_each_card_auxs_safe' + - 'for_each_card_components' + - 'for_each_card_dapms' + - 'for_each_card_pre_auxs' + - 'for_each_card_prelinks' + - 'for_each_card_rtds' + - 'for_each_card_rtds_safe' + - 'for_each_card_widgets' + - 'for_each_card_widgets_safe' + - 'for_each_cgroup_storage_type' + - 'for_each_child_of_node' + - 'for_each_clear_bit' + - 'for_each_clear_bit_from' + - 'for_each_cmsghdr' + - 'for_each_compatible_node' + - 'for_each_component_dais' + - 'for_each_component_dais_safe' + - 'for_each_comp_order' + - 'for_each_console' + - 'for_each_cpu' + - 'for_each_cpu_and' + - 'for_each_cpu_not' + - 'for_each_cpu_wrap' + - 'for_each_dapm_widgets' + - 'for_each_dev_addr' + - 'for_each_dev_scope' + - 'for_each_dma_cap_mask' + - 'for_each_dpcm_be' + - 'for_each_dpcm_be_rollback' + - 'for_each_dpcm_be_safe' + - 'for_each_dpcm_fe' + - 'for_each_drhd_unit' + - 'for_each_dss_dev' + - 'for_each_dtpm_table' + - 'for_each_efi_memory_desc' + - 'for_each_efi_memory_desc_in_map' + - 'for_each_element' + - 'for_each_element_extid' + - 'for_each_element_id' + - 'for_each_endpoint_of_node' + - 'for_each_evictable_lru' + - 'for_each_fib6_node_rt_rcu' + - 'for_each_fib6_walker_rt' + - 'for_each_free_mem_pfn_range_in_zone' + - 'for_each_free_mem_pfn_range_in_zone_from' + - 'for_each_free_mem_range' + - 'for_each_free_mem_range_reverse' + - 'for_each_func_rsrc' + - 'for_each_hstate' + - 'for_each_if' + - 'for_each_iommu' + - 'for_each_ip_tunnel_rcu' + - 'for_each_irq_nr' + - 'for_each_link_codecs' + - 'for_each_link_cpus' + - 'for_each_link_platforms' + - 'for_each_lru' + - 'for_each_matching_node' + - 'for_each_matching_node_and_match' + - 'for_each_member' + - 'for_each_memcg_cache_index' + - 'for_each_mem_pfn_range' + - '__for_each_mem_range' + - 'for_each_mem_range' + - '__for_each_mem_range_rev' + - 'for_each_mem_range_rev' + - 'for_each_mem_region' + - 'for_each_migratetype_order' + - 'for_each_msi_entry' + - 'for_each_msi_entry_safe' + - 'for_each_msi_vector' + - 'for_each_net' + - 'for_each_net_continue_reverse' + - 'for_each_netdev' + - 'for_each_netdev_continue' + - 'for_each_netdev_continue_rcu' + - 'for_each_netdev_continue_reverse' + - 'for_each_netdev_feature' + - 'for_each_netdev_in_bond_rcu' + - 'for_each_netdev_rcu' + - 'for_each_netdev_reverse' + - 'for_each_netdev_safe' + - 'for_each_net_rcu' + - 'for_each_new_connector_in_state' + - 'for_each_new_crtc_in_state' + - 'for_each_new_mst_mgr_in_state' + - 'for_each_new_plane_in_state' + - 'for_each_new_private_obj_in_state' + - 'for_each_node' + - 'for_each_node_by_name' + - 'for_each_node_by_type' + - 'for_each_node_mask' + - 'for_each_node_state' + - 'for_each_node_with_cpus' + - 'for_each_node_with_property' + - 'for_each_nonreserved_multicast_dest_pgid' + - 'for_each_of_allnodes' + - 'for_each_of_allnodes_from' + - 'for_each_of_cpu_node' + - 'for_each_of_pci_range' + - 'for_each_old_connector_in_state' + - 'for_each_old_crtc_in_state' + - 'for_each_old_mst_mgr_in_state' + - 'for_each_oldnew_connector_in_state' + - 'for_each_oldnew_crtc_in_state' + - 'for_each_oldnew_mst_mgr_in_state' + - 'for_each_oldnew_plane_in_state' + - 'for_each_oldnew_plane_in_state_reverse' + - 'for_each_oldnew_private_obj_in_state' + - 'for_each_old_plane_in_state' + - 'for_each_old_private_obj_in_state' + - 'for_each_online_cpu' + - 'for_each_online_node' + - 'for_each_online_pgdat' + - 'for_each_pci_bridge' + - 'for_each_pci_dev' + - 'for_each_pci_msi_entry' + - 'for_each_pcm_streams' + - 'for_each_physmem_range' + - 'for_each_populated_zone' + - 'for_each_possible_cpu' + - 'for_each_present_cpu' + - 'for_each_prime_number' + - 'for_each_prime_number_from' + - 'for_each_process' + - 'for_each_process_thread' + - 'for_each_prop_codec_conf' + - 'for_each_prop_dai_codec' + - 'for_each_prop_dai_cpu' + - 'for_each_prop_dlc_codecs' + - 'for_each_prop_dlc_cpus' + - 'for_each_prop_dlc_platforms' + - 'for_each_property_of_node' + - 'for_each_registered_fb' + - 'for_each_requested_gpio' + - 'for_each_requested_gpio_in_range' + - 'for_each_reserved_mem_range' + - 'for_each_reserved_mem_region' + - 'for_each_rtd_codec_dais' + - 'for_each_rtd_components' + - 'for_each_rtd_cpu_dais' + - 'for_each_rtd_dais' + - 'for_each_set_bit' + - 'for_each_set_bit_from' + - 'for_each_set_clump8' + - 'for_each_sg' + - 'for_each_sg_dma_page' + - 'for_each_sg_page' + - 'for_each_sgtable_dma_page' + - 'for_each_sgtable_dma_sg' + - 'for_each_sgtable_page' + - 'for_each_sgtable_sg' + - 'for_each_sibling_event' + - 'for_each_subelement' + - 'for_each_subelement_extid' + - 'for_each_subelement_id' + - '__for_each_thread' + - 'for_each_thread' + - 'for_each_unicast_dest_pgid' + - 'for_each_vsi' + - 'for_each_wakeup_source' + - 'for_each_zone' + - 'for_each_zone_zonelist' + - 'for_each_zone_zonelist_nodemask' + - 'fwnode_for_each_available_child_node' + - 'fwnode_for_each_child_node' + - 'fwnode_graph_for_each_endpoint' + - 'gadget_for_each_ep' + - 'genradix_for_each' + - 'genradix_for_each_from' + - 'hash_for_each' + - 'hash_for_each_possible' + - 'hash_for_each_possible_rcu' + - 'hash_for_each_possible_rcu_notrace' + - 'hash_for_each_possible_safe' + - 'hash_for_each_rcu' + - 'hash_for_each_safe' + - 'hctx_for_each_ctx' + - 'hlist_bl_for_each_entry' + - 'hlist_bl_for_each_entry_rcu' + - 'hlist_bl_for_each_entry_safe' + - 'hlist_for_each' + - 'hlist_for_each_entry' + - 'hlist_for_each_entry_continue' + - 'hlist_for_each_entry_continue_rcu' + - 'hlist_for_each_entry_continue_rcu_bh' + - 'hlist_for_each_entry_from' + - 'hlist_for_each_entry_from_rcu' + - 'hlist_for_each_entry_rcu' + - 'hlist_for_each_entry_rcu_bh' + - 'hlist_for_each_entry_rcu_notrace' + - 'hlist_for_each_entry_safe' + - 'hlist_for_each_entry_srcu' + - '__hlist_for_each_rcu' + - 'hlist_for_each_safe' + - 'hlist_nulls_for_each_entry' + - 'hlist_nulls_for_each_entry_from' + - 'hlist_nulls_for_each_entry_rcu' + - 'hlist_nulls_for_each_entry_safe' + - 'i3c_bus_for_each_i2cdev' + - 'i3c_bus_for_each_i3cdev' + - 'ide_host_for_each_port' + - 'ide_port_for_each_dev' + - 'ide_port_for_each_present_dev' + - 'idr_for_each_entry' + - 'idr_for_each_entry_continue' + - 'idr_for_each_entry_continue_ul' + - 'idr_for_each_entry_ul' + - 'in_dev_for_each_ifa_rcu' + - 'in_dev_for_each_ifa_rtnl' + - 'inet_bind_bucket_for_each' + - 'inet_lhash2_for_each_icsk_rcu' + - 'key_for_each' + - 'key_for_each_safe' + - 'klp_for_each_func' + - 'klp_for_each_func_safe' + - 'klp_for_each_func_static' + - 'klp_for_each_object' + - 'klp_for_each_object_safe' + - 'klp_for_each_object_static' + - 'kunit_suite_for_each_test_case' + - 'kvm_for_each_memslot' + - 'kvm_for_each_vcpu' + - 'list_for_each' + - 'list_for_each_codec' + - 'list_for_each_codec_safe' + - 'list_for_each_continue' + - 'list_for_each_entry' + - 'list_for_each_entry_continue' + - 'list_for_each_entry_continue_rcu' + - 'list_for_each_entry_continue_reverse' + - 'list_for_each_entry_from' + - 'list_for_each_entry_from_rcu' + - 'list_for_each_entry_from_reverse' + - 'list_for_each_entry_lockless' + - 'list_for_each_entry_rcu' + - 'list_for_each_entry_reverse' + - 'list_for_each_entry_safe' + - 'list_for_each_entry_safe_continue' + - 'list_for_each_entry_safe_from' + - 'list_for_each_entry_safe_reverse' + - 'list_for_each_entry_srcu' + - 'list_for_each_prev' + - 'list_for_each_prev_safe' + - 'list_for_each_safe' + - 'llist_for_each' + - 'llist_for_each_entry' + - 'llist_for_each_entry_safe' + - 'llist_for_each_safe' + - 'mci_for_each_dimm' + - 'media_device_for_each_entity' + - 'media_device_for_each_intf' + - 'media_device_for_each_link' + - 'media_device_for_each_pad' + - 'nanddev_io_for_each_page' + - 'netdev_for_each_lower_dev' + - 'netdev_for_each_lower_private' + - 'netdev_for_each_lower_private_rcu' + - 'netdev_for_each_mc_addr' + - 'netdev_for_each_uc_addr' + - 'netdev_for_each_upper_dev_rcu' + - 'netdev_hw_addr_list_for_each' + - 'nft_rule_for_each_expr' + - 'nla_for_each_attr' + - 'nla_for_each_nested' + - 'nlmsg_for_each_attr' + - 'nlmsg_for_each_msg' + - 'nr_neigh_for_each' + - 'nr_neigh_for_each_safe' + - 'nr_node_for_each' + - 'nr_node_for_each_safe' + - 'of_for_each_phandle' + - 'of_property_for_each_string' + - 'of_property_for_each_u32' + - 'pci_bus_for_each_resource' + - 'pcl_for_each_chunk' + - 'pcl_for_each_segment' + - 'pcm_for_each_format' + - 'ping_portaddr_for_each_entry' + - 'plist_for_each' + - 'plist_for_each_continue' + - 'plist_for_each_entry' + - 'plist_for_each_entry_continue' + - 'plist_for_each_entry_safe' + - 'plist_for_each_safe' + - 'pnp_for_each_card' + - 'pnp_for_each_dev' + - 'protocol_for_each_card' + - 'protocol_for_each_dev' + - 'queue_for_each_hw_ctx' + - 'radix_tree_for_each_slot' + - 'radix_tree_for_each_tagged' + - 'rb_for_each' + - 'rbtree_postorder_for_each_entry_safe' + - 'rdma_for_each_block' + - 'rdma_for_each_port' + - 'rdma_umem_for_each_dma_block' + - 'resource_list_for_each_entry' + - 'resource_list_for_each_entry_safe' + - 'rhl_for_each_entry_rcu' + - 'rhl_for_each_rcu' + - 'rht_for_each' + - 'rht_for_each_entry' + - 'rht_for_each_entry_from' + - 'rht_for_each_entry_rcu' + - 'rht_for_each_entry_rcu_from' + - 'rht_for_each_entry_safe' + - 'rht_for_each_from' + - 'rht_for_each_rcu' + - 'rht_for_each_rcu_from' + - '__rq_for_each_bio' + - 'rq_for_each_bvec' + - 'rq_for_each_segment' + - 'scsi_for_each_prot_sg' + - 'scsi_for_each_sg' + - 'sctp_for_each_hentry' + - 'sctp_skb_for_each' + - 'shdma_for_each_chan' + - '__shost_for_each_device' + - 'shost_for_each_device' + - 'sk_for_each' + - 'sk_for_each_bound' + - 'sk_for_each_entry_offset_rcu' + - 'sk_for_each_from' + - 'sk_for_each_rcu' + - 'sk_for_each_safe' + - 'sk_nulls_for_each' + - 'sk_nulls_for_each_from' + - 'sk_nulls_for_each_rcu' + - 'snd_array_for_each' + - 'snd_pcm_group_for_each_entry' + - 'snd_soc_dapm_widget_for_each_path' + - 'snd_soc_dapm_widget_for_each_path_safe' + - 'snd_soc_dapm_widget_for_each_sink_path' + - 'snd_soc_dapm_widget_for_each_source_path' + - 'tb_property_for_each' + - 'tcf_exts_for_each_action' + - 'udp_portaddr_for_each_entry' + - 'udp_portaddr_for_each_entry_rcu' + - 'usb_hub_for_each_child' + - 'v4l2_device_for_each_subdev' + - 'v4l2_m2m_for_each_dst_buf' + - 'v4l2_m2m_for_each_dst_buf_safe' + - 'v4l2_m2m_for_each_src_buf' + - 'v4l2_m2m_for_each_src_buf_safe' + - 'virtio_device_for_each_vq' + - 'while_for_each_ftrace_op' + - 'xa_for_each' + - 'xa_for_each_marked' + - 'xa_for_each_range' + - 'xa_for_each_start' + - 'xas_for_each' + - 'xas_for_each_conflict' + - 'xas_for_each_marked' + - 'xbc_array_for_each_value' + - 'xbc_for_each_key_value' + - 'xbc_node_for_each_array_value' + - 'xbc_node_for_each_child' + - 'xbc_node_for_each_key_value' + - 'zorro_for_each_dev' + - 'for_each_line' + - 'for_each_non_empty_line' + +#IncludeBlocks: Preserve # Unknown to clang-format-5.0 +IncludeCategories: + - Regex: '.*' + Priority: 1 +IncludeIsMainRegex: '(Test)?$' +IndentCaseLabels: false +#IndentPPDirectives: None # Unknown to clang-format-5.0 +IndentWidth: 8 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0 +ObjCBlockIndentWidth: 8 +ObjCSpaceAfterProperty: true +ObjCSpaceBeforeProtocolList: true + +# Taken from git's rules +#PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0 +PenaltyBreakBeforeFirstCallParameter: 30 +PenaltyBreakComment: 10 +PenaltyBreakFirstLessLess: 0 +PenaltyBreakString: 10 +PenaltyExcessCharacter: 100 +PenaltyReturnTypeOnItsOwnLine: 60 + +PointerAlignment: Right +ReflowComments: false +SortIncludes: false +#SortUsingDeclarations: false # Unknown to clang-format-4.0 +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +#SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0 +#SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0 +SpaceBeforeParens: ControlStatements +#SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0 +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp03 +TabWidth: 8 +UseTab: Always +... diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..7592deb --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +open_collective: osmocom @@ -18,6 +18,11 @@ tags *.bin *.p host/simtrace2-list -host/simtrace2-remsim -host/simtrace2-remsim-usb2udp +host/simtrace2-cardem-pcsc +host/contrib/simtrace2.spec +host/src/simtrace2-tool +host/tests usb_strings_generated.h +firmware/usbstring/usbstring +firmware/apps/*/usb_strings.txt.patched +firmware/misc/crctool
\ No newline at end of file diff --git a/.gitreview b/.gitreview new file mode 100644 index 0000000..d1ed04a --- /dev/null +++ b/.gitreview @@ -0,0 +1,3 @@ +[gerrit] +host=gerrit.osmocom.org +project=simtrace2 @@ -8,19 +8,34 @@ fw-$(1)-$(2)-clean: endef $(eval $(call RULES,simtrace,dfu)) +$(eval $(call RULES,simtrace,blupdate)) $(eval $(call RULES,simtrace,trace)) $(eval $(call RULES,simtrace,cardem)) $(eval $(call RULES,qmod,dfu)) +$(eval $(call RULES,qmod,blupdate)) $(eval $(call RULES,qmod,cardem)) +$(eval $(call RULES,ngff_cardem,dfu)) +$(eval $(call RULES,ngff_cardem,blupdate)) +$(eval $(call RULES,ngff_cardem,trace)) +$(eval $(call RULES,ngff_cardem,cardem)) -fw-clean: fw-simtrace-dfu-clean fw-simtrace-trace-clean fw-simtrace-cardem-clean fw-qmod-dfu-clean fw-qmod-cardem-clean -fw: fw-simtrace-dfu fw-simtrace-trace fw-simtrace-cardem fw-qmod-dfu fw-qmod-cardem +fw-clean: fw-simtrace-dfu-clean fw-simtrace-blupdate-clean fw-simtrace-trace-clean fw-simtrace-cardem-clean \ + fw-qmod-dfu-clean fw-qmod-blupdate-clean fw-qmod-cardem-clean \ + fw-ngff_cardem-dfu-clean fw-ngff_cardem-blupdate-clean fw-ngff_cardem-trace-clean fw-ngff_cardem-cardem-clean +fw: fw-simtrace-dfu fw-simtrace-blupdate fw-simtrace-trace fw-simtrace-cardem \ + fw-qmod-dfu fw-qmod-blupdate fw-qmod-cardem \ + fw-ngff_cardem-dfu fw-ngff_cardem-blupdate fw-ngff_cardem-trace fw-ngff_cardem-cardem utils: - make -C host + (cd host && \ + autoreconf -fi && \ + ./configure --prefix=/usr --disable-werror && \ + make) clean: fw-clean - make -C host clean + if [ -e host/Makefile ]; then \ + make -C host clean; \ + fi install: make -C firmware install @@ -5,9 +5,6 @@ This is the repository for the next-generation SIMtrace devices, providing abilities to trace the communication between (U)SIM card and phone, remote (U)SIM card forward, (U)SIM man-in-the-middle, and more. -This is under heavy development, and right now it is not surprising if -things still break on a daily basis. - NOTE: Nothing in this repository applies to the SIMtrace v1.x hardware or its associated firmware. SIMtrace v1.x is based on a different CPU / microcontroller architecture and uses a completely different software @@ -16,18 +13,17 @@ stack and host software. Supported Hardware ------------------ -At this point, the primary development target is still the OWHW + sysmoQMOD -device, but we expect to add support for a SAM3 based SIMtrace hardware -board soon. - -The goal is to support the following devices: - -* Osmocom SIMtrace 1.x with SAM3 controller -** this is open hardware and schematics / PCB design is published -* sysmocom sysmoQMOD (with 4 Modems, 4 SIM slots and 2 SAM3) -** this is a proprietary device, publicly available from sysmocom +* Osmocom [SIMtrace2](https://osmocom.org/projects/simtrace2/wiki) with SAM3 controller + * this is open hardware and schematics / PCB design is published + * pre-built hardware available from [sysmocom webshop](https://shop.sysmocom.de/SIMtrace2-Hardware-Kit/simtrace2-kit) +* Osmocom [ngff-cardem](https://osmocom.org/projects/ngff-cardem/wiki) M.2/NGFF modem carrier with SAM3 controller + * this is open hardware and schematics / PCB design is published + * pre-built hardware available from [sysmocom webshoo](https://shop.sysmocom.de/M.2-modem-carrier-with-remote-SIM-tracing/ngff-cardem-kit-external) +* sysmocom [sysmoQMOD](https://sysmocom.de/products/lab/sysmoqmod/index.html) (with 4 Modems, 4 SIM slots and 2 SAM3) + * this is a proprietary device, publicly available from sysmocom + * hardware evaluation kit available from [sysmocom webshop](https://shop.sysmocom.de/sysmoQMOD-evaluation-kit/sysmoQMOD-evk) * sysmocom OWHW (with 2 Modems and 1 SAM3 onboard) -** this is not publicly available hardware, but still supported + * this is not publicly available hardware, but still supported This Repository --------------- @@ -37,3 +33,11 @@ This repository contains several directory * firmware - the firmware to run on the actual devices * hardware - some information related to the hardware * host - Programs to use on the USB host to interface with the hardware + + +The host software includes + +* libosmo-simtrace2 - a shared library to talk to devices running the simtrace2 firmware +* simtrace2-list - list any USB-attached devices running simtrace2 firmware +* simtrace2-sniff - interface the 'trace' firmware to obtain card protocol traces +* simtrace2-cardem-pcsc - interface the 'cardem' fimrware to use a SIM in a PC/SC reader diff --git a/TODO-RELEASE b/TODO-RELEASE new file mode 100644 index 0000000..5da461b --- /dev/null +++ b/TODO-RELEASE @@ -0,0 +1,10 @@ +# When cleaning up this file: bump API version in corresponding Makefile.am and rename corresponding debian/lib*.install +# according to https://osmocom.org/projects/cellular-infrastructure/wiki/Make_a_new_release +# In short: https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info +# LIBVERSION=c:r:a +# If the library source code has changed at all since the last update, then increment revision: c:r + 1:a. +# If any interfaces have been added, removed, or changed since the last update: c + 1:0:0. +# If any interfaces have been added since the last public release: c:r:a + 1. +# If any interfaces have been removed or changed since the last public release: c:r:0. +#library what description / commit summary line +simtrace2 API/ABI change osmo_st2_transport new member diff --git a/contrib/flash.py b/contrib/flash.py new file mode 100755 index 0000000..01fe7c9 --- /dev/null +++ b/contrib/flash.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python +# encoding: utf-8 +# python: 3.8.1 + +# library to enumerate USB devices +import usb.core +from usb.util import * +# more elegant structure +from typing import NamedTuple +# regular expressions utilities +import re +# open utilities to handle files +import os, sys +# to download the firmwares +import urllib.request +# to flash using DFU-util +import subprocess + +# SIMtrace 2 device information +class Device(NamedTuple): + usb_vendor_id: int + usb_product_id: int + name: str + url: dict # 1: sniff/trace firmware, 2: card emulation firmware + +# SIMtrace 2 devices definitions +DEVICE_SIMTRACE = Device(usb_vendor_id=0x1d50, usb_product_id=0x60e3, name="SIMtrace 2", url={"trace": "https://ftp.osmocom.org/binaries/simtrace2/firmware/latest/simtrace-trace-dfu-latest.bin", "cardem": "https://osmocom.org/attachments/download/3868/simtrace-cardem-dfu.bin"}) +DEVICE_QMOD = Device(usb_vendor_id=0x1d50, usb_product_id=0x4004, name="sysmoQMOD (Quad Modem)", url={"cardem": "https://ftp.osmocom.org/binaries/simtrace2/firmware/latest/qmod-cardem-dfu-latest.bin"}) +DEVICE_OWHW = Device(usb_vendor_id=0x1d50, usb_product_id=0x4001, name="OWHW", url={"cardem": "https://ftp.osmocom.org/binaries/simtrace2/firmware/latest/owhw-cardem-dfu-latest.bin"}) +DEVICE_OCTSIMTEST = Device(usb_vendor_id=0x1d50, usb_product_id=0x616d, name="OCTSIMTEST", url={"cardem": "https://ftp.osmocom.org/binaries/simtrace2/firmware/latest/octsimtest-cardem-dfu-latest.bin"}) +DEVICE_NGFF_CARDEM = Device(usb_vendor_id=0x1d50, usb_product_id=0x616e, name="ngff-cardem", url={"cardem": "https://ftp.osmocom.org/binaries/simtrace2/firmware/latest/ngff_cardem-cardem-dfu-latest.bin"}) +DEVICES = [DEVICE_SIMTRACE, DEVICE_QMOD, DEVICE_OCTSIMTEST, DEVICE_NGFF_CARDEM] + +# which firmware does the SIMtrace USN interface subclass correspond +FIRMWARE_SUBCLASS = {1: "trace", 2: "cardem"} + +def print_help(): + print("this script will flash SIMtrace 2 - based devices") + print("when no argument is provided, it will try to flash the application firmware of all SIMtrace 2 devices connected to USB with the latest version") + print("to flash a specific firmware, provide the name as argument") + print("the possible firmwares are: trace, cardem") + print("to list all devices connected to USB, provide the argument \"list\"") + +# the firmware to flash +to_flash = None + +# parse command line argument +if len(sys.argv) == 2: + to_flash = sys.argv[1] +if to_flash not in ["list", "trace", "cardem"] and len(sys.argv) > 1: + print_help() + exit(0) + +# get all USB devices +devices = [] +devices_nb = 0 +updated_nb = 0 +usb_devices = usb.core.find(find_all=True) +for usb_device in usb_devices: + # find SIMtrace devices + definitions = list(filter(lambda x: x.usb_vendor_id == usb_device.idVendor and x.usb_product_id == usb_device.idProduct, DEVICES)) + if 1 != len(definitions): + continue + devices_nb += 1 + definition = definitions[0] + serial = usb_device.serial_number or "unknown" + usb_path = str(usb_device.bus) + "-" + ".".join(map(str, usb_device.port_numbers)) + print("found " + definition.name + " device (chip ID " + serial + ") at USB path " + usb_path) + # determine if we are running DFU (in most cases the bootloader, but could also be the application) + dfu_interface = None + for configuration in usb_device: + # get DFU interface descriptor + dfu_interface = dfu_interface or find_descriptor(configuration, bInterfaceClass=254, bInterfaceSubClass=1) + if (None == dfu_interface): + print("no DFU USB interface found") + continue + dfu_mode = (2 == dfu_interface.bInterfaceProtocol) # InterfaceProtocol 1 is runtime mode, 2 is DFU mode + # determine firmware type (when not in DFU mode) + firmware = None + simtrace_interface = None + for configuration in usb_device: + simtrace_interface = simtrace_interface or find_descriptor(configuration, bInterfaceClass=255) + if simtrace_interface and simtrace_interface.bInterfaceSubClass in FIRMWARE_SUBCLASS: + firmware = firmware or FIRMWARE_SUBCLASS[simtrace_interface.bInterfaceSubClass] + if dfu_mode: + firmware = 'dfu' + if firmware: + print("installed firmware: " + firmware) + else: + print("unknown installed firmware") + continue + # determine version of the application/bootloader firmware + version = None + version_interface = None + for configuration in usb_device: + # get custom interface with string + version_interface = version_interface or find_descriptor(configuration, bInterfaceClass=255, bInterfaceSubClass=255) + if version_interface and version_interface.iInterface and version_interface.iInterface > 0 and get_string(usb_device, version_interface.iInterface): + version = get_string(usb_device, version_interface.iInterface) + if not version: + # the USB serial is set (in the application) since version 0.5.1.34-e026 from 2019-08-06 + # https://git.osmocom.org/simtrace2/commit/?id=e0265462d8c05ebfa133db2039c2fbe3ebbd286e + # the USB serial is set (in the bootloader) since version 0.5.1.45-ac7e from 2019-11-18 + # https://git.osmocom.org/simtrace2/commit/?id=5db9402a5f346e30288db228157f71c29aefce5a + # the firmware version is set (in the application) since version 0.5.1.37-ede8 from 2019-08-13 + # https://git.osmocom.org/simtrace2/commit/?id=ede87e067dadd07119f24e96261b66ac92b3af6f + # the firmware version is set (in the bootloader) since version 0.5.1.45-ac7e from 2019-11-18 + # https://git.osmocom.org/simtrace2/commit/?id=5db9402a5f346e30288db228157f71c29aefce5a + if dfu_mode: + if serial: + version = "< 0.5.1.45-ac7e" + else: + versoin = "< 0.5.1.45-ac7e" + else: + if serial: + version = "< 0.5.1.37-ede8" + else: + versoin = "< 0.5.1.34-e026" + print("device firmware version: " + version) + # flash latest firmware + if to_flash == "list": # we just want to list the devices, not flash them + continue + # check the firmware exists + if firmware == "dfu" and to_flash is None: + print("device is currently in DFU mode. you need to specify which firmware to flash") + continue + to_flash = to_flash or firmware + if to_flash not in definition.url.keys(): + print("no firmware image available for " + firmware + " firmware") + continue + # download firmware + try: + dl_path, header = urllib.request.urlretrieve(definition.url[to_flash]) + except: + print("could not download firmware " + definition.url[to_flash]) + continue + dl_file = open(dl_path, "rb") + dl_data = dl_file.read() + dl_file.close() + # compare versions + dl_version = re.search(b'firmware \d+\.\d+\.\d+\.\d+-[0-9a-fA-F]{4}', dl_data) + if dl_version is None: + print("could not get version from downloaded firmware image") + os.remove(dl_path) + continue + dl_version = dl_version.group(0).decode("utf-8").split(" ")[1] + print("latest firmware version: " + dl_version) + versions = list(map(lambda x: int(x), version.split(" ")[-1].split("-")[0].split("."))) + dl_versions = list(map(lambda x: int(x), dl_version.split("-")[0].split("."))) + dl_newer = (versions[0] < dl_versions[0] or (versions[0] == dl_versions[0] and versions[1] < dl_versions[1]) or (versions[0] == dl_versions[0] and versions[1] == dl_versions[1] and versions[2] < dl_versions[2]) or (versions[0] == dl_versions[0] and versions[1] == dl_versions[1] and versions[2] == dl_versions[2] and versions[3] < dl_versions[3])) + if not dl_newer: + print("no need to flash latest version") + os.remove(dl_path) + continue + print("flashing latest version") + dfu_result = subprocess.run(["dfu-util", "--device", hex(definition.usb_vendor_id) + ":" + hex(definition.usb_product_id), "--path", usb_path, "--cfg", "1", "--alt", "1", "--reset", "--download", dl_path]) + os.remove(dl_path) + if 0 != dfu_result.returncode: + printf("flashing firmware using dfu-util failed. ensure dfu-util is installed and you have the permissions to access this USB device") + continue + updated_nb += 1 + +print(str(devices_nb)+ " SIMtrace 2 device(s) found") +print(str(updated_nb)+ " SIMtrace 2 device(s) updated") diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index 99a6f00..e53a450 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -21,22 +21,51 @@ mkdir "$deps" || true osmo-build-dep.sh libosmocore "" '--disable-doxygen --enable-gnutls' +# verify only after building the dependency (to ensure we have most recent source of dependency) +verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]") + export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH" export LD_LIBRARY_PATH="$inst/lib" -BUILDS="" -BUILDS+="simtrace/dfu simtrace/cardem simtrace/trace " # simtrace/triple_play -BUILDS+="qmod/dfu qmod/cardem " -BUILDS+="owhw/dfu owhw/cardem " +# dfu target MUST be built first, the combined targets need a bl that can be combined.. +BUILDS="simtrace/dfu qmod/dfu owhw/dfu ngff_cardem/dfu " +# +BUILDS+="simtrace/blupdate qmod/blupdate owhw/blupdate ngff_cardem/blupdate " +BUILDS+="simtrace/cardem qmod/cardem owhw/cardem octsimtest/cardem ngff_cardem/cardem " +BUILDS+="simtrace/trace ngff_cardem/trace " cd $TOPDIR/firmware for build in $BUILDS; do board=`echo $build | cut -d "/" -f 1` app=`echo $build | cut -d "/" -f 2` + case "$build" in + "owhw/cardem") + comb="combined" + ;; + "qmod/cardem") + comb="combined" + ;; + "ngff_cardem/cardem") + comb="combined" + ;; + "simtrace/trace") + comb="combined" + ;; + *) + comb="" + ;; + esac echo - echo "=============== $board / $app START ==============" - make BOARD="$board" APP="$app" - echo "=============== $board / $app RES:$? ==============" + # Build the bootloader with clang, the rest with gcc (OS#5260, OS#6026) + if [ "$app" = "dfu" ]; then + echo "=============== $board / $app START (CLANG) ==============" + PATH="/opt/llvm-arm/bin:$PATH" make USE_CLANG=1 BOARD="$board" APP="$app" $comb + echo "=============== $board / $app RES:$? ==============" + else + echo "=============== $board / $app START (GCC) ==============" + make USE_CLANG=0 BOARD="$board" APP="$app" $comb + echo "=============== $board / $app RES:$? ==============" + fi done echo @@ -50,24 +79,36 @@ make clean echo echo "=============== HOST START ==============" cd $TOPDIR/host -make clean -make -make clean +autoreconf --install --force +./configure --enable-sanitize --enable-werror +$MAKE $PARALLEL_MAKE +#$MAKE distcheck || cat-testlogs.sh +make dist + +#if [ "$WITH_MANUALS" = "1" ] && [ "$PUBLISH" = "1" ]; then +# make -C "$base/doc/manuals" publish +#fi if [ "x$publish" = "x--publish" ]; then echo echo "=============== UPLOAD BUILD ==============" + $TOPDIR/contrib/prepare_upload.sh - cat > "$WORKSPACE/known_hosts" <<EOF -[rita.osmocom.org]:48 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDgQ9HntlpWNmh953a2Gc8NysKE4orOatVT1wQkyzhARnfYUerRuwyNr1GqMyBKdSI9amYVBXJIOUFcpV81niA7zQRUs66bpIMkE9/rHxBd81SkorEPOIS84W4vm3SZtuNqa+fADcqe88Hcb0ZdTzjKILuwi19gzrQyME2knHY71EOETe9Yow5RD2hTIpB5ecNxI0LUKDq+Ii8HfBvndPBIr0BWYDugckQ3Bocf+yn/tn2/GZieFEyFpBGF/MnLbAAfUKIdeyFRX7ufaiWWz5yKAfEhtziqdAGZaXNaLG6gkpy3EixOAy6ZXuTAk3b3Y0FUmDjhOHllbPmTOcKMry9 -[rita.osmocom.org]:48 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPdWn1kEousXuKsZ+qJEZTt/NSeASxCrUfNDW3LWtH+d8Ust7ZuKp/vuyG+5pe5pwpPOgFu7TjN+0lVjYJVXH54= -[rita.osmocom.org]:48 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK8iivY70EiR5NiGChV39gRLjNpC8lvu1ZdHtdMw2zuX + cat > "/build/known_hosts" <<EOF +[ftp.osmocom.org]:48 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDgQ9HntlpWNmh953a2Gc8NysKE4orOatVT1wQkyzhARnfYUerRuwyNr1GqMyBKdSI9amYVBXJIOUFcpV81niA7zQRUs66bpIMkE9/rHxBd81SkorEPOIS84W4vm3SZtuNqa+fADcqe88Hcb0ZdTzjKILuwi19gzrQyME2knHY71EOETe9Yow5RD2hTIpB5ecNxI0LUKDq+Ii8HfBvndPBIr0BWYDugckQ3Bocf+yn/tn2/GZieFEyFpBGF/MnLbAAfUKIdeyFRX7ufaiWWz5yKAfEhtziqdAGZaXNaLG6gkpy3EixOAy6ZXuTAk3b3Y0FUmDjhOHllbPmTOcKMry9 +[ftp.osmocom.org]:48 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPdWn1kEousXuKsZ+qJEZTt/NSeASxCrUfNDW3LWtH+d8Ust7ZuKp/vuyG+5pe5pwpPOgFu7TjN+0lVjYJVXH54= +[ftp.osmocom.org]:48 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK8iivY70EiR5NiGChV39gRLjNpC8lvu1ZdHtdMw2zuX EOF - SSH_COMMAND="ssh -o 'UserKnownHostsFile=$WORKSPACE/known_hosts' -p 48" - rsync -avz --delete -e "$SSH_COMMAND" $TOPDIR/firmware/bin/*.bin binaries@rita.osmocom.org:web-files/simtrace2/firmware/ + SSH_COMMAND="ssh -o 'UserKnownHostsFile=/build/known_hosts' -p 48" + rsync --archive --verbose --compress --delete --rsh "$SSH_COMMAND" $TOPDIR/firmware/bin/*-latest.{bin,elf} binaries@ftp.osmocom.org:web-files/simtrace2/firmware/latest/ + rsync --archive --verbose --compress --rsh "$SSH_COMMAND" --exclude $TOPDIR/firmware/bin/*-latest.{bin,elf} $TOPDIR/firmware/bin/*-*-*-*.{bin,elf} binaries@ftp.osmocom.org:web-files/simtrace2/firmware/all/ fi echo +echo "=============== HOST CLEAN ==============" +$MAKE maintainer-clean + +echo echo "=============== FIRMWARE CLEAN ==============" cd $TOPDIR/firmware/ for build in $BUILDS; do diff --git a/contrib/prepare_upload.sh b/contrib/prepare_upload.sh new file mode 100755 index 0000000..cdd144f --- /dev/null +++ b/contrib/prepare_upload.sh @@ -0,0 +1,18 @@ +#!/bin/bash -e +# Create copies of binaries with -latest, -$GIT_VERSION (OS#4413, OS#3452) +cd "$(dirname "$0")/.." + +GIT_VERSION="$(./git-version-gen .tarball-version)" + +echo "Copying binaries with "-latest" and "-$GIT_VERSION" appended..." + +cd firmware/bin +for ext in bin elf; do + for file in *."$ext"; do + if ! [[ "$file" =~ ^(.*padded.*|.*nocrcstub.*bin)$ ]];then + without_ext="${file%.*}" + cp -v "$file" "$without_ext-latest.$ext" + cp -v "$file" "$without_ext-$GIT_VERSION.$ext" + fi + done +done diff --git a/contrib/simtrace.lua b/contrib/simtrace.lua new file mode 100644 index 0000000..9015085 --- /dev/null +++ b/contrib/simtrace.lua @@ -0,0 +1,286 @@ +-- wireshark LUA dissector for the SIMtrace USB protocol +-- (C) 2021 by sysmocom - s.f.m.c. GmbH, Author: Eric Wild +-- SPDX-License-Identifier: GPL-2.0+ +-- +-- Usage: Move this file to your "personal lua plugins" folder that +-- can be found in the Wireshark Help->About Wireshark->Folders tab +-- Windows: %APPDATA%\Wireshark\plugins. +-- Unix-like systems: ~/.local/lib/wireshark/plugins. + +usb_simtrace_protocol = Proto("USB_simtrace", "USB simtrace protocol") + + +local control_commands = { +-- /* SIMTRACE_MSGC_GENERIC */ +[0x0000] = "SIMTRACE_CMD_DO_ERROR", +[0x0001] = "SIMTRACE_CMD_BD_BOARD_INFO", + +-- /* SIMTRACE_MSGC_CARDEM */ +[0x0101] = "DT_CEMU_TX_DATA", +[0x0102] = "DT_CEMU_SET_ATR", +[0x0103] = "BD_CEMU_STATS", +[0x0104] = "BD_CEMU_STATUS", +[0x0105] = "DT_CEMU_CARDINSERT", +[0x0106] = "DO_CEMU_RX_DATA", +[0x0107] = "DO_CEMU_PTS", +[0x0108] = "BD_CEMU_CONFIG", + +-- /* SIMTRACE_MSGC_MODEM */ +[0x0201] = "DT_MODEM_RESET", +[0x0202] = "DT_MODEM_SIM_SELECT", +[0x0203] = "BD_MODEM_STATUS", + +-- /* SIMTRACE_MSGC_SNIFF */ +[0x0300] = "SNIFF_CHANGE", +[0x0301] = "SNIFF_FIDI", +[0x0302] = "SNIFF_ATR", +[0x0304] = "SNIFF_TPDU", +[0x0303] = "SNIFF_PPS" +} + +local msgtype = ProtoField.uint16("usb_simtrace.msgtype", "Message Type", base.HEX_DEC, control_commands) +local seqnr = ProtoField.uint8("usb_simtrace.seqnr", "Sequence Number", base.DEC) +local slotnr = ProtoField.uint8("usb_simtrace.slotnr", "Slot Number", base.DEC) +local reserved = ProtoField.uint16("usb_simtrace.reserved", "reserved", base.HEX_DEC) +local payloadlen = ProtoField.uint16("usb_simtrace.length", "length", base.DEC) +local payload = ProtoField.bytes("usb_simtrace.payload", "Data") + +local pb_and_rx = ProtoField.uint32("usb_simtrace.pb_and_rx", "pb_and_rx", base.HEX_DEC, NULL, 0x8) +local pb_and_tx = ProtoField.uint32("usb_simtrace.pb_and_tx", "pb_and_tx", base.HEX_DEC, NULL, 0x4) +local final = ProtoField.uint32("usb_simtrace.final", "final", base.HEX_DEC, NULL, 0x2) +local tpdu_hdr = ProtoField.uint32("usb_simtrace.tpdu_hdr", "tpdu_hdr", base.HEX_DEC, NULL, 0x1) +local rxtxdatalen = ProtoField.uint16("usb_simtrace.rxtxdatalen", "rx/tx data length", base.DEC) +local rxtxdata = ProtoField.bytes("usb_simtrace.rxtxdata", "rx/tx (data)") + +local hf_pts_len = ProtoField.uint8("usb_simtrace.pts_len", "PTS length", base.DEC) +local hf_pts_req = ProtoField.bytes("usb_simtrace.pts_req", "PTS request") +local hf_pts_resp = ProtoField.bytes("usb_simtrace.pts_resp", "PTS response") + +local hf_cemu_cfg_features = ProtoField.uint32("usb_simtrace.cemu_cfg.features.status_irq", "CardEm Features", base.HEX) +local hf_cemu_cfg_slot_mux_nr = ProtoField.uint32("usb_simtrace.cemu_cfg.features.slot_mux_nr", "CardEm Slot Mux Nr", base.DEC) + +local card_insert_types = { + [0x00] = "not inserted", + [0x01] = "inserted", +} +local hf_cemu_cardinsert = ProtoField.uint8("usb_simtrace.cardinsert", "Card Insert", base.DEC, card_insert_types, 0xff) + +local CEMU_STATUS_F_VCC_PRESENT = ProtoField.uint32("usb_simtrace.CEMU_STATUS.F_VCC_PRESENT", "VCC_PRESENT", base.HEX_DEC, NULL, 0x00000001) +local CEMU_STATUS_F_CLK_ACTIVE = ProtoField.uint32("usb_simtrace.CEMU_STATUS.F_CLK_ACTIVE", "CLK_ACTIVE", base.HEX_DEC, NULL, 0x00000002) +local CEMU_STATUS_F_RCEMU_ACTIVE = ProtoField.uint32("usb_simtrace.CEMU_STATUS.F_RCEMU_ACTIVE", "CEMU_ACTIVE", base.HEX_DEC, NULL, 0x00000004) +local CEMU_STATUS_F_CARD_INSERT = ProtoField.uint32("usb_simtrace.CEMU_STATUS.F_CARD_INSERT", "CARD_INSERT", base.HEX_DEC, NULL, 0x00000008) +local CEMU_STATUS_F_RESET_ACTIVE = ProtoField.uint32("usb_simtrace.CEMU_STATUS.F_RESET_ACTIVE", "RESET_ACTIVE", base.HEX_DEC, NULL, 0x00000010) + +local modem_reset_types = { + [0x00] = "de-assert", + [0x01] = "assert", + [0x02] = "pulse" +} +local modem_reset_status = ProtoField.uint8("usb_simtrace.modem.reset_type", "modem reset type", base.HEX, modem_reset_types, 0xf) +local modem_reset_len = ProtoField.uint8("usb_simtrace.modem.reset_len", "modem reset length (ms)", base.DEC) + +local modem_sim_select_types = { + [0x00] = "local", + [0x01] = "remote", +} +local hf_modem_sim_select = ProtoField.uint8("usb_simtrace.modem.sim_select", "SIM card selection", base.DEC, modem_sim_select_types, 0xff) + +usb_simtrace_protocol.fields = { + msgtype, seqnr, slotnr, reserved, payloadlen, payload, + pb_and_rx, pb_and_tx, final, tpdu_hdr, rxtxdatalen, rxtxdata, + CEMU_STATUS_F_VCC_PRESENT, CEMU_STATUS_F_CLK_ACTIVE, CEMU_STATUS_F_RCEMU_ACTIVE, CEMU_STATUS_F_CARD_INSERT, CEMU_STATUS_F_RESET_ACTIVE, + modem_reset_status, modem_reset_len, + hf_pts_len, hf_pts_req, hf_pts_resp, + hf_cemu_cfg_features, hf_cemu_cfg_slot_mux_nr, + hf_cemu_cardinsert, hf_modem_sim_select, +} + +local is_hdr = Field.new("usb_simtrace.tpdu_hdr") +local is_pbrx = Field.new("usb_simtrace.pb_and_rx") +local is_pbtx = Field.new("usb_simtrace.pb_and_tx") +local is_final= Field.new("usb_simtrace.final") + +function dissect_rxtx(payload_data,pinfo,tree) + + local headerSubtree = tree:add(usb_simtrace_protocol, payload_data, "rx/tx data") + local len = payload_data(4,2):le_uint(); + local cmd32 = payload_data(0,4):le_uint(); + + headerSubtree:add(pb_and_rx, cmd32) + headerSubtree:add(pb_and_tx, cmd32) + headerSubtree:add(final, cmd32) + headerSubtree:add(tpdu_hdr, cmd32) + + headerSubtree:add(rxtxdatalen, len) + headerSubtree:add_le(rxtxdata, payload_data(6,len)) + + local flagstr = " " + if is_pbrx().value == 1 then + flagstr = flagstr .. "R" + else + flagstr = flagstr .. "." + end + if is_pbtx().value == 1 then + flagstr = flagstr .. "T" + else + flagstr = flagstr .. "." + end + if is_final().value == 1 then + flagstr = flagstr .. "F" + else + flagstr = flagstr .. "." + end + if is_hdr().value == 1 then + flagstr = flagstr .. "H" + else + flagstr = flagstr .. "." + end + flagstr = flagstr .. " " + pinfo.cols.info:append(flagstr .. payload_data(6,len)) + + -- ghetto dissection does not work due to mixed in procedure bytes + --if pinfo.visited == false then + -- Dissector.get("iso7816"):call(payload_data(6):tvb(), pinfo, tree) + +-- local offs = 0 +-- if (is_pbrx().value == 1 or is_pbtx().value == 1) and is_final().value == 0 then +-- offs = 1 +-- else +-- offs = 0 +-- end +-- +-- if is_hdr().value == 1 then +-- Dissector.get("gsm_sim"):call(concatss:tvb(), pinfo, tree) +-- concatss = payload_data(6):bytes() +-- else +-- concatss = concatss .. payload_data(6+offs):bytes() +-- end + +--end + +end + +function dissect_status(payload_data,pinfo,tree) + + local headerSubtree = tree:add(usb_simtrace_protocol, payload_data, "status message") + local cmd32 = payload_data(0,4):le_uint(); + + headerSubtree:add(CEMU_STATUS_F_VCC_PRESENT, cmd32) + headerSubtree:add(CEMU_STATUS_F_CLK_ACTIVE, cmd32) + headerSubtree:add(CEMU_STATUS_F_RCEMU_ACTIVE, cmd32) + headerSubtree:add(CEMU_STATUS_F_CARD_INSERT, cmd32) + headerSubtree:add(CEMU_STATUS_F_RESET_ACTIVE, cmd32) + + pinfo.cols.info:append(" VCC:" .. payload_data(0,1):bitfield(7, 1) .. " CLK:" .. payload_data(0,1):bitfield(6, 1) .. " RESET:" .. payload_data(0,1):bitfield(3, 1)) +end + +function dissect_atr(payload_data,pinfo,tree) + + local len = payload_data(0,1):le_uint() + Dissector.get("iso7816.atr"):call(payload_data(1):tvb(), pinfo, tree) +end + +function dissect_modem_reset(payload_data,pinfo,tree) + + local headerSubtree = tree:add(usb_simtrace_protocol, payload_data, "modem reset") + local cmd8 = payload_data(0,1):le_uint(); + + headerSubtree:add(modem_reset_status, cmd8) + pinfo.cols.info:append(" reset type:" .. modem_reset_types[cmd8]); + + if(cmd8 == 2) then + local duration = payload_data(1,2):le_uint() + headerSubtree:add(modem_reset_len, duration) + pinfo.cols.info:append(" duration:" .. duration .. "ms") + end + + +end + +function dissect_pts(payload_data, pinfo, tree) + local subtree = tree:add(usb_simtrace_protocol, payload_data, "PTS") + local pts_len = payload_data(0,1):le_uint() + local pts_req = payload_data(1, pts_len); + local pts_resp = payload_data(7, pts_len); + + subtree:add(hf_pts_len, pts_len); + subtree:add(hf_pts_req, pts_req); + subtree:add(hf_pts_resp, pts_resp); + + pinfo.cols.info:append(" Req: " .. pts_req .. ", Resp: " .. pts_resp); +end + +function dissect_cemu_config(payload_data, pinfo, tree) + local subtree = tree:add(usb_simtrace_protocol, payload_data, "Card Emu Config") + + subtree:add(hf_cemu_cfg_features, payload_data(0,4)); + subtree:add(hf_cemu_cfg_slot_mux_nr, payload_data(4,1)); +end + +function dissect_modem_sim_sel(payload_data, pinfo, tree) + local subtree = tree:add(usb_simtrace_protocol, payload_data, "Modem SIM Select") + local sim_select = payload_data(0,1):le_uint(); + + subtree:add(hf_modem_sim_select, sim_select); + pinfo.cols.info:append(" " .. modem_sim_select_types[sim_select]); +end + +function dissect_cemu_cardinsert(payload_data, pinfo, tree) + local subtree = tree:add(usb_simtrace_protocol, payload_data, "Card Insert") + local cins_type = payload_data(0,1):le_uint() + + subtree:add(hf_cemu_cardinsert, cins_type); + pinfo.cols.info:append(" " .. card_insert_types[cins_type]); +end + + + +function usb_simtrace_protocol.dissector(buffer, pinfo, tree) + length = buffer:len() + if length == 0 then return end + + pinfo.cols.protocol = usb_simtrace_protocol.name + + local subtree = tree:add(usb_simtrace_protocol, buffer(), "USB simtrace Data") + local command = buffer(0,2):uint() + + subtree:add(msgtype, command):set_generated() + subtree:add(seqnr, buffer(2,1)) + subtree:add(slotnr, buffer(3,1)) + subtree:add_le(payloadlen, buffer(6,2)) + pinfo.cols.info = string.format("Cmd 0x%04X : %s", command, control_commands[command]) + local payload_data = buffer(8,length-8) + if(command == 0x0101 or command == 0x0106) then + return dissect_rxtx(payload_data(),pinfo,subtree) + elseif(command == 0x0104) then + return dissect_status(payload_data(),pinfo,subtree) + elseif(command == 0x0102) then + return dissect_atr(payload_data(),pinfo,subtree) + elseif(command == 0x0105) then + return dissect_cemu_cardinsert(payload_data(),pinfo,subtree) + elseif(command == 0x0107) then + return dissect_pts(payload_data(),pinfo,subtree) + elseif(command == 0x0108) then + return dissect_cemu_config(payload_data(),pinfo,subtree) + elseif(command == 0x0201) then + return dissect_modem_reset(payload_data(),pinfo,subtree) + elseif(command == 0x0202) then + return dissect_modem_sim_sel(payload_data(),pinfo,subtree) + else + subtree:add(payload, payload_data) + end + +end + + +function usb_simtrace_protocol.init() + local usb_product_dissectors = DissectorTable.get("usb.product") + usb_product_dissectors:add(0x1d50616d, usb_simtrace_protocol) -- OCTSIMTEST + usb_product_dissectors:add(0x1d50616e, usb_simtrace_protocol) -- NGFF_CARDEM + usb_product_dissectors:add(0x1d5060e3, usb_simtrace_protocol) -- SIMTRACE2 + usb_product_dissectors:add(0x1d504004, usb_simtrace_protocol) -- QMOD + usb_product_dissectors:add(0x1d504001, usb_simtrace_protocol) -- OWHW + DissectorTable.get("usb.device"):add_for_decode_as(usb_simtrace_protocol) + DissectorTable.get("usb.bulk"):add(0xffff, usb_simtrace_protocol) + DissectorTable.get("usb.interrupt"):add(0xffff, usb_simtrace_protocol) +end diff --git a/debian/changelog b/debian/changelog index a3da488..99cfb8b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,212 @@ +simtrace2 (0.8.1) unstable; urgency=medium + + * host/contrib/simtrace2.spec.in: fix soname + + -- Oliver Smith <osmith@sysmocom.de> Fri, 10 Dec 2021 10:04:28 +0100 + +simtrace2 (0.8.0) unstable; urgency=medium + + [ Harald Welte ] + * adapt to host tools in autotools + * simtrace2_api: Remove dead code + * fix baudrate of 'make log' + * qmod DFU: Don't overwrite memory beyond end of usb_strings[] + * usb_strings.txt: s/SIMtrace Phone/SIMtrace Card Emulation/ + * Patch actual board name into the USB iProduct string descriptor + * Build only 'reasonable' combinations of APP/MEMORY + * stdio: Add support for %p format string (pointer address) + * Fix format string related warnings (int vs. long) + * Add missing CR to achieve CRLF at end of log lines + * more comments in host_communication.c. + * usb_buf: count number of elements in queue + * usb_buf: Limit the maximum queue length to 3 elements + * qmod: Don't print EEPROM operations in help when not supported + * cosmetic: board_qmod: Annotate #endif with comments + * qmod: Document '!' and '@' commands on UART + * implement minimalistic talloc_report(); add 't' command on UART + * update copyright statement + * cardem: Fix memory leak on unsupported SIMTRACE_MSGT_DT_CEMU_CARDINSERT + * usb_buf: Actually limit queue to 3 elements, not 4 + * USBD_HAL: Don't disable UDP peripheral clock on suspend + * usb_buf: Properly initialize buffered_endpoint->ep number + * pseudo_talloc: Increment number of buffers from 10 to 20 + * card_emu: Factor out card_handle_reset() from card_emu_init() + * cardem: Move card_emu_io_statechg() calls out of interrupt context + * cardem: RST resets all state (including release of buffers) + * host_communication: Send zero-length-packet on wMaxPacketSize + * card_emu: Initialize PTSS state every time we start PTS + * card_emu: Avoid recursive calls to card_set_state() + * card_emu: Always print state names in string representation + * card_emu: Remove extraneous code + * card_emu: Remove extraneous initialization of ch->pts.state + * cardem: Make card_emu_report_status() optionally use IRQ endpoint + * cardem: Add SIMTRACE_MSGT_BD_CEMU_CONFIG + * cardem: Implement support for CEMU_FEAT_F_STATUS_IRQ + * simtrace2-sniff: Reformat value_string to pass our validation scripts + * firmware: Reformat value_string to pass our validation scripts + * jenkins.sh: Add verify_value_string_arrays_are_terminated.py + * [lib] apdu_dispatch: Use DLGLOBAL and don't printf() directly + * [lib] apdu_dispatch: Don't print APDU state to stdout + * OSMO_ASSERT() on double-free or invalid pointer + * Update .gitignore file for host + * migrate to libosmousb + * library: Add osmo_st2_compatible_dev_idsp[] + * firmware: move printing of welcome banner to common function print_banner() + * firmware: apps/cardem/main.c: Synchronize with apps/trace/main.c + * host: Add COPYING file for host software (GPLv2) + * host/lib/gsmtap.c: Add GPLv2 disclaimer + * increase ringbuffer size from 512 to 1024 bytes + * simtrace2_api: Add osmo_st2_cardem_request_config() + * Disable interrupts during EEFC_ReadUniqueID() + * cardem: Fix infinite loop + watchdog reset on long OUT message + * extend osmo_st2_cardem_inst with fields required by osmo-remsim + * cosmetic: Add missing CR to LF in dispatch_received_usb_msg() + * USBD.c: Don't reset EP0 on SetConfiguration(0) + * pio_it.c: Permit repeated calls to PIO_ConfigureIt() + * simtrace2_siff: getopt_long() returns int, not char + * Introduce support for asynchronous USB transmission + * firmware: fix builds with gcc stack smashing protection enabled + * dfu: Shrink code by 144 bytes (by not calling PIO_InitializeInterrupts) + * dfu: Save another 60 bytes by changing the way we print horizontal lines + * migrate from BSC_FD_* to OSMO_FD_* + * remove usb2udp + * rename simtrace2-remsim to simtrace2-cardem-pcsc + * Update README + * remove old pre-autoconf makefile + * simtrace2-cardem-pcsc: Make it work again + * Revert "add ISO 7816-3 library to remsim project" + * Revert "add library providing ISO 7816-3 utilities" + * card_emu: waiting_time is stored in etu, not clocks. + * card_emu: Rename fi to Fi and di to Di + * card_emu: Clarify and differentiate F/Fi/F_index/Fi_index + * iso7816_fidi: Add iso7816_3_ prefix to symbols; fix terminology + * card_emu: improve reset detection conditions + * card_emu: explicitly initialize PTS and TPDU states + * card_emu: Use USART timeout for waiting time + * card_emu: Fix USART timer, particularly in re-start situations + * card_emu: Fix computation of waiting time + * contrib/jenkins.sh: Switch from rita -> ftp.osmocom.org + * st2-cardem-pcsc: Fix goto-in-while mess + * st2-cardem-pcsc: Use ATR of real card by default + * simtrace board.h: Enable HAVE_CARDEM if we build the cardem firmware + * jenkins.sh: build 'cardem' firmware also for simtrace board + * Revert "cardem: disable upload for simtrace2" + * simtrace2-cardem-pcsc: Decode STATUS flags to strings + * simtrace2-cardem-pcsc: Reset the real card if reader resets cardem + * assert: Use printf_sync() to ensure printing of assert / panic + * Add usb product ID of sysmoOCTSIMTEST + * octsimtest: remove lots of unused #defines + * octsimtest: most code for support of this new board + * octsimtest: Switch direction of I/O level shifter depending on uart tx / rx + * cardem-pcsc: initialize libosmocore logging + * octsimtest: Adjust VCC voltage thresholds (resistive VCC divider) + * contrib/jenkins.sh: Build 'cardem' app for 'octsimtest' board + * firmware: octsimtest: Fix IO_DIR pin definition + * firmware: octsimtest: Make slot mux configurable via USB + * firmware: octsimtest: mcp23017 initializaiton + * firmware: cardem: re-factor CARDINSERT command processing + * firmware: octsimtest: Support SIMTRACE_MSGT_DT_CEMU_CARDINSERT + * firmware: octsimtest: use TRACE_* macros instead of direct printf + * firmware: octsimtest: Fix disabling the card_insert signal + * firmware: octsimtest: Add i/I command for setting card-insert via I2C GPIO + * firmware: octsimtest: ensure all card_insert GPIO are 0 after reset + * don't printf() directly from library code, go via libosmocore logging + * simtrace2-list: Use osmo_st2_compatible_dev_ids[] + * board_gpio.gnumeric: Add ngff-cardem pin-out + * 99-simtrace2.rules: Add OCTSIMTEST + * contrib/flash.py: Add OCTSIMTEST support + * Introduce simtrace2-tool + * introduce support for new ngff_cardem board + * simtrace2.spec: Add simtrace2-tool binary to package + * contrib/jenkins.sh: Build APP=cardem for BOARD=ngff_cardem + * jenkins.sh: Build 'trace' firmware for ngff_cardem + * Use osmo_libusb_{init,exit}() instead of libusb_{init,exit}() + * simtrace2-cardem-pcsc: Remove double libusb initialization + * simtrace2-tool: Initialize logging to avoid error on first log output + * cardem-pcsc: Fix return of uninitialized variable + * host: Upgrade libosmocore dependency to 1.4.0 + + [ Kévin Redon ] + * minor: fix spacing + * minor: updated copyright years + * dfu: minor: make debug output only verbose in info level + * minor: move USB debug output from info to debug level + * minor: improve debug output + * minor : fix typo in comment + * better detect VCC and nRST changes on simtrace2 board + * minor: ignore usbstring binary + * simtrace2-remsim: Use simplest ATR + * cardem: use simplest ATR as default ATR + * minor: fix typo + * DFU: increase USB reset duration to 50 ms + * DFU: restart bootloader when USB conf failed + * Makefile: add linker option showing memory usage + * improve shared bootloader/application memory + * minor: improve trace output + * DFU: add DFU application + * add script to flash latest firmware + * minor: use same LED pattern for cardem as other applications + * cardem: currently simtrace does not support cardem + * add library providing ISO 7816-3 utilities + * add ISO 7816-3 library to remsim project + * rename PIN_PHONE_{CLK,IO} to PIN_USIM1_{CLK,IO} + * minor add comments + * make sim switch board specific + + [ Eric Wild ] + * remsim: allow selecting pcsc reader number + * cardem: disable upload for simtrace2 + * firmware: do not allow undefined symbols + * firmware: allow verbose builds + * cardem: choose a more reasonable default ATR + * contrib: add a basic simtrace lua dissector for wireshark + * cardem: free the buf + * cardemu: support 1v8 for the tester + * firmware: data sections + * firmware: proper makefile deps + * firmware: make the ngff beakout blink + * simtrace2-cardem: use local sim on exit + * contrib: more cardem dissection + * firmware: trace for ngff + * cardem: fix spurious NULL bytes during transfers + * contrib/jenkins.sh: build ngff_Cardem dfu bootloader + * contrib: allow manually forcing bulk simtrace dissection + * contrib/jenkins.sh: lower trace to make bl fit + * Revert "firmware: data sections" + * add the ngff cardem to default build targets + * drop unused exidx sections when linking + * clang build support + * fix bootloader led config crash + * firmware: add bootloader update "app" + * firmware: remove usb pullup that dates back to simtrace1 + * firmware: increase reset delay before usb reattach + * firmware: drop cref printing + * add our default clang-format file + * firmware: add missing usb strings to blupdate that prevented building it + * jenkins: build bootloader updater + * firmware: remove dfu-dfu default target + + [ Oliver Smith ] + * contrib: import RPM spec + * contrib: integrate RPM spec + * d/source/format: new file + * firmware/Makefile: fix UNKNOWN in OBS packages + * host: use git-version-gen/tarball-v. from topdir + * gitignore: add firmware/apps/*/usb_strings.txt.patched + * firmware: create duplicate files for upload only + * contrib/prepare_upload.sh: fix cd problems + * firmware: qmod-dfu: disable stack protector + * firmware: disable stack protector by default + * gitreview: new file + + [ Leonard Hübner ] + * remsim: adding cli argument to set the atr + + [ Eric ] + * dfu: let the device reset itself + + -- Harald Welte <laforge@osmocom.org> Thu, 09 Dec 2021 08:12:56 +0100 + simtrace2 (0.5.1) unstable; urgency=medium * Backwards-compatibility with older (released, non-master) libosmocore diff --git a/debian/compat b/debian/compat index ec63514..f599e28 100644 --- a/debian/compat +++ b/debian/compat @@ -1 +1 @@ -9 +10 diff --git a/debian/control b/debian/control index f30b1d3..cae4e8d 100644 --- a/debian/control +++ b/debian/control @@ -1,16 +1,23 @@ Source: simtrace2 -Maintainer: Harald Welte <laforge@gnumonks.org> +Maintainer: Osmocom team <openbsc@lists.osmocom.org> Section: devel Priority: optional -Build-Depends: debhelper (>= 9), - libosmocore-dev, +Build-Depends: debhelper (>= 10), + autotools-dev, + autoconf, + automake, + libtool, + pkg-config, + git, + dh-autoreconf, + libosmocore-dev (>= 1.4.0), libpcsclite-dev, libnewlib-arm-none-eabi, libusb-1.0-0-dev, gcc-arm-none-eabi Standards-Version: 3.9.8 -Vcs-Git: git://git.osmocom.org/simtrace2.git -Vcs-Browser: http://git.osmocom.org/simtrace2/ +Vcs-Git: https://gitea.osmocom.org/sim-card/simtrace2 +Vcs-Browser: https://gitea.osmocom.org/sim-card/simtrace2 Homepage: http://osmocom.org/projects/simtrace2/wiki Package: simtrace2-firmware @@ -26,6 +33,33 @@ Package: simtrace2-utils Section: devel Architecture: any Multi-Arch: same -Depends: ${shlibs:Depends}, ${misc:Depends} +Depends: ${shlibs:Depends}, ${misc:Depends}, libosmo-simtrace2-1 Recommends: simtrace2-firmware Description: Host utilities to communicate with SIMtrace2 USB Devices. + +Package: libosmo-simtrace2-1 +Section: libs +Architecture: any +Multi-Arch: same +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Osmocom SIMtrace2 library + This library contains core "driver" functionality to interface with the + Osmocom SIMtrace2 (and compatible) USB device firmware. It enables + applications to implement SIM card / smart card tracing as well as + SIM / smart card emulation functions. + +Package: libosmo-simtrace2-dev +Section: libdevel +Architecture: any +Multi-Arch: same +Depends: libosmo-simtrace2-1, ${misc:Depends} +Description: Development headers for Osmocom SIMtrace2 library + This library contains core "driver" functionality to interface with the + Osmocom SIMtrace2 (and compatible) USB device firmware. It enables + applications to implement SIM card / smart card tracing as well as + SIM / smart card emulation functions. + . + The header files provided by this package may be used to develop + with any of the libosmocore libraries. + . + Also static libraries are installed with this package. diff --git a/debian/libosmo-simtrace2-1.install b/debian/libosmo-simtrace2-1.install new file mode 100644 index 0000000..383b232 --- /dev/null +++ b/debian/libosmo-simtrace2-1.install @@ -0,0 +1 @@ +usr/lib/libosmo-simtrace2*.so.* diff --git a/debian/libosmo-simtrace2-dev.install b/debian/libosmo-simtrace2-dev.install new file mode 100644 index 0000000..eec0e15 --- /dev/null +++ b/debian/libosmo-simtrace2-dev.install @@ -0,0 +1,5 @@ +usr/include/* +usr/lib/lib*.a +usr/lib/lib*.so +usr/lib/lib*.la +usr/lib/pkgconfig/* diff --git a/debian/rules b/debian/rules index 2d33f6a..37cd4d7 100755 --- a/debian/rules +++ b/debian/rules @@ -1,4 +1,16 @@ #!/usr/bin/make -f +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +DEBIAN := $(shell dpkg-parsechangelog | grep ^Version: | cut -d' ' -f2) +DEBVERS := $(shell echo '$(DEBIAN)' | cut -d- -f1) +VERSION := $(shell echo '$(DEBVERS)' | sed -e 's/[+-].*//' -e 's/~//g') + +export DEB_BUILD_MAINT_OPTIONS = hardening=+all + +export DEB_LDFLAGS_MAINT_STRIP = -Wl,-Bsymbolic-functions + + %: - dh $@ + dh $@ --no-parallel diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000..89ae9db --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (native) diff --git a/firmware/Makefile b/firmware/Makefile index fa72bd3..2f7a370 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -28,22 +28,41 @@ # Makefile for compiling the Getting Started with SAM3S Microcontrollers project +GIT_VERSION=$(shell $(TOP)/git-version-gen $(TOP)/.tarball-version) + +CFLAGS = \ + -Werror=format-security \ + -Wformat \ + -g \ + $(NULL) + #------------------------------------------------------------------------------- # User-modifiable options #------------------------------------------------------------------------------- +# verbosity +V ?= 0 +ifneq ("$(V)","0") +SILENT := +else +SILENT := @ +endif + # Chip & board used for compilation # (can be overriden by adding CHIP=chip and BOARD=board to the command-line) CHIP ?= sam3s4 BOARD ?= qmod - -# Defines which are the available memory targets for the SAM3S-EK board. -MEMORIES ?= flash dfu - -# Output file basename APP ?= dfu -# Output directories +# Defines which are the available memory targets for the SAM3S-EK board. +ifeq ($(APP), dfu) +MEMORIES ?= flash +TRACE_LEVEL ?= 0 +else +MEMORIES ?= dfu +endif + +# Output directories and filename OUTPUT = $(BOARD)-$(APP) BIN = bin OBJ = obj/$(BOARD) @@ -61,19 +80,26 @@ AT91LIB_USB_DFU_PATH = $(AT91LIB)/usb/device/dfu # Tool suffix when cross-compiling CROSS_COMPILE = arm-none-eabi- -LIBS = -Wl,--start-group -lgcc -Wl,--end-group -nostdlib - -# Compilation tools +USE_CLANG ?= 0 +ifneq ("$(USE_CLANG)","0") +# --target=thumbv7m-none-eabi +CC = clang +LD = ld.lld +SIZE = llvm-size +LIBS = -nostdlib +else CC = $(CROSS_COMPILE)gcc LD = $(CROSS_COMPILE)ld SIZE = $(CROSS_COMPILE)size +LIBS = -Wl,--start-group -lgcc -Wl,--end-group -nostdlib +endif + STRIP = $(CROSS_COMPILE)strip OBJCOPY = $(CROSS_COMPILE)objcopy GDB = $(CROSS_COMPILE)gdb NM = $(CROSS_COMPILE)nm TOP=.. -GIT_VERSION=$(shell $(TOP)/git-version-gen $(TOP)/.tarvers) #------------------------------------------------------------------------------- # Files @@ -97,10 +123,11 @@ C_LIBCHIP = $(notdir $(wildcard $(AT91LIB)/libchip_sam3s/source/*.c) $(wildcard C_LIBUSB = USBDescriptors.c USBRequests.c USBD.c USBDCallbacks.c USBDDriver.c USBDDriverCallbacks.c C_LIBUSB_RT = dfu.c dfu_runtime.c C_LIBUSB_DFU = dfu.c dfu_desc.c dfu_driver.c -C_LIBCOMMON = string.c stdio.c fputs.c usb_buf.c ringbuffer.c pseudo_talloc.c host_communication.c +C_LIBCOMMON = string.c stdio.c fputs.c usb_buf.c ringbuffer.c pseudo_talloc.c host_communication.c \ + main_common.c stack_check.c crcstub.c C_BOARD = $(notdir $(wildcard libboard/common/source/*.c)) -C_BOARD += $(notdir $(wildcard libboard/$(BOARD)/source/*.c)) +C_BOARD += $(notdir $(wildcard libboard/$(BOARD)/source/*.c)) C_APPLEVEL = $(notdir $(wildcard apps/$(APP)/*.c)) @@ -124,14 +151,14 @@ TRACE_LEVEL ?= 4 # only applicable for qmod board ALLOW_PEER_ERASE?=0 -DEBUG_PHONE_SNIFF?=0 - #CFLAGS+=-DUSB_NO_DEBUG=1 # Optimization level, put in comment for debugging +ifneq ("$(USE_CLANG)","0") +OPTIMIZATION ?= -Oz +else OPTIMIZATION ?= -Os - - +endif # Flags INCLUDES_USB = -I$(AT91LIB)/usb/include -I$(AT91LIB) @@ -145,6 +172,11 @@ INCLUDES += -Ilibosmocore/include INCLUDES += -Isrc_simtrace -Iinclude INCLUDES += -Iapps/$(APP) +ifneq ("$(USE_CLANG)","0") +CFLAGS += -Wno-unknown-warning-option -Wno-empty-body -fno-exceptions -fno-unwind-tables --config armv7em_soft_nofp_nosys +else +CFLAGS += -Wno-suggest-attribute=noreturn --param max-inline-insns-single=500 +endif CFLAGS += -Wall -Wchar-subscripts -Wcomment -Wimplicit-int -Wformat=2 CFLAGS += -Werror-implicit-function-declaration -Wmain -Wparentheses CFLAGS += -Wsequence-point -Wreturn-type -Wswitch -Wtrigraphs #-Wunused @@ -157,33 +189,43 @@ CFLAGS += -Wredundant-decls -Wnested-externs #-Winline -Wlong-long CFLAGS += -Wunreachable-code #CFLAGS += -Wcast-align #CFLAGS += -std=c11 -CFLAGS += -Wmissing-noreturn +#CFLAGS += -Wmissing-noreturn #CFLAGS += -Wconversion CFLAGS += -Wno-unused-but-set-variable -Wno-unused-variable -CFLAGS += -Wno-suggest-attribute=noreturn + # -mlong-calls -Wall #CFLAGS += -save-temps -fverbose-asm #CFLAGS += -Wa,-a,-ad -CFLAGS += -D__ARM -CFLAGS += --param max-inline-insns-single=500 -mcpu=cortex-m3 -mthumb # -mfix-cortex-m3-ldrd -CFLAGS += -ffunction-sections -g $(OPTIMIZATION) $(INCLUDES) -D$(CHIP) -DTRACE_LEVEL=$(TRACE_LEVEL) -DDEBUG_PHONE_SNIFF=$(DEBUG_PHONE_SNIFF) -DALLOW_PEER_ERASE=$(ALLOW_PEER_ERASE) +CFLAGS += -D__ARM -fno-builtin +CFLAGS += -mcpu=cortex-m3 -mthumb # -mfix-cortex-m3-ldrd +CFLAGS += -ffunction-sections -g $(OPTIMIZATION) $(INCLUDES) -D$(CHIP) -DTRACE_LEVEL=$(TRACE_LEVEL) -DALLOW_PEER_ERASE=$(ALLOW_PEER_ERASE) CFLAGS += -DGIT_VERSION=\"$(GIT_VERSION)\" CFLAGS += -DBOARD=\"$(BOARD)\" -DBOARD_$(BOARD) CFLAGS += -DAPPLICATION=\"$(APP)\" -DAPPLICATION_$(APP) + +# Disable stack protector by default (OS#5081) +ifeq ($(STACK_PROTECTOR), 1) +CFLAGS += -fstack-protector +else +CFLAGS += -fno-stack-protector +endif + ASFLAGS = -mcpu=cortex-m3 -mthumb -Wall -g $(OPTIMIZATION) $(INCLUDES) -D$(CHIP) -D__ASSEMBLY__ -LDFLAGS = -mcpu=cortex-m3 -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=ResetException -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols $(LIB) +LDFLAGS = -mcpu=cortex-m3 -mthumb -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=ResetException -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--no-undefined $(LIB) +ifeq ("$(USE_CLANG)","0") +LDFLAGS += -Wl,--warn-section-align -Wl,--print-memory-usage +endif #LD_OPTIONAL=-Wl,--print-gc-sections -Wl,--stats - -# Append OBJ and BIN directories to output filename +# Append BIN directories to output filename OUTPUT := $(BIN)/$(OUTPUT) #------------------------------------------------------------------------------- # Rules #------------------------------------------------------------------------------- -all: apps/$(APP)/usb_strings_generated.h $(BIN) $(OBJ) $(MEMORIES) +all: $(BIN) $(OBJ) $(MEMORIES) combined: $(OUTPUT)-combined.bin @@ -194,48 +236,97 @@ $(BIN)/$(BOARD)-dfu-flash-padded.bin: $(BIN)/$(BOARD)-dfu-flash.bin $(OUTPUT)-combined.bin: $(BIN)/$(BOARD)-dfu-flash-padded.bin $(OUTPUT)-dfu.bin cat $^ > $@ -$(BIN) $(OBJ): +$(BIN) $(OBJ): apps/$(APP)/usb_strings_generated.h misc/crctool mkdir -p $@ usbstring/usbstring: usbstring/usbstring.c gcc $^ -o $@ -apps/$(APP)/usb_strings_generated.h: apps/$(APP)/usb_strings.txt usbstring/usbstring +misc/crctool: misc/crctool.c + gcc $^ -o $@ + +.PHONY: apps/$(APP)/usb_strings.txt.patched +apps/$(APP)/usb_strings.txt.patched: apps/$(APP)/usb_strings.txt + sed "s/PRODUCT_STRING/$(shell cat libboard/$(BOARD)/product_string.txt)/" $< > $@ + +apps/$(APP)/usb_strings_generated.h: apps/$(APP)/usb_strings.txt.patched usbstring/usbstring cat $< | usbstring/usbstring > $@ define RULES C_OBJECTS_$(1) = $(addprefix $(OBJ)/$(1)_, $(C_OBJECTS)) ASM_OBJECTS_$(1) = $(addprefix $(OBJ)/$(1)_, $(ASM_OBJECTS)) +EXTRA_OBJECTS_$(1) = $(addprefix $(OBJ)/$(1)_, $(EXTRA_OBJECTS)) -$(1): $$(ASM_OBJECTS_$(1)) $$(C_OBJECTS_$(1)) - @$(CC) $(LDFLAGS) $(LD_OPTIONAL) -T"libboard/common/resources/$(CHIP)/$$@.ld" -Wl,-Map,$(OUTPUT)-$$@.map -o $(OUTPUT)-$$@.elf $$^ $(LIBS) - @$(NM) $(OUTPUT)-$$@.elf >$(OUTPUT)-$$@.elf.txt - @$(OBJCOPY) -O binary $(OUTPUT)-$$@.elf $(OUTPUT)-$$@.bin - @$(SIZE) $$^ $(OUTPUT)-$$@.elf +build_$(1): $$(ASM_OBJECTS_$(1)) $$(C_OBJECTS_$(1)) $$(EXTRA_OBJECTS_$(1)) + $(SILENT)$(CC) $(CFLAGS) $(LDFLAGS) $(LD_OPTIONAL) -T"libboard/common/resources/$(CHIP)/$(1).ld" -Wl,-Map,$(OUTPUT)-$(1).map -o $(OUTPUT)-$(1).elf $$^ $(LIBS) + $(SILENT)$(NM) $(OUTPUT)-$(1).elf >$(OUTPUT)-$(1).elf.txt + $(SILENT)$(OBJCOPY) -O binary $(OUTPUT)-$(1).elf $(OUTPUT)-$(1).bin $$(C_OBJECTS_$(1)): $(OBJ)/$(1)_%.o: %.c Makefile $(OBJ) $(BIN) @echo [COMPILING $$<] - @$(CC) $(CFLAGS) -DENVIRONMENT_$(1) -DENVIRONMENT=\"$(1)\" -Wa,-ahlms=$(BIN)/$$*.lst -c -o $$@ $$< + $(SILENT)$(CC) $(CFLAGS) -DENVIRONMENT_$(1) -DENVIRONMENT=\"$(1)\" -c -o $$@ $$< $$(ASM_OBJECTS_$(1)): $(OBJ)/$(1)_%.o: %.S Makefile $(OBJ) $(BIN) @echo [ASSEMBLING $$@] - @$(CC) $(ASFLAGS) -DENVIRONMENT_$(1) -DENVIRONMENT=\"$(1)\" -c -o $$@ $$< + $(SILENT)$(CC) $(ASFLAGS) -DENVIRONMENT_$(1) -DENVIRONMENT=\"$(1)\" -c -o $$@ $$< -debug_$(1): $(1) - $(GDB) -x "$(BOARD_LIB)/resources/gcc/$(BOARD)_$(1).gdb" -ex "reset" -readnow -se $(OUTPUT)-$(1).elf endef -$(foreach MEMORY, $(MEMORIES), $(eval $(call RULES,$(MEMORY)))) +ALL_MEMORIES = flash ram +$(foreach MEMORY, $(ALL_MEMORIES), $(eval $(call RULES,$(MEMORY)))) + +# files with those names do exist.. +.PHONY: dfu +dfu: $(OUTPUT)-dfu.bin +.PHONY: ram +ram: build_ram +.PHONY: flash +flash: build_flash +#alternate way of embedding: obj file +#ifeq ($(APP), dfu) +# $(info bootloader bin file to obj..) +# $(SILENT)$(OBJCOPY) --rename-section .data=.fwupdate -I binary -O elf32-littlearm bin/$(BOARD)-dfu-flash.bin $(OBJ)/flash_fwupdate.o +#endif + +C_OBJECTS_dfu = $(addprefix $(OBJ)/dfu_, $(C_OBJECTS)) +ASM_OBJECTS_dfu = $(addprefix $(OBJ)/dfu_, $(ASM_OBJECTS)) +EXTRA_OBJECTS_dfu = $(addprefix $(OBJ)/dfu_, $(EXTRA_OBJECTS)) + +$(OUTPUT)-dfu.bin: $(OUTPUT)-dfu_nocrcstub.bin + $(info updating app with crc..) + $(SILENT)cp $< $@.temp + $(SILENT)misc/crctool 512 $@.temp + $(SILENT)mv $@.temp $@ + +$(OUTPUT)-dfu_nocrcstub.bin: $(OUTPUT)-dfu_nocrcstub.elf +ifeq ($(APP), blupdate) + $(info updating updater section with padded bootloader file..) + $(SILENT)dd status=none if=/dev/zero bs=16384 count=1 of=$(BIN)/$(BOARD)-dfu-flash-padded.bin + $(SILENT)dd status=none if=$(BIN)/$(BOARD)-dfu-flash.bin conv=notrunc of=$(BIN)/$(BOARD)-dfu-flash-padded.bin + $(SILENT)$(OBJCOPY) --update-section .blupdate=bin/$(BOARD)-dfu-flash-padded.bin $< +endif + $(SILENT)$(OBJCOPY) -O binary $< $@ + +$(OUTPUT)-dfu_nocrcstub.elf: $(ASM_OBJECTS_dfu) $(C_OBJECTS_dfu) $(EXTRA_OBJECTS_dfu) + $(SILENT)$(CC) $(CFLAGS) $(LDFLAGS) $(LD_OPTIONAL) -T"libboard/common/resources/$(CHIP)/dfu.ld" -Wl,-Map,$(OUTPUT)-dfu_nocrcstub.map -o $@ $^ $(LIBS) + $(SILENT)$(NM) $@ >$@.txt + +$(C_OBJECTS_dfu): $(OBJ)/dfu_%.o: %.c Makefile $(OBJ) $(BIN) + @echo [COMPILING $<] + $(SILENT)$(CC) $(CFLAGS) -DENVIRONMENT_dfu -DENVIRONMENT=\"dfu\" -c -o $@ $< + +$(ASM_OBJECTS_dfu): $(OBJ)/dfu_%.o: %.S Makefile $(OBJ) $(BIN) + @echo [ASSEMBLING $@] + $(SILENT)$(CC) $(ASFLAGS) -DENVIRONMENT_dfu -DENVIRONMENT=\"dfu\" -c -o$@ $< -program: - openocd -f openocd/openocd.cfg -c "init" -c "halt" -c "flash write_bank 0 ./bin/project-flash.bin 0" -c "reset" -c "shutdown" SERIAL ?= /dev/ttyUSB0 log: - stty -F $(SERIAL) 115200 + stty -F $(SERIAL) 921600 lsof $(SERIAL) && echo "log is already opened" || ( sed -u "s/\r//" $(SERIAL) | ts ) clean: + -rm -f apps/$(APP)/usb_strings.txt.patched -rm -fR $(OBJ)/*.o $(BIN)/*.bin $(BIN)/*.elf $(BIN)/*.elf.txt $(BIN)/*.map $(BIN)/*.lst `find . -name \*.p` install: diff --git a/firmware/README.txt b/firmware/README.txt index fa7f60a..cd04e7a 100644 --- a/firmware/README.txt +++ b/firmware/README.txt @@ -24,6 +24,7 @@ Current boards supported are: * `simtrace`: The good old Osmocom SIMtrace PCB with SAM3 instead of SAM7, open hardware. * `qmod`: A sysmocom-proprietary quad mPCIe carrier board, publicly available * `owhw`: An undisclosed sysmocom-internal board, not publicly available +* `octsimtest`: A sysmocom-proprietary production testing board, not publicly available = Firmware @@ -51,6 +52,7 @@ Current applications supported are: * `cardem`: To provide remote SIM operation capabilities. * `trace`: To monitor the communication between a SIM card and a phone (corresponds to the functionality provide by the first SIMtrace) * `triple_play`: To support the three previous functionalities, using USB configurations. +* `gpio_test`: internal test code == Memories diff --git a/firmware/apps/blupdate/Makefile b/firmware/apps/blupdate/Makefile new file mode 100644 index 0000000..4f1d377 --- /dev/null +++ b/firmware/apps/blupdate/Makefile @@ -0,0 +1,12 @@ + +C_FILES += $(C_LIBUSB_DFU) + +# Trace level used for compilation +# (can be overridden by adding TRACE_LEVEL=#number to the command-line) +# TRACE_LEVEL_DEBUG 5 +# TRACE_LEVEL_INFO 4 +# TRACE_LEVEL_WARNING 3 +# TRACE_LEVEL_ERROR 2 +# TRACE_LEVEL_FATAL 1 +# TRACE_LEVEL_NO_TRACE 0 +TRACE_LEVEL ?= 3 diff --git a/firmware/apps/blupdate/main.c b/firmware/apps/blupdate/main.c new file mode 100644 index 0000000..8c48e37 --- /dev/null +++ b/firmware/apps/blupdate/main.c @@ -0,0 +1,136 @@ +/* SIMtrace 2 firmware USB DFU bootloader + * + * (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de> + * (C) 2018-2019 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "board.h" +#include "core_cm3.h" +#include "flashd.h" +#include "utils.h" +#include "usb/device/dfu/dfu.h" +#include "usb/common/dfu/usb_dfu.h" +#include "manifest.h" +#include "USBD_HAL.h" + +#include <osmocom/core/timer.h> + +/* actual section content must be replaced with the padded bootloader by running objcopy! */ +const uint32_t bl_update_data[BOARD_DFU_BOOT_SIZE / sizeof(uint32_t)] __attribute__((section(".fwupdate"))) = { 0xFF }; + +unsigned int g_unique_id[4]; +/* remember if the watchdog has been configured in the main loop so we can kick it in the ISR */ +static bool watchdog_configured = false; + +extern uint32_t _end; +extern uint32_t _srelocate; +extern uint32_t _etext; + +void DFURT_SwitchToDFU(void) +{ +} +void USBDFU_Runtime_RequestHandler(const USBGenericRequest *request) +{ +} +int USBDFU_handle_dnload(uint8_t altif, unsigned int offset, uint8_t *data, unsigned int len) +{ + return 0; +} +int USBDFU_handle_upload(uint8_t altif, unsigned int offset, uint8_t *data, unsigned int req_len) +{ + return 0; +} +int USBDFU_OverrideEnterDFU(void) +{ + return 0; +} + +__attribute__((section(".ramfunc"), noinline)) static uint32_t flash_wait_ready() +{ + Efc *efc = EFC; + uint32_t dwStatus; + + do { + dwStatus = efc->EEFC_FSR; + } while ((dwStatus & EEFC_FSR_FRDY) != EEFC_FSR_FRDY); + return (dwStatus & (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE)); +} + +__attribute__((section(".ramfunc"), noinline)) static void flash_cmd(uint32_t dwCommand, uint32_t dwArgument) +{ + Efc *efc = EFC; + uint32_t dwStatus; + efc->EEFC_FCR = EEFC_FCR_FKEY(0x5A) | EEFC_FCR_FARG(dwArgument) | EEFC_FCR_FCMD(dwCommand); +} + +__attribute__((section(".ramfunc"), noinline, noreturn)) static void erase_first_app_sector() +{ + /* page 64 */ + uint32_t first_app_page = (BOARD_DFU_BOOT_SIZE / IFLASH_PAGE_SIZE); + uint32_t *first_app_address = (uint32_t *)(IFLASH_ADDR + first_app_page * IFLASH_PAGE_SIZE + 0); + +#if 1 + /* overwrite first app sector so we don't keep booting this */ + for (int i = 0; i < IFLASH_PAGE_SIZE / 4; i++) + first_app_address[i] = 0xffffffff; + + flash_cmd(EFC_FCMD_EWP, first_app_page); +#else + /* why does erasing the whole flash with a protected bootloader not work at all? */ + flash_cmd(EFC_FCMD_EA, 0); +#endif + flash_wait_ready(); + for (;;) { + /* no functon call, since NVIC_SystemReset() might not be inlined! */ + SCB->AIRCR = ((0x5FA << SCB_AIRCR_VECTKEY_Pos) | (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + SCB_AIRCR_SYSRESETREQ_Msk); + __DSB(); + while (1) + ; + } +} + +#define MAX_USB_ITER BOARD_MCK / 72 // This should be around a second +extern int main(void) +{ + uint8_t isUsbConnected = 0; + unsigned int i = 0; + uint32_t reset_cause = (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos; + + /* Enable watchdog for 2000ms, with no window */ + WDT_Enable(WDT, WDT_MR_WDRSTEN | WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT | (WDT_GetPeriod(2000) << 16) | + WDT_GetPeriod(2000)); + watchdog_configured = true; + + EEFC_ReadUniqueID(g_unique_id); + + printf("\n\r\n\r"); + printf("bootloader updater %s for board %s\n\r" + "(C) 2010-2017 by Harald Welte, 2018-2019 by Kevin Redon\n\r", + manifest_revision, manifest_board); + + /* clear g_dfu on power-up reset */ + memset(g_dfu, 0, sizeof(*g_dfu)); + + TRACE_INFO("USB init...\n\r"); + /* Signal USB reset by disabling the pull-up on USB D+ for at least 10 ms */ + USBD_Disconnect(); + + /* Initialize the flash to be able to write it, using the IAP ROM code */ + FLASHD_Initialize(BOARD_MCK, 1); + + __disable_irq(); + FLASHD_Unlock(IFLASH_ADDR, IFLASH_ADDR + IFLASH_SIZE - 1, 0, 0); + FLASHD_Write(IFLASH_ADDR, bl_update_data, BOARD_DFU_BOOT_SIZE); + + erase_first_app_sector(); +} diff --git a/firmware/apps/blupdate/usb_strings.txt b/firmware/apps/blupdate/usb_strings.txt new file mode 100644 index 0000000..f652071 --- /dev/null +++ b/firmware/apps/blupdate/usb_strings.txt @@ -0,0 +1,6 @@ +sysmocom - s.f.m.c. GmbH +PRODUCT_STRING +bootloader updater +RAM +Flash (Application Partition) +Flash (Bootloader Partition) diff --git a/firmware/apps/cardem/Makefile b/firmware/apps/cardem/Makefile index 75c43e8..c0d903f 100644 --- a/firmware/apps/cardem/Makefile +++ b/firmware/apps/cardem/Makefile @@ -1,3 +1,3 @@ C_FILES += $(C_LIBUSB_RT) -C_FILES += card_emu.c cciddriver.c iso7816_4.c iso7816_fidi.c mitm.c mode_cardemu.c mode_ccid.c simtrace_iso7816.c sniffer.c tc_etu.c usb.c +C_FILES += card_emu.c cciddriver.c iso7816_4.c iso7816_fidi.c mitm.c mode_cardemu.c mode_ccid.c simtrace_iso7816.c sniffer.c usb.c diff --git a/firmware/apps/cardem/main.c b/firmware/apps/cardem/main.c index 209c79f..6372e04 100644 --- a/firmware/apps/cardem/main.c +++ b/firmware/apps/cardem/main.c @@ -1,7 +1,7 @@ /* SIMtrace 2 firmware card emulation application * * (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de> - * (C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de> + * (C) 2018-2019, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /*------------------------------------------------------------------------------ * Headers @@ -24,10 +20,9 @@ #include "board.h" #include "simtrace.h" #include "utils.h" +#include "main_common.h" #include <osmocom/core/timer.h> -unsigned int g_unique_id[4]; - /*------------------------------------------------------------------------------ * Internal variables *------------------------------------------------------------------------------*/ @@ -40,7 +35,7 @@ typedef struct { void (*exit) (void); /* main loop content for given configuration */ void (*run) (void); - /* Interrupt handler for USART1 */ + /* Interrupt handler for USART0 */ void (*usart0_irq) (void); /* Interrupt handler for USART1 */ void (*usart1_irq) (void); @@ -54,6 +49,8 @@ static const conf_func config_func_ptrs[] = { .init = Sniffer_init, .exit = Sniffer_exit, .run = Sniffer_run, + .usart0_irq = Sniffer_usart0_irq, + .usart1_irq = Sniffer_usart1_irq, }, #endif #ifdef HAVE_CCID @@ -70,8 +67,13 @@ static const conf_func config_func_ptrs[] = { .init = mode_cardemu_init, .exit = mode_cardemu_exit, .run = mode_cardemu_run, +#if defined (ngff_cardem) + .usart0_irq = mode_cardemu_usart1_irq, + .usart1_irq = mode_cardemu_usart0_irq, +#else .usart0_irq = mode_cardemu_usart0_irq, .usart1_irq = mode_cardemu_usart1_irq, +#endif }, #endif #ifdef HAVE_MITM @@ -146,41 +148,16 @@ extern int main(void) unsigned int i = 0; led_init(); - led_blink(LED_RED, BLINK_3O_5F); + led_blink(LED_RED, BLINK_ALWAYS_ON); + led_blink(LED_GREEN, BLINK_ALWAYS_ON); /* Enable watchdog for 2000ms, with no window */ WDT_Enable(WDT, WDT_MR_WDRSTEN | WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT | (WDT_GetPeriod(2000) << 16) | WDT_GetPeriod(2000)); - PIO_InitializeInterrupts(0); - - EEFC_ReadUniqueID(g_unique_id); - - printf("\n\r\n\r" - "=============================================================================\n\r" - "SIMtrace2 firmware " GIT_VERSION " (C) 2010-2016 by Harald Welte\n\r" - "=============================================================================\n\r"); - -#if (TRACE_LEVEL >= TRACE_LEVEL_INFO) - TRACE_INFO("Chip ID: 0x%08lx (Ext 0x%08lx)\n\r", CHIPID->CHIPID_CIDR, CHIPID->CHIPID_EXID); - TRACE_INFO("Serial Nr. %08x-%08x-%08x-%08x\n\r", - g_unique_id[0], g_unique_id[1], - g_unique_id[2], g_unique_id[3]); - uint8_t reset_cause = (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos; - static const char* reset_causes[] = { - "general reset (first power-up reset)", - "backup reset (return from backup mode)", - "watchdog reset (watchdog fault occurred)", - "software reset (processor reset required by the software)", - "user reset (NRST pin detected low)", - }; - if (reset_cause < ARRAY_SIZE(reset_causes)) { - TRACE_INFO("Reset Cause: %s\n\r", reset_causes[reset_cause]); - } else { - TRACE_INFO("Reset Cause: 0x%lx\n\r", (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos); - } -#endif + PIO_InitializeInterrupts(10); + print_banner(); board_main_top(); TRACE_INFO("USB init...\n\r"); @@ -201,8 +178,7 @@ extern int main(void) } TRACE_INFO("calling configure of all configurations...\n\r"); - for (i = 1; i < sizeof(config_func_ptrs) / sizeof(config_func_ptrs[0]); - ++i) { + for (i = 1; i < ARRAY_SIZE(config_func_ptrs); i++) { if (config_func_ptrs[i].configure) config_func_ptrs[i].configure(); } @@ -218,8 +194,8 @@ extern int main(void) WDT_Restart(WDT); #if TRACE_LEVEL >= TRACE_LEVEL_DEBUG const char rotor[] = { '-', '\\', '|', '/' }; - putchar('\b'); putchar(rotor[i++ % ARRAY_SIZE(rotor)]); + putchar('\b'); #endif check_exec_dbg_cmd(); osmo_timers_prepare(); @@ -230,6 +206,10 @@ extern int main(void) if (isUsbConnected) { isUsbConnected = 0; } + /* HACK: we don't really deal with USB disconnect yet, + * so let's just reset the entire uC if this happens */ + TRACE_INFO("Resetting uC on USB disconnect\n\r"); + NVIC_SystemReset(); } else if (isUsbConnected == 0) { TRACE_INFO("USB is now configured\n\r"); diff --git a/firmware/apps/cardem/usb_strings.txt b/firmware/apps/cardem/usb_strings.txt index 0e797ac..3a1bcc3 100644 --- a/firmware/apps/cardem/usb_strings.txt +++ b/firmware/apps/cardem/usb_strings.txt @@ -1,8 +1,8 @@ sysmocom - s.f.m.c. GmbH -SIMtrace 2 compatible device +PRODUCT_STRING SIMtrace Sniffer SIMtrace CCID -SIMtrace Phone +SIMtrace Card Emulation SIMtrace MITM CardEmulator Modem 1 CardEmulator Modem 2 diff --git a/firmware/apps/dfu/main.c b/firmware/apps/dfu/main.c index f9b6aed..ef58ec2 100644 --- a/firmware/apps/dfu/main.c +++ b/firmware/apps/dfu/main.c @@ -1,7 +1,7 @@ /* SIMtrace 2 firmware USB DFU bootloader * * (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de> - * (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de> + * (C) 2018-2019 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "board.h" #include "utils.h" @@ -26,8 +22,15 @@ #include <osmocom/core/timer.h> +/* USB alternate interface index used to identify which partition to flash */ +/** USB alternate interface index indicating RAM partition */ #define ALTIF_RAM 0 +/** USB alternate interface index indicating flash partition */ +#if defined(ENVIRONMENT_flash) #define ALTIF_FLASH 1 +#elif defined(ENVIRONMENT_dfu) +#define ALTIF_FLASH 2 +#endif unsigned int g_unique_id[4]; /* remember if the watchdog has been configured in the main loop so we can kick it in the ISR */ @@ -44,10 +47,18 @@ static const Pin pinsLeds[] = { PINS_LEDS } ; *----------------------------------------------------------------------------*/ #define RAM_ADDR(offset) (IRAM_ADDR + BOARD_DFU_RAM_SIZE + offset) +#if defined(ENVIRONMENT_flash) #define FLASH_ADDR(offset) (IFLASH_ADDR + BOARD_DFU_BOOT_SIZE + offset) +#elif defined(ENVIRONMENT_dfu) +#define FLASH_ADDR(offset) (IFLASH_ADDR + offset) +#endif -#define IFLASH_END ((uint8_t *)IFLASH_ADDR + IFLASH_SIZE) -#define IRAM_END ((uint8_t *)IRAM_ADDR + IRAM_SIZE) +#define IRAM_END ((uint8_t *)IRAM_ADDR + IRAM_SIZE) +#if defined(ENVIRONMENT_flash) +#define IFLASH_END ((uint8_t *)IFLASH_ADDR + IFLASH_SIZE) +#elif defined(ENVIRONMENT_dfu) +#define IFLASH_END ((uint8_t *)IFLASH_ADDR + BOARD_DFU_BOOT_SIZE) +#endif /* incoming call-back: Host has transferred 'len' bytes (stored at * 'data'), which we shall write to 'offset' into the partition @@ -66,7 +77,11 @@ int USBDFU_handle_dnload(uint8_t altif, unsigned int offset, WDT_Restart(WDT); } - printf("dnload(altif=%u, offset=%u, len=%u)\n\r", altif, offset, len); +#if TRACE_LEVEL >= TRACE_LEVEL_INFO + TRACE_INFO("dnload(altif=%u, offset=%u, len=%u)\n\r", altif, offset, len); +#else + printf("DL off=%u\n\r", offset); +#endif #ifdef PINS_LEDS PIO_Clear(&pinsLeds[LED_NUM_RED]); @@ -86,7 +101,11 @@ int USBDFU_handle_dnload(uint8_t altif, unsigned int offset, break; case ALTIF_FLASH: addr = FLASH_ADDR(offset); +#if defined(ENVIRONMENT_flash) if (addr < IFLASH_ADDR || addr + len >= IFLASH_ADDR + IFLASH_SIZE) { +#elif defined(ENVIRONMENT_dfu) + if (addr < IFLASH_ADDR || addr + len >= IFLASH_ADDR + BOARD_DFU_BOOT_SIZE) { +#endif g_dfu->state = DFU_STATE_dfuERROR; g_dfu->status = DFU_STATUS_errADDRESS; rc = DFU_RET_STALL; @@ -220,6 +239,17 @@ static void check_exec_dbg_cmd(void) //board_exec_dbg_cmd(ch); } +/* print a horizontal line of '=' characters; Doing this in a loop vs. using a 'const' + * string saves us ~60 bytes of executable size (matters particularly for DFU loader) */ +static void print_line(void) +{ + int i; + for (i = 0; i < 78; i++) + fputc('=', stdout); + fputc('\n', stdout); + fputc('\r', stdout); +} + /*------------------------------------------------------------------------------ * Main *------------------------------------------------------------------------------*/ @@ -237,38 +267,50 @@ extern int main(void) #ifdef PINS_LEDS /* Configure LED */ - PIO_Configure(pinsLeds, sizeof(pinsLeds)); + PIO_Configure(pinsLeds, PIO_LISTSIZE(pinsLeds)); PIO_Set(&pinsLeds[LED_NUM_RED]); PIO_Clear(&pinsLeds[LED_NUM_GREEN]); #endif - PIO_InitializeInterrupts(0); - EEFC_ReadUniqueID(g_unique_id); - printf("\n\r\n\r" - "=============================================================================\n\r" - "DFU bootloader %s for board %s (C) 2010-2017 by Harald Welte\n\r" - "=============================================================================\n\r", + printf("\n\r\n\r"); + print_line(); + printf("DFU bootloader %s for board %s\n\r" + "(C) 2010-2017 by Harald Welte, 2018-2019 by Kevin Redon\n\r", manifest_revision, manifest_board); + print_line(); - TRACE_INFO("Chip ID: 0x%08x (Ext 0x%08x)\n\r", CHIPID->CHIPID_CIDR, CHIPID->CHIPID_EXID); +#if (TRACE_LEVEL >= TRACE_LEVEL_INFO) + TRACE_INFO("Chip ID: 0x%08lx (Ext 0x%08lx)\n\r", CHIPID->CHIPID_CIDR, CHIPID->CHIPID_EXID); TRACE_INFO("Serial Nr. %08x-%08x-%08x-%08x\n\r", g_unique_id[0], g_unique_id[1], g_unique_id[2], g_unique_id[3]); - TRACE_INFO("Reset Cause: 0x%lx\n\r", reset_cause); + static const char* reset_causes[] = { + "general reset (first power-up reset)", + "backup reset (return from backup mode)", + "watchdog reset (watchdog fault occurred)", + "software reset (processor reset required by the software)", + "user reset (NRST pin detected low)", + }; + if (reset_cause < ARRAY_SIZE(reset_causes)) { + TRACE_INFO("Reset Cause: %s\n\r", reset_causes[reset_cause]); + } else { + TRACE_INFO("Reset Cause: 0x%lx\n\r", (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos); + } +#endif #if (TRACE_LEVEL >= TRACE_LEVEL_INFO) /* Find out why we are in the DFU bootloader, and not the main application */ TRACE_INFO("DFU bootloader start reason: "); switch (USBDFU_OverrideEnterDFU()) { case 0: - /* 0 normally means that there is no override, but we are in the bootloader, - * thus the first check in board_cstartup_gnu did return something else than 0. - * this can only be g_dfu->magic which is erased when the segment are - * relocated, which happens in board_cstartup_gnu just after USBDFU_OverrideEnterDFU. - * no static variable can be used to store this case since this will also be overwritten - */ + if (SCB->VTOR < IFLASH_ADDR + BOARD_DFU_BOOT_SIZE) { + TRACE_INFO_WP("unknown\n\r"); + } else { + TRACE_INFO_WP("DFU is the main application\n\r"); + } + break; case 1: TRACE_INFO_WP("DFU switch requested by main application\n\r"); break; @@ -295,18 +337,8 @@ extern int main(void) TRACE_INFO("USB init...\n\r"); /* Signal USB reset by disabling the pull-up on USB D+ for at least 10 ms */ -#ifdef PIN_USB_PULLUP - const Pin usb_dp_pullup = PIN_USB_PULLUP; - PIO_Configure(&usb_dp_pullup, 1); - PIO_Set(&usb_dp_pullup); -#endif - USBD_HAL_Suspend(); - mdelay(20); -#ifdef PIN_USB_PULLUP - PIO_Clear(&usb_dp_pullup); -#endif - USBD_HAL_Activate(); - + USBD_Disconnect(); + mdelay(500); USBDFU_Initialize(&dfu_descriptors); while (USBD_GetState() < USBD_STATE_CONFIGURED) { @@ -314,8 +346,8 @@ extern int main(void) check_exec_dbg_cmd(); #if 1 if (i >= MAX_USB_ITER * 3) { - TRACE_ERROR("Resetting board (USB could " - "not be configured)\n\r"); + TRACE_ERROR("Resetting board (USB could not be configured)\n\r"); + g_dfu->magic = USB_DFU_MAGIC; // start the bootloader after reboot USBD_Disconnect(); NVIC_SystemReset(); } diff --git a/firmware/apps/dfu/usb_strings.txt b/firmware/apps/dfu/usb_strings.txt index 8a4facb..4a58cb8 100644 --- a/firmware/apps/dfu/usb_strings.txt +++ b/firmware/apps/dfu/usb_strings.txt @@ -1,5 +1,6 @@ sysmocom - s.f.m.c. GmbH -SIMtrace 2 compatible device +PRODUCT_STRING DFU (Device Firmware Upgrade) RAM Flash (Application Partition) +Flash (Bootloader Partition) diff --git a/firmware/apps/freq_ctr/usb_strings.txt b/firmware/apps/freq_ctr/usb_strings.txt index 0e797ac..3a1bcc3 100644 --- a/firmware/apps/freq_ctr/usb_strings.txt +++ b/firmware/apps/freq_ctr/usb_strings.txt @@ -1,8 +1,8 @@ sysmocom - s.f.m.c. GmbH -SIMtrace 2 compatible device +PRODUCT_STRING SIMtrace Sniffer SIMtrace CCID -SIMtrace Phone +SIMtrace Card Emulation SIMtrace MITM CardEmulator Modem 1 CardEmulator Modem 2 diff --git a/firmware/apps/gpio_test/Makefile b/firmware/apps/gpio_test/Makefile new file mode 100644 index 0000000..b2b4707 --- /dev/null +++ b/firmware/apps/gpio_test/Makefile @@ -0,0 +1,3 @@ +C_FILES += $(C_LIBUSB_RT) + +C_FILES += gpio_test.c diff --git a/firmware/apps/gpio_test/gpio_test.c b/firmware/apps/gpio_test/gpio_test.c new file mode 100644 index 0000000..a6b0a00 --- /dev/null +++ b/firmware/apps/gpio_test/gpio_test.c @@ -0,0 +1,8 @@ +#include <stdint.h> +#include "utils.h" +#include "chip.h" + +void gpio_test_init(void) +{ + printf("FIXME run tests here\n\r"); +} diff --git a/firmware/apps/gpio_test/main.c b/firmware/apps/gpio_test/main.c new file mode 100644 index 0000000..8fe68b3 --- /dev/null +++ b/firmware/apps/gpio_test/main.c @@ -0,0 +1,54 @@ + +#include "board.h" +#include "utils.h" +#include "osmocom/core/timer.h" + +extern void gpio_test_init(void); + +/* returns '1' in case we should break any endless loop */ +static void check_exec_dbg_cmd(void) +{ + int ch; + + if (!UART_IsRxReady()) + return; + + ch = UART_GetChar(); + + board_exec_dbg_cmd(ch); +} + + +extern int main(void) +{ + led_init(); + led_blink(LED_RED, BLINK_ALWAYS_ON); + led_blink(LED_GREEN, BLINK_ALWAYS_ON); + + /* Enable watchdog for 2000 ms, with no window */ + WDT_Enable(WDT, WDT_MR_WDRSTEN | WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT | + (WDT_GetPeriod(2000) << 16) | WDT_GetPeriod(2000)); + + PIO_InitializeInterrupts(0); + + + printf("\n\r\n\r" + "=============================================================================\n\r" + "GPIO Test firmware " GIT_VERSION " (C) 2019 Sysmocom GmbH\n\r" + "=============================================================================\n\r"); + + board_main_top(); + + TRACE_INFO("starting gpio test...\n\r"); + gpio_test_init(); + + TRACE_INFO("entering main loop...\n\r"); + while (1) { + WDT_Restart(WDT); + + check_exec_dbg_cmd(); + osmo_timers_prepare(); + osmo_timers_update(); + } + +} diff --git a/firmware/apps/gpio_test/usb_strings.txt b/firmware/apps/gpio_test/usb_strings.txt new file mode 100644 index 0000000..3a1bcc3 --- /dev/null +++ b/firmware/apps/gpio_test/usb_strings.txt @@ -0,0 +1,10 @@ +sysmocom - s.f.m.c. GmbH +PRODUCT_STRING +SIMtrace Sniffer +SIMtrace CCID +SIMtrace Card Emulation +SIMtrace MITM +CardEmulator Modem 1 +CardEmulator Modem 2 +CardEmulator Modem 3 +CardEmulator Modem 4 diff --git a/firmware/apps/trace/Makefile b/firmware/apps/trace/Makefile index 75c43e8..c0d903f 100644 --- a/firmware/apps/trace/Makefile +++ b/firmware/apps/trace/Makefile @@ -1,3 +1,3 @@ C_FILES += $(C_LIBUSB_RT) -C_FILES += card_emu.c cciddriver.c iso7816_4.c iso7816_fidi.c mitm.c mode_cardemu.c mode_ccid.c simtrace_iso7816.c sniffer.c tc_etu.c usb.c +C_FILES += card_emu.c cciddriver.c iso7816_4.c iso7816_fidi.c mitm.c mode_cardemu.c mode_ccid.c simtrace_iso7816.c sniffer.c usb.c diff --git a/firmware/apps/trace/main.c b/firmware/apps/trace/main.c index 97455fb..ec84b5a 100644 --- a/firmware/apps/trace/main.c +++ b/firmware/apps/trace/main.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /*------------------------------------------------------------------------------ * Headers @@ -24,10 +20,9 @@ #include "board.h" #include "simtrace.h" #include "utils.h" +#include "main_common.h" #include "osmocom/core/timer.h" -unsigned int g_unique_id[4]; - /*------------------------------------------------------------------------------ * Internal variables *------------------------------------------------------------------------------*/ @@ -158,20 +153,7 @@ extern int main(void) PIO_InitializeInterrupts(0); - EEFC_ReadUniqueID(g_unique_id); - - printf("\n\r\n\r" - "=============================================================================\n\r" - "SIMtrace2 firmware " GIT_VERSION " (C) 2010-2016 by Harald Welte\n\r" - "=============================================================================\n\r"); - - TRACE_INFO("Chip ID: 0x%08lx (Ext 0x%08lx)\n\r", CHIPID->CHIPID_CIDR, CHIPID->CHIPID_EXID); - TRACE_INFO("Serial Nr. %08x-%08x-%08x-%08x\n\r", - g_unique_id[0], g_unique_id[1], - g_unique_id[2], g_unique_id[3]); - TRACE_INFO("Reset Cause: 0x%lx\n\r", (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos); - TRACE_INFO("USB configuration used: %d\n\r", simtrace_config); - + print_banner(); board_main_top(); TRACE_INFO("USB init...\n\r"); diff --git a/firmware/apps/trace/usb_strings.txt b/firmware/apps/trace/usb_strings.txt index 0e797ac..3a1bcc3 100644 --- a/firmware/apps/trace/usb_strings.txt +++ b/firmware/apps/trace/usb_strings.txt @@ -1,8 +1,8 @@ sysmocom - s.f.m.c. GmbH -SIMtrace 2 compatible device +PRODUCT_STRING SIMtrace Sniffer SIMtrace CCID -SIMtrace Phone +SIMtrace Card Emulation SIMtrace MITM CardEmulator Modem 1 CardEmulator Modem 2 diff --git a/firmware/apps/triple_play/Makefile b/firmware/apps/triple_play/Makefile index df89448..be06c11 100644 --- a/firmware/apps/triple_play/Makefile +++ b/firmware/apps/triple_play/Makefile @@ -1,3 +1,3 @@ C_FILES += $(C_LIBUSB_RT) -C_FILES += card_emu.c iso7816_4.c iso7816_fidi.c mitm.c mode_cardemu.c mode_ccid.c simtrace_iso7816.c sniffer.c tc_etu.c usb.c +C_FILES += card_emu.c iso7816_4.c iso7816_fidi.c mitm.c mode_cardemu.c mode_ccid.c simtrace_iso7816.c sniffer.c usb.c diff --git a/firmware/apps/triple_play/main.c b/firmware/apps/triple_play/main.c index b81abdd..b853cdb 100644 --- a/firmware/apps/triple_play/main.c +++ b/firmware/apps/triple_play/main.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /*------------------------------------------------------------------------------ * Headers @@ -26,8 +22,6 @@ #include "req_ctx.h" #include <osmocom/core/timer.h> -unsigned int g_unique_id[4]; - /*------------------------------------------------------------------------------ * Internal variables *------------------------------------------------------------------------------*/ @@ -149,17 +143,7 @@ extern int main(void) PIO_InitializeInterrupts(0); - EEFC_ReadUniqueID(g_unique_id); - - printf("\r\n\r\n" - "=============================================================================\r\n" - "SIMtrace2 firmware " GIT_REVISION " (C) 2010-2017 by Harald Welte\r\n" - "=============================================================================\r\n"); - - TRACE_INFO("Serial Nr. %08x-%08x-%08x-%08x\r\n", - g_unique_id[0], g_unique_id[1], - g_unique_id[2], g_unique_id[3]); - + print_banner(); board_main_top(); TRACE_INFO("USB init...\r\n"); diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/chip.h b/firmware/atmel_softpack_libraries/libchip_sam3s/chip.h index e6af94e..8ae70df 100644 --- a/firmware/atmel_softpack_libraries/libchip_sam3s/chip.h +++ b/firmware/atmel_softpack_libraries/libchip_sam3s/chip.h @@ -15,7 +15,7 @@ /* Define attribute */ -#if defined ( __CC_ARM ) /* Keil µVision 4 */ +#if defined ( __CC_ARM ) /* Keil µVision 4 */ #define WEAK __attribute__ ((weak)) #elif defined ( __ICCARM__ ) /* IAR Ewarm 5.41+ */ #define WEAK __weak diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c b/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c index 2f56602..1ebab5b 100644 --- a/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c +++ b/firmware/atmel_softpack_libraries/libchip_sam3s/source/USBD_HAL.c @@ -45,11 +45,6 @@ * Headers *---------------------------------------------------------------------------*/ -#ifdef TRACE_LEVEL -#undef TRACE_LEVEL -#endif -#define TRACE_LEVEL TRACE_LEVEL_WARNING - #include "chip.h" #include "USBD_HAL.h" #include <usb/device/dfu/dfu.h> @@ -1082,6 +1077,14 @@ static inline uint8_t UDP_Read(uint8_t bEndpoint, * Exported functions *---------------------------------------------------------------------------*/ + +uint16_t USBD_GetEndpointSize(uint8_t bEndpoint) +{ + Endpoint *pEndpoint = &(endpoints[bEndpoint]); + + return pEndpoint->size; +} + /** * USBD (UDP) interrupt handler * Manages device resume, suspend, end of bus reset. @@ -1138,7 +1141,7 @@ void USBD_IrqHandler(void) /* Resume (Wakeup) */ if ((status & (UDP_ISR_WAKEUP | UDP_ISR_RXRSM)) != 0) { - TRACE_INFO_WP("Res "); + TRACE_DEBUG_WP("Res "); /* Clear and disable resume interrupts */ UDP->UDP_ICR = UDP_ICR_WAKEUP | UDP_ICR_RXRSM | UDP_ICR_RXSUSP; UDP->UDP_IDR = UDP_IDR_WAKEUP | UDP_IDR_RXRSM; @@ -1150,7 +1153,7 @@ void USBD_IrqHandler(void) This interrupt is always treated last (hence the '==') */ if (status == UDP_ISR_RXSUSP) { - TRACE_INFO_WP("Susp "); + TRACE_DEBUG_WP("Susp "); /* Enable wakeup */ UDP->UDP_IER = UDP_IER_WAKEUP | UDP_IER_RXRSM; /* Acknowledge interrupt */ @@ -1161,19 +1164,26 @@ void USBD_IrqHandler(void) /* End of bus reset */ else if ((status & UDP_ISR_ENDBUSRES) != 0) { - TRACE_INFO_WP("EoBRes "); + TRACE_DEBUG_WP("EoBRes "); #if defined(BOARD_USB_DFU) #if defined(APPLICATION_dfu) /* if we are currently in the DFU bootloader, and we are beyond * the MANIFEST stage, we shall switch to the normal * application */ - if (g_dfu->past_manifest) + if (g_dfu->past_manifest) { +#if defined(ENVIRONMENT_flash) USBDFU_SwitchToApp(); +#elif defined(ENVIRONMENT_dfu) + USBDFU_SwitchToDFU(); +#endif + } + #else /* if we are currently in the main application, and we are in - * appDETACH state, switch into the DFU bootloader */ - if (g_dfu->state == DFU_STATE_appDETACH) + * appDETACH state or past downloading, switch into the DFU bootloader. + */ + if (g_dfu->state == DFU_STATE_appDETACH || g_dfu->state == DFU_STATE_dfuMANIFEST) DFURT_SwitchToDFU(); #endif /* APPLICATION_dfu */ #endif /* BOARD_USB_DFU */ @@ -1202,7 +1212,7 @@ void USBD_IrqHandler(void) if (status != 0) { - TRACE_INFO_WP("\n\r - "); + TRACE_DEBUG_WP("\n\r - "); } } eptnum++; @@ -1211,7 +1221,7 @@ void USBD_IrqHandler(void) /* Toggle LED back to its previous state */ TRACE_DEBUG_WP("!"); - TRACE_INFO_WP("\n\r"); + TRACE_DEBUG_WP("\n\r"); if (USBD_GetState() >= USBD_STATE_POWERED) { //LED_Clear(USBD_LEDUSB); @@ -1361,7 +1371,7 @@ uint8_t USBD_HAL_ConfigureEP(const USBEndpointDescriptor *pDescriptor) UDP->UDP_IER = (1 << bEndpoint); } - TRACE_INFO_WP("CfgEp%d ", bEndpoint); + TRACE_DEBUG_WP("CfgEp%d ", bEndpoint); return bEndpoint; } @@ -1529,7 +1539,7 @@ void USBD_HAL_RemoteWakeUp(void) UDP_EnableUsbClock(); UDP_EnableTransceiver(); - TRACE_INFO_WP("RWUp "); + TRACE_DEBUG_WP("RWUp "); // Activates a remote wakeup (edge on ESR), then clear ESR UDP->UDP_GLB_STAT |= UDP_GLB_STAT_ESR; @@ -1692,7 +1702,10 @@ void USBD_HAL_Suspend(void) /* The device enters the Suspended state */ UDP_DisableTransceiver(); UDP_DisableUsbClock(); - UDP_DisablePeripheralClock(); + /* Don't disable peripheral clock; this somehow breaks completion of any IN transfers + * that have already been written to the peripheral, and which we expect to complete + * after resume */ + //UDP_DisablePeripheralClock(); } /** diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/source/efc.c b/firmware/atmel_softpack_libraries/libchip_sam3s/source/efc.c index 0c288e0..f8925b4 100644 --- a/firmware/atmel_softpack_libraries/libchip_sam3s/source/efc.c +++ b/firmware/atmel_softpack_libraries/libchip_sam3s/source/efc.c @@ -163,7 +163,7 @@ extern void EFC_TranslateAddress( Efc** ppEfc, uint32_t dwAddress, uint16_t* pwP wPage = (dwAddress - IFLASH_ADDR) / IFLASH_PAGE_SIZE; wOffset = (dwAddress - IFLASH_ADDR) % IFLASH_PAGE_SIZE; - TRACE_DEBUG( "Translated 0x%08X to page=%d and offset=%d\n\r", dwAddress, wPage, wOffset ) ; + TRACE_DEBUG( "Translated 0x%08lX to page=%d and offset=%d\n\r", dwAddress, wPage, wOffset ) ; /* Store values */ if ( pEfc ) { diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/source/exceptions.c b/firmware/atmel_softpack_libraries/libchip_sam3s/source/exceptions.c index 4799eae..7496f3a 100644 --- a/firmware/atmel_softpack_libraries/libchip_sam3s/source/exceptions.c +++ b/firmware/atmel_softpack_libraries/libchip_sam3s/source/exceptions.c @@ -151,8 +151,7 @@ WEAK void HardFault_Handler( void ) " mrseq r0, msp \n" " mrsne r0, psp \n" //" ldr r1, [r0, #24] \n" - " b hard_fault_handler_c\n" - ".syntax divided \n"); + " b hard_fault_handler_c\n"); } /** diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/source/flashd.c b/firmware/atmel_softpack_libraries/libchip_sam3s/source/flashd.c index 677ea30..c661b3f 100644 --- a/firmware/atmel_softpack_libraries/libchip_sam3s/source/flashd.c +++ b/firmware/atmel_softpack_libraries/libchip_sam3s/source/flashd.c @@ -134,7 +134,7 @@ static void ComputeLockRange( uint32_t dwStart, uint32_t dwEnd, uint32_t *pdwAct // Store actual page numbers EFC_ComputeAddress( pStartEfc, wActualStartPage, 0, pdwActualStart ) ; EFC_ComputeAddress( pEndEfc, wActualEndPage, 0, pdwActualEnd ) ; - TRACE_DEBUG( "Actual lock range is 0x%06X - 0x%06X\n\r", *pdwActualStart, *pdwActualEnd ) ; + TRACE_DEBUG( "Actual lock range is 0x%06lX - 0x%06lX\n\r", *pdwActualStart, *pdwActualEnd ) ; } diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/source/pio_it.c b/firmware/atmel_softpack_libraries/libchip_sam3s/source/pio_it.c index 7feccd1..781b914 100644 --- a/firmware/atmel_softpack_libraries/libchip_sam3s/source/pio_it.c +++ b/firmware/atmel_softpack_libraries/libchip_sam3s/source/pio_it.c @@ -211,6 +211,16 @@ extern void PIO_InitializeInterrupts( uint32_t dwPriority ) NVIC_EnableIRQ( PIOC_IRQn ) ; } +static InterruptSource *find_intsource4pin(const Pin *pPin) +{ + unsigned int i ; + for (i = 0; i < _dwNumSources; i++) { + if (_aIntSources[i].pPin == pPin) + return &_aIntSources[i]; + } + return NULL; +} + /** * Configures a PIO or a group of PIO to generate an interrupt on status * change. The provided interrupt handler will be called with the triggering @@ -228,15 +238,17 @@ extern void PIO_ConfigureIt( const Pin *pPin, void (*handler)( const Pin* ) ) assert( pPin ) ; pio = pPin->pio ; - assert( _dwNumSources < MAX_INTERRUPT_SOURCES ) ; - - /* Define new source */ - TRACE_DEBUG( "PIO_ConfigureIt: Defining new source #%" PRIu32 ".\n\r", _dwNumSources ) ; - pSource = &(_aIntSources[_dwNumSources]) ; - pSource->pPin = pPin ; + pSource = find_intsource4pin(pPin); + if (!pSource) { + /* Define new source */ + TRACE_DEBUG( "PIO_ConfigureIt: Defining new source #%" PRIu32 ".\n\r", _dwNumSources ) ; + assert( _dwNumSources < MAX_INTERRUPT_SOURCES ) ; + pSource = &(_aIntSources[_dwNumSources]) ; + pSource->pPin = pPin ; + _dwNumSources++ ; + } pSource->handler = handler ; - _dwNumSources++ ; /* PIO3 with additional interrupt support * Configure additional interrupt mode registers */ diff --git a/firmware/atmel_softpack_libraries/libchip_sam3s/source/unique_id.c b/firmware/atmel_softpack_libraries/libchip_sam3s/source/unique_id.c index 460eb9c..00c1aac 100644 --- a/firmware/atmel_softpack_libraries/libchip_sam3s/source/unique_id.c +++ b/firmware/atmel_softpack_libraries/libchip_sam3s/source/unique_id.c @@ -8,6 +8,11 @@ void EEFC_ReadUniqueID(unsigned int *pdwUniqueID) { unsigned int status; + /* disable interrupts, as interrupt vectors are stored in flash, + * and after STUI was issued, we can no longer access flassh until + * SPUI complets */ + __disable_irq(); + /* Errata / Workaround: Set bit 16 of EEFC Flash Mode Register * to 1 */ EFC->EEFC_FMR |= (1 << 16); @@ -40,4 +45,6 @@ void EEFC_ReadUniqueID(unsigned int *pdwUniqueID) do { status = EFC->EEFC_FSR; } while ((status & EEFC_FSR_FRDY) != EEFC_FSR_FRDY); + + __enable_irq(); } diff --git a/firmware/atmel_softpack_libraries/usb/device/core/USBD.c b/firmware/atmel_softpack_libraries/usb/device/core/USBD.c index bd39a53..747bdd0 100644 --- a/firmware/atmel_softpack_libraries/usb/device/core/USBD.c +++ b/firmware/atmel_softpack_libraries/usb/device/core/USBD.c @@ -300,7 +300,7 @@ void USBD_SetConfiguration(uint8_t cfgnum) else { deviceState = USBD_STATE_ADDRESS; /* Reset all endpoints */ - USBD_HAL_ResetEPs(0xFFFFFFFF, USBD_STATUS_RESET, 0); + USBD_HAL_ResetEPs(0xFFFFFFFE, USBD_STATUS_RESET, 0); } } diff --git a/firmware/atmel_softpack_libraries/usb/device/core/USBDDriver.c b/firmware/atmel_softpack_libraries/usb/device/core/USBDDriver.c index 22889cf..c6cf6e0 100644 --- a/firmware/atmel_softpack_libraries/usb/device/core/USBDDriver.c +++ b/firmware/atmel_softpack_libraries/usb/device/core/USBDDriver.c @@ -251,7 +251,7 @@ static void GetDescriptor( switch (type) { case USBGenericDescriptor_DEVICE: - TRACE_INFO_WP("Dev "); + TRACE_DEBUG_WP("Dev "); /* Adjust length and send descriptor */ @@ -263,7 +263,7 @@ static void GetDescriptor( break; case USBGenericDescriptor_CONFIGURATION: - TRACE_INFO_WP("Cfg "); + TRACE_DEBUG_WP("Cfg "); /* Adjust length and send descriptor */ @@ -280,7 +280,7 @@ static void GetDescriptor( break; case USBGenericDescriptor_DEVICEQUALIFIER: - TRACE_INFO_WP("Qua "); + TRACE_DEBUG_WP("Qua "); /* Check if descriptor exists */ @@ -301,7 +301,7 @@ static void GetDescriptor( break; case USBGenericDescriptor_OTHERSPEEDCONFIGURATION: - TRACE_INFO_WP("OSC "); + TRACE_DEBUG_WP("OSC "); /* Check if descriptor exists */ @@ -327,7 +327,7 @@ static void GetDescriptor( break; case USBGenericDescriptor_STRING: - TRACE_INFO_WP("Str%d ", indexRDesc); + TRACE_DEBUG_WP("Str%d ", indexRDesc); /* Check if descriptor exists */ @@ -504,13 +504,13 @@ void USBDDriver_RequestHandler( uint32_t length; uint32_t address; - TRACE_INFO_WP("Std "); + TRACE_DEBUG_WP("Std "); /* Check request code */ switch (USBGenericRequest_GetRequest(pRequest)) { case USBGenericRequest_GETDESCRIPTOR: - TRACE_INFO_WP("gDesc "); + TRACE_DEBUG_WP("gDesc "); /* Send the requested descriptor */ type = USBGetDescriptorRequest_GetDescriptorType(pRequest); @@ -520,7 +520,7 @@ void USBDDriver_RequestHandler( break; case USBGenericRequest_SETADDRESS: - TRACE_INFO_WP("sAddr "); + TRACE_DEBUG_WP("sAddr "); /* Sends a zero-length packet and then set the device address */ address = USBSetAddressRequest_GetAddress(pRequest); @@ -528,7 +528,7 @@ void USBDDriver_RequestHandler( break; case USBGenericRequest_SETCONFIGURATION: - TRACE_INFO_WP("sCfg "); + TRACE_DEBUG_WP("sCfg "); /* Set the requested configuration */ cfgnum = USBSetConfigurationRequest_GetConfiguration(pRequest); @@ -536,27 +536,27 @@ void USBDDriver_RequestHandler( break; case USBGenericRequest_GETCONFIGURATION: - TRACE_INFO_WP("gCfg "); + TRACE_DEBUG_WP("gCfg "); /* Send the current configuration number */ GetConfiguration(pDriver); break; case USBGenericRequest_GETSTATUS: - TRACE_INFO_WP("gSta "); + TRACE_DEBUG_WP("gSta "); /* Check who is the recipient */ switch (USBGenericRequest_GetRecipient(pRequest)) { case USBGenericRequest_DEVICE: - TRACE_INFO_WP("Dev "); + TRACE_DEBUG_WP("Dev "); /* Send the device status */ GetDeviceStatus(pDriver); break; case USBGenericRequest_ENDPOINT: - TRACE_INFO_WP("Ept "); + TRACE_DEBUG_WP("Ept "); /* Send the endpoint status */ eptnum = USBGenericRequest_GetEndpointNumber(pRequest); @@ -572,13 +572,13 @@ void USBDDriver_RequestHandler( break; case USBGenericRequest_CLEARFEATURE: - TRACE_INFO_WP("cFeat "); + TRACE_DEBUG_WP("cFeat "); /* Check which is the requested feature */ switch (USBFeatureRequest_GetFeatureSelector(pRequest)) { case USBFeatureRequest_ENDPOINTHALT: - TRACE_INFO_WP("Hlt "); + TRACE_DEBUG_WP("Hlt "); /* Unhalt endpoint and send a zero-length packet */ USBD_Unhalt(USBGenericRequest_GetEndpointNumber(pRequest)); @@ -586,7 +586,7 @@ void USBDDriver_RequestHandler( break; case USBFeatureRequest_DEVICEREMOTEWAKEUP: - TRACE_INFO_WP("RmWU "); + TRACE_DEBUG_WP("RmWU "); /* Disable remote wake-up and send a zero-length packet */ pDriver->isRemoteWakeUpEnabled = 0; @@ -602,13 +602,13 @@ void USBDDriver_RequestHandler( break; case USBGenericRequest_SETFEATURE: - TRACE_INFO_WP("sFeat "); + TRACE_DEBUG_WP("sFeat "); /* Check which is the selected feature */ switch (USBFeatureRequest_GetFeatureSelector(pRequest)) { case USBFeatureRequest_DEVICEREMOTEWAKEUP: - TRACE_INFO_WP("RmWU "); + TRACE_DEBUG_WP("RmWU "); /* Enable remote wake-up and send a ZLP */ pDriver->isRemoteWakeUpEnabled = 1; @@ -616,25 +616,25 @@ void USBDDriver_RequestHandler( break; case USBFeatureRequest_ENDPOINTHALT: - TRACE_INFO_WP("Halt "); + TRACE_DEBUG_WP("Halt "); /* Halt endpoint */ USBD_Halt(USBGenericRequest_GetEndpointNumber(pRequest)); USBD_Write(0, 0, 0, 0, 0); break; case USBFeatureRequest_OTG_B_HNP_ENABLE: - TRACE_INFO_WP("OTG_B_HNP_ENABLE "); + TRACE_DEBUG_WP("OTG_B_HNP_ENABLE "); pDriver->otg_features_supported |= 1<<USBFeatureRequest_OTG_B_HNP_ENABLE; USBD_Write(0, 0, 0, 0, 0); break; case USBFeatureRequest_OTG_A_HNP_SUPPORT: - TRACE_INFO_WP("OTG_A_HNP_SUPPORT "); + TRACE_DEBUG_WP("OTG_A_HNP_SUPPORT "); pDriver->otg_features_supported |= 1<<USBFeatureRequest_OTG_A_HNP_SUPPORT; USBD_Write(0, 0, 0, 0, 0); break; case USBFeatureRequest_OTG_A_ALT_HNP_SUPPORT: - TRACE_INFO_WP("OTG_A_ALT_HNP_SUPPORT "); + TRACE_DEBUG_WP("OTG_A_ALT_HNP_SUPPORT "); pDriver->otg_features_supported |= 1<<USBFeatureRequest_OTG_A_ALT_HNP_SUPPORT; USBD_Write(0, 0, 0, 0, 0); @@ -649,7 +649,7 @@ void USBDDriver_RequestHandler( break; case USBGenericRequest_SETINTERFACE: - TRACE_INFO_WP("sInterface "); + TRACE_DEBUG_WP("sInterface "); infnum = USBInterfaceRequest_GetInterface(pRequest); setting = USBInterfaceRequest_GetAlternateSetting(pRequest); @@ -657,7 +657,7 @@ void USBDDriver_RequestHandler( break; case USBGenericRequest_GETINTERFACE: - TRACE_INFO_WP("gInterface "); + TRACE_DEBUG_WP("gInterface "); infnum = USBInterfaceRequest_GetInterface(pRequest); GetInterface(pDriver, infnum); diff --git a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h index 2a44602..84ce14e 100644 --- a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h +++ b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu.h @@ -39,8 +39,8 @@ struct dfu_desc { #define DFU_FUNC_DESC { \ .bLength = USB_DT_DFU_SIZE, \ .bDescriptorType = USB_DT_DFU, \ - .bmAttributes = USB_DFU_CAN_UPLOAD | USB_DFU_CAN_DOWNLOAD, \ - .wDetachTimeOut = 0xff00, \ + .bmAttributes = USB_DFU_CAN_UPLOAD | USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH, \ + .wDetachTimeOut = 0x00, \ .wTransferSize = BOARD_DFU_PAGE_SIZE, \ .bcdDFUVersion = 0x0100, \ } @@ -101,7 +101,7 @@ struct dfudata { extern struct dfudata _g_dfu; extern struct dfudata *g_dfu; -void set_usb_serial_str(const uint8_t *serial_usbstr); +void set_usb_serial_str(void); void DFURT_SwitchToDFU(void); @@ -124,6 +124,9 @@ void USBDFU_Initialize(const USBDDriverDescriptors *pDescriptors); /* USBD tells us to switch from DFU mode to application mode */ void USBDFU_SwitchToApp(void); +/* USBD tells us to switch from to DFU mode */ +void USBDFU_SwitchToDFU(void); + /* Return values to be used by USBDFU_handle_{dn,up}load */ #define DFU_RET_NOTHING 0 #define DFU_RET_ZLP 1 diff --git a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_desc.c b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_desc.c index 75fded1..faebc13 100644 --- a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_desc.c +++ b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_desc.c @@ -13,14 +13,107 @@ #include <usb/common/dfu/usb_dfu.h> #include <usb/device/dfu/dfu.h> +#include "usb_strings_generated.h" + enum { STR_MANUF = 1, STR_PROD, STR_CONFIG, + // strings for the first alternate interface (e.g. DFU) _STR_FIRST_ALT, - STR_SERIAL = (_STR_FIRST_ALT+BOARD_DFU_NUM_IF), + // serial string + STR_SERIAL = (_STR_FIRST_ALT + BOARD_DFU_NUM_IF), + // version string (on additional interface) + VERSION_CONF_STR, + VERSION_STR, + // count + STRING_DESC_CNT, +}; + +/* string used to replace one of both DFU flash partition atlsettings */ +static const unsigned char usb_string_notavailable[] = { + USBStringDescriptor_LENGTH(13), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('n'), + USBStringDescriptor_UNICODE('o'), + USBStringDescriptor_UNICODE('t'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('a'), + USBStringDescriptor_UNICODE('v'), + USBStringDescriptor_UNICODE('a'), + USBStringDescriptor_UNICODE('i'), + USBStringDescriptor_UNICODE('l'), + USBStringDescriptor_UNICODE('a'), + USBStringDescriptor_UNICODE('b'), + USBStringDescriptor_UNICODE('l'), + USBStringDescriptor_UNICODE('e'), }; +/* USB string for the serial (using 128-bit device ID) */ +static unsigned char usb_string_serial[] = { + USBStringDescriptor_LENGTH(32), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('0'), + USBStringDescriptor_UNICODE('0'), + USBStringDescriptor_UNICODE('1'), + USBStringDescriptor_UNICODE('1'), + USBStringDescriptor_UNICODE('2'), + USBStringDescriptor_UNICODE('2'), + USBStringDescriptor_UNICODE('3'), + USBStringDescriptor_UNICODE('3'), + USBStringDescriptor_UNICODE('4'), + USBStringDescriptor_UNICODE('4'), + USBStringDescriptor_UNICODE('5'), + USBStringDescriptor_UNICODE('5'), + USBStringDescriptor_UNICODE('6'), + USBStringDescriptor_UNICODE('6'), + USBStringDescriptor_UNICODE('7'), + USBStringDescriptor_UNICODE('7'), + USBStringDescriptor_UNICODE('8'), + USBStringDescriptor_UNICODE('8'), + USBStringDescriptor_UNICODE('9'), + USBStringDescriptor_UNICODE('9'), + USBStringDescriptor_UNICODE('a'), + USBStringDescriptor_UNICODE('a'), + USBStringDescriptor_UNICODE('b'), + USBStringDescriptor_UNICODE('b'), + USBStringDescriptor_UNICODE('c'), + USBStringDescriptor_UNICODE('c'), + USBStringDescriptor_UNICODE('d'), + USBStringDescriptor_UNICODE('d'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('f'), + USBStringDescriptor_UNICODE('f'), +}; + +/* USB string for the version */ +static const unsigned char usb_string_version_conf[] = { + USBStringDescriptor_LENGTH(16), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('f'), + USBStringDescriptor_UNICODE('i'), + USBStringDescriptor_UNICODE('r'), + USBStringDescriptor_UNICODE('m'), + USBStringDescriptor_UNICODE('w'), + USBStringDescriptor_UNICODE('a'), + USBStringDescriptor_UNICODE('r'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('v'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('r'), + USBStringDescriptor_UNICODE('s'), + USBStringDescriptor_UNICODE('i'), + USBStringDescriptor_UNICODE('o'), + USBStringDescriptor_UNICODE('n'), +}; + +static const char git_version[] = GIT_VERSION; +static unsigned char usb_string_version[2 + ARRAY_SIZE(git_version) * 2 - 2]; +/** array of static (from usb_strings) and runtime (serial, version) USB strings */ +static const unsigned char *usb_strings_extended[STRING_DESC_CNT]; + static const USBDeviceDescriptor fsDevice = { .bLength = sizeof(USBDeviceDescriptor), .bDescriptorType = USBGenericDescriptor_DEVICE, @@ -34,12 +127,8 @@ static const USBDeviceDescriptor fsDevice = { .bcdDevice = BOARD_USB_RELEASE, .iManufacturer = STR_MANUF, .iProduct = STR_PROD, -#ifdef BOARD_USB_SERIAL .iSerialNumber = STR_SERIAL, -#else - .iSerialNumber = 0, -#endif - .bNumConfigurations = 1, + .bNumConfigurations = 2, // DFU + version configurations }; /* Alternate Interface Descriptor, we use one per partition/memory type */ @@ -52,7 +141,7 @@ static const USBDeviceDescriptor fsDevice = { .bNumEndpoints = 0, \ .bInterfaceClass = 0xfe, \ .bInterfaceSubClass = 1, \ - .iInterface = (_STR_FIRST_ALT+ALT), \ + .iInterface = (_STR_FIRST_ALT + ALT), \ .bInterfaceProtocol = 2, \ } @@ -85,17 +174,79 @@ const struct dfu_desc dfu_cfg_descriptor = { .func_dfu = DFU_FUNC_DESC }; -#include "usb_strings_generated.h" - -#if 0 -void set_usb_serial_str(const uint8_t *serial_usbstr) +void set_usb_serial_str(void) { - usb_strings[STR_SERIAL] = serial_usbstr; -} + unsigned int i; + + // put device ID into USB serial number description + unsigned int device_id[4]; + EEFC_ReadUniqueID(device_id); + char device_id_string[32 + 1]; + snprintf(device_id_string, ARRAY_SIZE(device_id_string), "%08x%08x%08x%08x", + device_id[0], device_id[1], device_id[2], device_id[3]); + for (i = 0; i < ARRAY_SIZE(device_id_string) - 1; i++) { + usb_string_serial[2 + 2 * i] = device_id_string[i]; + } + + // put version into USB string + usb_string_version[0] = USBStringDescriptor_LENGTH(ARRAY_SIZE(git_version) - 1); + usb_string_version[1] = USBGenericDescriptor_STRING; + for (i = 0; i < ARRAY_SIZE(git_version) - 1; i++) { + usb_string_version[2 + i * 2 + 0] = git_version[i]; + usb_string_version[2 + i * 2 + 1] = 0; + } + + // fill extended USB strings + for (i = 0; i < ARRAY_SIZE(usb_strings) && i < ARRAY_SIZE(usb_strings_extended); i++) { + usb_strings_extended[i] = usb_strings[i]; + } +#if defined(ENVIRONMENT_dfu) + usb_strings_extended[_STR_FIRST_ALT + 1] = usb_string_notavailable; +#elif defined(ENVIRONMENT_flash) + usb_strings_extended[_STR_FIRST_ALT + 2] = usb_string_notavailable; #endif + usb_strings_extended[STR_SERIAL] = usb_string_serial; + usb_strings_extended[VERSION_CONF_STR] = usb_string_version_conf; + usb_strings_extended[VERSION_STR] = usb_string_version; +} + +/* USB descriptor just to show the version */ +typedef struct _SIMTraceDriverConfigurationDescriptorVersion { + /** Standard configuration descriptor. */ + USBConfigurationDescriptor configuration; + USBInterfaceDescriptor version; +} __attribute__ ((packed)) SIMTraceDriverConfigurationDescriptorVersion; + +static const SIMTraceDriverConfigurationDescriptorVersion + configurationDescriptorVersion = { + /* Standard configuration descriptor for the interface descriptor*/ + .configuration = { + .bLength = sizeof(USBConfigurationDescriptor), + .bDescriptorType = USBGenericDescriptor_CONFIGURATION, + .wTotalLength = sizeof(SIMTraceDriverConfigurationDescriptorVersion), + .bNumInterfaces = 1, + .bConfigurationValue = 2, + .iConfiguration = VERSION_CONF_STR, + .bmAttributes = USBD_BMATTRIBUTES, + .bMaxPower = USBConfigurationDescriptor_POWER(100), + }, + /* Interface standard descriptor just holding the version information */ + .version = { + .bLength = sizeof(USBInterfaceDescriptor), + .bDescriptorType = USBGenericDescriptor_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = USB_CLASS_PROPRIETARY, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0, + .iInterface = VERSION_STR, + }, +}; static const USBConfigurationDescriptor *conf_desc_arr[] = { &dfu_cfg_descriptor.ucfg, + &configurationDescriptorVersion.configuration, }; const USBDDriverDescriptors dfu_descriptors = { @@ -108,6 +259,6 @@ const USBDDriverDescriptors dfu_descriptors = { .pHsConfiguration = NULL, .pHsQualifier = NULL, .pHsOtherSpeed = NULL, - .pStrings = usb_strings, - .numStrings = ARRAY_SIZE(usb_strings), + .pStrings = usb_strings_extended, + .numStrings = ARRAY_SIZE(usb_strings_extended), }; diff --git a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_driver.c b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_driver.c index 6230d6c..afec518 100644 --- a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_driver.c +++ b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_driver.c @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #include <unistd.h> @@ -33,8 +29,7 @@ #include <usb/common/dfu/usb_dfu.h> #include <usb/device/dfu/dfu.h> -/* FIXME: this was used for a special ELF section which then got called - * by DFU code and Application code, across flash partitions */ +/** specific memory location shared across bootloader and application */ #define __dfudata __attribute__ ((section (".dfudata"))) #define __dfufunc @@ -42,11 +37,14 @@ static USBDDriver usbdDriver; static unsigned char if_altsettings[1]; +/** structure containing the DFU state and magic value to know if DFU or application should be started */ __dfudata struct dfudata _g_dfu = { - .state = DFU_STATE_appIDLE, + .state = DFU_STATE_dfuIDLE, .past_manifest = 0, .total_bytes = 0, }; + +/** variable to structure containing DFU state */ struct dfudata *g_dfu = &_g_dfu; WEAK void dfu_drv_updstatus(void) @@ -83,7 +81,7 @@ static void __dfufunc handle_getstate(void) { uint8_t u8 = g_dfu->state; - TRACE_DEBUG("handle_getstate(%u)\n\r", g_dfu->state); + TRACE_DEBUG("handle_getstate(%ld)\n\r", g_dfu->state); USBD_Write(0, (char *)&u8, sizeof(u8), NULL, 0); } @@ -447,6 +445,7 @@ void USBDFU_Initialize(const USBDDriverDescriptors *pDescriptors) /* We already start in DFU idle mode */ g_dfu->state = DFU_STATE_dfuIDLE; + set_usb_serial_str(); USBDDriver_Initialize(&usbdDriver, pDescriptors, if_altsettings); USBD_Init(); USBD_Connect(); @@ -460,7 +459,20 @@ void USBDFU_SwitchToApp(void) /* make sure the MAGIC is not set to enter DFU again */ g_dfu->magic = 0; - printf("switching to app\r\n"); + /* disconnect from USB to ensure re-enumeration */ + USBD_Disconnect(); + + /* disable any interrupts during transition */ + __disable_irq(); + + /* Tell the hybrid to execute FTL JUMP! */ + NVIC_SystemReset(); +} + +void USBDFU_SwitchToDFU(void) +{ + /* make sure the MAGIC is not set to enter DFU again */ + g_dfu->magic = USB_DFU_MAGIC; /* disconnect from USB to ensure re-enumeration */ USBD_Disconnect(); diff --git a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_runtime.c b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_runtime.c index 444b75f..6e16a86 100644 --- a/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_runtime.c +++ b/firmware/atmel_softpack_libraries/usb/device/dfu/dfu_runtime.c @@ -15,10 +15,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ #include <board.h> @@ -36,7 +32,12 @@ #include <usb/common/dfu/usb_dfu.h> #include <usb/device/dfu/dfu.h> -struct dfudata *g_dfu = (struct dfudata *) IRAM_ADDR; +/** specific memory location shared across bootloader and application */ +#define __dfudata __attribute__ ((section (".dfudata"))) +/** structure containing the magic value to know if DFU or application should be started */ +__dfudata struct dfudata _g_dfu; +/** variable to structure containing the magic value to know if DFU or application should be started */ +struct dfudata *g_dfu = &_g_dfu; /* FIXME: this was used for a special ELF section which then got called * by DFU code and Application code, across flash partitions */ @@ -63,7 +64,7 @@ static void __dfufunc handle_getstate(void) { uint8_t u8 = g_dfu->state; - TRACE_DEBUG("handle_getstate(%u)\n\r", g_dfu->state); + TRACE_DEBUG("handle_getstate(%lu)\n\r", g_dfu->state); USBD_Write(0, (char *)&u8, sizeof(u8), NULL, 0); } @@ -160,6 +161,8 @@ void USBDFU_Runtime_RequestHandler(const USBGenericRequest *request) * will then trigger DFURT_SwitchToDFU() below */ TRACE_DEBUG("\r\n====dfu_detach\n\r"); g_dfu->state = DFU_STATE_appDETACH; + USBD_Write(0, 0, 0, 0, 0); + DFURT_SwitchToDFU(); ret = DFU_RET_ZLP; goto out; break; @@ -204,13 +207,14 @@ out: void DFURT_SwitchToDFU(void) { + __disable_irq(); + /* store the magic value that the DFU loader can detect and * activate itself, rather than boot into the application */ g_dfu->magic = USB_DFU_MAGIC; - - /* Disconnect the USB by remoting the pull-up */ + __DMB(); + /* Disconnect the USB by removing the pull-up */ USBD_Disconnect(); - __disable_irq(); /* reset the processor, we will start execution with the * ResetVector of the bootloader */ diff --git a/firmware/atmel_softpack_libraries/usb/include/USBD.h b/firmware/atmel_softpack_libraries/usb/include/USBD.h index 15a6859..6eeb68a 100644 --- a/firmware/atmel_softpack_libraries/usb/include/USBD.h +++ b/firmware/atmel_softpack_libraries/usb/include/USBD.h @@ -63,7 +63,7 @@ *------------------------------------------------------------------------------*/ /* Define attribute */ -#if defined ( __CC_ARM ) /* Keil µVision 4 */ +#if defined ( __CC_ARM ) /* Keil µVision 4 */ #define WEAK __attribute__ ((weak)) #elif defined ( __ICCARM__ ) /* IAR Ewarm 5.41+ */ #define WEAK __weak @@ -214,6 +214,8 @@ typedef void (*MblTransferCallback)(void *pArg, * Exported functions *------------------------------------------------------------------------------*/ +extern uint16_t USBD_GetEndpointSize(uint8_t bEndpoint); + //extern void USBD_IrqHandler(void); extern void USBD_Init(void); diff --git a/firmware/atmel_softpack_libraries/usb/include/USBDescriptors.h b/firmware/atmel_softpack_libraries/usb/include/USBDescriptors.h index 84b5ef6..aada0f1 100644 --- a/firmware/atmel_softpack_libraries/usb/include/USBDescriptors.h +++ b/firmware/atmel_softpack_libraries/usb/include/USBDescriptors.h @@ -296,7 +296,7 @@ typedef uint32_t (*USBDescriptorParseFunction)(void *descriptor, void *parseArg) */ #pragma pack(1) -#if defined ( __CC_ARM ) /* Keil µVision 4 */ +#if defined ( __CC_ARM ) /* Keil µVision 4 */ #elif defined ( __ICCARM__ ) /* IAR Ewarm 5.41+ */ #define __attribute__(...) #elif defined ( __GNUC__ ) /* GCC CS3 2009q3-68 */ diff --git a/firmware/libboard/common/include/board_common.h b/firmware/libboard/common/include/board_common.h index cb72d40..37fd1a3 100644 --- a/firmware/libboard/common/include/board_common.h +++ b/firmware/libboard/common/include/board_common.h @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #ifndef _BOARD_ #define _BOARD_ @@ -56,16 +52,12 @@ /** Core definition */ #define cortexm3 -#define PIO_LED_RED PIO_PA17 -#define PIO_LED_GREEN PIO_PA18 - -#define PIN_LED_RED {PIO_LED_RED, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} -#define PIN_LED_GREEN {PIO_LED_GREEN, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} -#define PINS_LEDS PIN_LED_RED, PIN_LED_GREEN - -#define LED_NUM_RED 0 -#define LED_NUM_GREEN 1 - +/* LEDs are used to indicate the status + * the LED definition is board specific + * most boards have two LEDs, one green and one red + * the red LED indicates of the main firmware is ready (on) or if there is an error (blinking) + * the green LED indicates if the firmware is idling (on) or if there is activity (blinking) + */ /** USART0 pin RX */ #define PIN_USART0_RXD {PIO_PA9A_URXD0, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} /** USART0 pin TX */ @@ -112,17 +104,17 @@ /* Interrupt request ID of USART peripheral connected to the phone */ #define IRQ_USART_PHONE USART1_IRQn -#define SIM_PWEN PIO_PA5 -#define VCC_FWD PIO_PA26 - // Board has UDP controller #define BOARD_USB_UDP #define BOARD_USB_DFU + + #define BOARD_DFU_BOOT_SIZE (16 * 1024) #define BOARD_DFU_RAM_SIZE (2 * 1024) #define BOARD_DFU_PAGE_SIZE 512 -#define BOARD_DFU_NUM_IF 2 +/** number of DFU interfaces (used to flash specific partitions) */ +#define BOARD_DFU_NUM_IF 3 extern void board_exec_dbg_cmd(int ch); extern void board_main_top(void); diff --git a/firmware/libboard/common/include/boardver_adc.h b/firmware/libboard/common/include/boardver_adc.h index 956c302..c8f320e 100644 --- a/firmware/libboard/common/include/boardver_adc.h +++ b/firmware/libboard/common/include/boardver_adc.h @@ -7,10 +7,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #pragma once diff --git a/firmware/libboard/common/include/led.h b/firmware/libboard/common/include/led.h index 339702d..ab12448 100644 --- a/firmware/libboard/common/include/led.h +++ b/firmware/libboard/common/include/led.h @@ -7,10 +7,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #pragma once @@ -31,7 +27,8 @@ enum led_pattern { BLINK_200O_F = 7, BLINK_600O_F = 8, BLINK_CUSTOM = 9, - BLINK_2F_O, + BLINK_2F_O = 10, + BLINK_5O_5F = 11, _NUM_LED_BLINK }; diff --git a/firmware/libboard/common/include/manifest.h b/firmware/libboard/common/include/manifest.h index b29c1aa..0635bf9 100644 --- a/firmware/libboard/common/include/manifest.h +++ b/firmware/libboard/common/include/manifest.h @@ -7,10 +7,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #ifndef _MANIFEST_H #define _MANIFEST_H diff --git a/firmware/libboard/common/include/sim_switch.h b/firmware/libboard/common/include/sim_switch.h index 3d131f2..61d9c1f 100644 --- a/firmware/libboard/common/include/sim_switch.h +++ b/firmware/libboard/common/include/sim_switch.h @@ -7,12 +7,16 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #pragma once +/** switch card lines to use physical or emulated card + * @param[in] nr card interface number (i.e. slot) + * @param[in] physical which physical interface to switch to (e.g. 0: physical, 1: virtual) + * @return 0 on success, negative else + */ int sim_switch_use_physical(unsigned int nr, int physical); +/** initialise card switching capabilities + * @return number of switchable card interfaces + */ int sim_switch_init(void); diff --git a/firmware/libboard/common/resources/sam3s4/dfu.ld b/firmware/libboard/common/resources/sam3s4/dfu.ld index e56a435..86e6622 100644 --- a/firmware/libboard/common/resources/sam3s4/dfu.ld +++ b/firmware/libboard/common/resources/sam3s4/dfu.ld @@ -39,17 +39,26 @@ SEARCH_DIR(.) MEMORY { /* reserve the first 16k (= 0x4000) for the DFU bootloader */ - rom (rx) : ORIGIN = 0x00404000, LENGTH = 0x0003c000 /* flash, 256K */ - /* reserve the first 32 (= 0x20) bytes for the _g_dfu struct */ - ram (rwx) : ORIGIN = 0x20000020, LENGTH = 0x0000bfe0 /* sram, 48K */ + crcstub (rx) : ORIGIN = 0x00400000 + 16K, LENGTH = 512 /* crcstub part */ + rom (rx) : ORIGIN = 0x00400000 + 16K + 512, LENGTH = 256K - 16K - 512 /* flash, 256K */ + /* note: dfudata will be at the start */ + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 48K /* SRAM, 48K */ } /* Section Definitions */ SECTIONS { - .text : - { + .crcstub : + { . = ALIGN(4); + KEEP(*(.crcstub_table)) + KEEP(*(.crcstub_code)) + } > crcstub = 0xff + + .text : + { + + . = ALIGN(512); _sfixed = .; KEEP(*(.vectors .vectors.*)) *(.text .text.* .gnu.linkonce.t.*) @@ -94,15 +103,20 @@ SECTIONS . = ALIGN(4); _efixed = .; /* End of text section */ - } > rom + } > rom = 0xff + + /DISCARD/ : + { + *(.ARM.exidx) + } - /* .ARM.exidx is sorted, so has to go in its own output section. */ - PROVIDE_HIDDEN (__exidx_start = .); - .ARM.exidx : + .blupdate : { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) + . = ALIGN(4); + _blupdate_start = .; + KEEP(*(.fwupdate .fwupdate.*)); + _blupdate_end = .; } > rom - PROVIDE_HIDDEN (__exidx_end = .); . = ALIGN(4); _etext = .; @@ -111,6 +125,8 @@ SECTIONS { . = ALIGN(4); _srelocate = .; + /* we must make sure the .dfudata is linked to start of RAM */ + *(.dfudata .dfudata.*); *(.ramfunc .ramfunc.*); *(.data .data.*); . = ALIGN(4); diff --git a/firmware/libboard/common/resources/sam3s4/flash.ld b/firmware/libboard/common/resources/sam3s4/flash.ld index bdebbde..b1de154 100644 --- a/firmware/libboard/common/resources/sam3s4/flash.ld +++ b/firmware/libboard/common/resources/sam3s4/flash.ld @@ -38,8 +38,8 @@ SEARCH_DIR(.) /* Memory Spaces Definitions */ MEMORY { - rom (rx) : ORIGIN = 0x00400000, LENGTH = 0x00040000 /* flash, 256K */ - ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x0000c000 /* sram, 48K */ + rom (rx) : ORIGIN = 0x00400000, LENGTH = 16K /* flash, 256K, but only the first 16K should be used for the bootloader */ + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 48K /* SRAM, 48K */ } /* Section Definitions */ @@ -94,13 +94,12 @@ SECTIONS _efixed = .; /* End of text section */ } > rom - /* .ARM.exidx is sorted, so has to go in its own output section. */ - PROVIDE_HIDDEN (__exidx_start = .); - .ARM.exidx : + /DISCARD/ : { - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } > rom - PROVIDE_HIDDEN (__exidx_end = .); + *(.ARM.exidx) + *(.crcstub_table) + *(.crcstub_code) + } . = ALIGN(4); _etext = .; diff --git a/firmware/libboard/common/source/board_cstartup_gnu.c b/firmware/libboard/common/source/board_cstartup_gnu.c index e82a2fb..d548a30 100644 --- a/firmware/libboard/common/source/board_cstartup_gnu.c +++ b/firmware/libboard/common/source/board_cstartup_gnu.c @@ -126,7 +126,7 @@ IntFunc exception_table[] = { IrqHandlerNotUsed /* 35 not used */ }; -#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu) +#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu) && defined(ENVIRONMENT_flash) #include "usb/device/dfu/dfu.h" static void BootIntoApp(void) { @@ -159,8 +159,9 @@ void ResetException( void ) LowLevelInit() ; -#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu) - if (!USBDFU_OverrideEnterDFU()) { +#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu) && defined(ENVIRONMENT_flash) + // boot application if there is not DFU override + if (!USBDFU_OverrideEnterDFU() && SCB->VTOR < IFLASH_ADDR + BOARD_DFU_BOOT_SIZE) { UART_Exit(); __disable_irq(); BootIntoApp(); diff --git a/firmware/libboard/common/source/board_lowlevel.c b/firmware/libboard/common/source/board_lowlevel.c index 8210938..a04ce10 100644 --- a/firmware/libboard/common/source/board_lowlevel.c +++ b/firmware/libboard/common/source/board_lowlevel.c @@ -127,6 +127,9 @@ extern WEAK void LowLevelInit( void ) SUPC->SUPC_SMMR = SUPC_SMMR_SMTH_3_0V | SUPC_SMMR_SMSMPL_CSM | SUPC_SMMR_SMRSTEN_ENABLE; + /* disable ERASE pin to prevent accidental flash erase */ + MATRIX->CCFG_SYSIO |= CCFG_SYSIO_SYSIO12; + /* enable both LED and green LED */ PIOA->PIO_PER |= PIO_LED_RED | PIO_LED_GREEN; PIOA->PIO_OER |= PIO_LED_RED | PIO_LED_GREEN; @@ -144,7 +147,7 @@ extern WEAK void LowLevelInit( void ) } */ -#ifndef qmod +#ifndef BOARD_MAINOSC_BYPASS /* Initialize main oscillator */ if ( !(PMC->CKGR_MOR & CKGR_MOR_MOSCSEL) ) { @@ -162,11 +165,11 @@ extern WEAK void LowLevelInit( void ) timeout = 0; while (!(PMC->PMC_SR & PMC_SR_MOSCSELS) && (timeout++ < CLOCK_TIMEOUT)); #else - /* QMOD has external 12MHz clock source */ + /* Board has external clock, not a crystal oscillator */ PIOB->PIO_PDR = (1 << 9); PIOB->PIO_PUDR = (1 << 9); PIOB->PIO_PPDDR = (1 << 9); - PMC->CKGR_MOR = CKGR_MOR_KEY(0x37) | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTBY| CKGR_MOR_MOSCSEL; + PMC->CKGR_MOR = CKGR_MOR_KEY(0x37) | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTBY | CKGR_MOR_MOSCSEL; #endif /* disable the red LED after main clock initialization */ @@ -215,3 +218,8 @@ void mdelay(unsigned int msecs) do { } while ((jiffies - jiffies_start) < msecs); } + +void abort() { + NVIC_SystemReset(); + while(1) {}; +} diff --git a/firmware/libboard/common/source/boardver_adc.c b/firmware/libboard/common/source/boardver_adc.c index 11799cc..9c7769d 100644 --- a/firmware/libboard/common/source/boardver_adc.c +++ b/firmware/libboard/common/source/boardver_adc.c @@ -7,10 +7,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #include "board.h" #include "boardver_adc.h" diff --git a/firmware/libboard/common/source/led.c b/firmware/libboard/common/source/led.c index 6772007..8fcb61f 100644 --- a/firmware/libboard/common/source/led.c +++ b/firmware/libboard/common/source/led.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #include <stdint.h> #include <string.h> @@ -58,6 +54,10 @@ static const struct blink_state bs_on[] = { { 0, 1 } }; +static const struct blink_state bs_5on_5off[] = { + { 500, 1 }, { 500, 0 } +}; + static const struct blink_state bs_3on_5off[] = { { 300, 1 }, { 500, 0 } }; @@ -107,6 +107,10 @@ static const struct blink_pattern patterns[] = { .states = bs_on, .size = ARRAY_SIZE(bs_on), }, + [BLINK_5O_5F] = { + .states = bs_5on_5off, + .size = ARRAY_SIZE(bs_5on_5off), + }, [BLINK_3O_5F] = { .states = bs_3on_5off, .size = ARRAY_SIZE(bs_3on_5off), diff --git a/firmware/libboard/common/source/manifest.c b/firmware/libboard/common/source/manifest.c index 0ad537c..fb3870f 100644 --- a/firmware/libboard/common/source/manifest.c +++ b/firmware/libboard/common/source/manifest.c @@ -7,10 +7,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #include "manifest.h" diff --git a/firmware/libboard/common/source/uart_console.c b/firmware/libboard/common/source/uart_console.c index bcfb0b7..ead5555 100644 --- a/firmware/libboard/common/source/uart_console.c +++ b/firmware/libboard/common/source/uart_console.c @@ -100,6 +100,7 @@ extern void UART_Configure( uint32_t baudrate, uint32_t masterClock) /* Enable TX interrupts */ pUart->UART_IER = UART_IER_TXRDY; + NVIC_SetPriority(CONSOLE_IRQ, 15); /* lowest priority */ NVIC_EnableIRQ(CONSOLE_IRQ); /* Enable receiver and transmitter */ diff --git a/firmware/libboard/ngff_cardem/include/board.h b/firmware/libboard/ngff_cardem/include/board.h new file mode 100644 index 0000000..f74cea1 --- /dev/null +++ b/firmware/libboard/ngff_cardem/include/board.h @@ -0,0 +1,162 @@ +/* Osmocom ngff-cardem board definition + * + * (C) 2021 by Harald Welte <laforge@osmocom.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#pragma once +#include "board_common.h" +#include "simtrace_usb.h" + +/** Name of the board */ +#define BOARD_NAME "NGFF-CARDEM" +/** Board definition */ +#define ngff_cardem + +/** oscillator used as main clock source (in Hz) */ +#define BOARD_MAINOSC 12000000 +/** desired main clock frequency (in Hz, based on BOARD_MAINOSC) */ +#define BOARD_MCK 58000000 // 12.000 * 29 / 6 + +/** MCU pin connected to red LED */ +#define PIO_LED_RED PIO_PA17 +/** MCU pin connected to green LED */ +#define PIO_LED_GREEN PIO_PA18 +/** red LED pin definition */ +#define PIN_LED_RED {PIO_LED_RED, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +/** green LED pin definition */ +#define PIN_LED_GREEN {PIO_LED_GREEN, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +/** LEDs pin definition */ +#define PINS_LEDS PIN_LED_RED, PIN_LED_GREEN +/** index for red LED in LEDs pin definition array */ +#define LED_NUM_RED 0 +/** index for green LED in LEDs pin definition array */ +#define LED_NUM_GREEN 1 +/** the green LED is actually red and used as indication for USIM1 */ +#define LED_USIM1 LED_GREEN + +/* USIM 2 interface (USART) */ +#define PIN_USIM2_CLK {PIO_PA2, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} +#define PIN_USIM2_IO {PIO_PA6, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} +#define PINS_ISO7816_USIM2 PIN_USIM2_CLK, PIN_USIM2_IO + +/* USIM 2 interface (TC) */ +#define PIN_USIM2_IO_TC {PIO_PA1, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} +#define PIN_USIM2_CLK_TC {PIO_PA4, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} +#define PINS_TC_USIM2 PIN_USIM2_IO_TC, PIN_USIM2_CLK_TC + +/* USIM 1 interface (USART) */ +#define PIN_USIM1_IO {PIO_PA22, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} +#define PIN_USIM1_CLK {PIO_PA23, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} +#define PINS_ISO7816_USIM1 PIN_USIM1_CLK, PIN_USIM1_IO + +/* USIM 1 interface (TC) */ +#define PIN_USIM1_IO_TC {PIO_PA27, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} +#define PIN_USIM1_CLK_TC {PIO_PA29, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} +#define PINS_TC_USIM1 PIN_USIM1_IO_TC, PIN_USIM1_CLK_TC + +#define PIN_USIM1_nRST {PIO_PA24, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT} +#define PIN_USIM1_VCC {PIO_PB3, PIOB, ID_PIOB, PIO_INPUT, PIO_DEFAULT} + +#define PIN_USIM2_nRST {PIO_PA7, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT} +//#define PIN_USIM2_VCC {PIO_PB2, PIOB, ID_PIOB, PIO_INPUT, PIO_DEFAULT} + +#define PINS_USIM1 PINS_TC_USIM1, PINS_ISO7816_USIM1, PIN_USIM1_nRST +#define PINS_USIM2 PINS_TC_USIM2, PINS_ISO7816_USIM2, PIN_USIM2_nRST + +/* from v3 and onwards only (!) */ +#define PIN_DET_USIM1_PRES {PIO_PA8, PIOA, ID_PIOA, PIO_INPUT, PIO_DEGLITCH | PIO_IT_EDGE} + +/* inputs reading the WWAN LED level */ +#define PIN_WWAN1 {PIO_PA15, PIOA, ID_PIOA, PIO_INPUT, PIO_PULLUP | PIO_DEGLITCH | PIO_IT_EDGE} +#define PINS_WWAN_IN { PIN_WWAN1 } + +#define PIN_MODEM_EN {PIO_PA11, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +#define PIN_N_MODEM_PWR_ON {PIO_PA26, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} + +/* outputs controlling RESET input of modems */ +#define PIN_PERST1 {PIO_PA25, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +#define PINS_PERST { PIN_PERST1 } + +#define PIN_VERSION_DET {PIO_PA19, PIOA, ID_PIOA, PIO_PERIPH_D, PIO_DEFAULT} + +/* GPIO towards SPDT switches between real SIM and SAM3 */ +//#define PIN_SIM_SWITCH1 {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} +//#define PIN_SIM_SWITCH2 {PIO_PA28, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} + +#define BOARD_USB_BMATTRIBUTES USBConfigurationDescriptor_SELFPOWERED_NORWAKEUP + +#define BOARD_USB_VENDOR_ID USB_VENDOR_OPENMOKO +#define BOARD_USB_PRODUCT_ID USB_PRODUCT_NGFF_CARDEM +#define BOARD_DFU_USB_PRODUCT_ID USB_PRODUCT_NGFF_CARDEM +#define BOARD_USB_RELEASE 0x010 + +#define DETECT_VCC_BY_ADC +#define VCC_UV_THRESH_1V8 1500000 +#define VCC_UV_THRESH_3V VCC_UV_THRESH_1V8 + +#ifdef APPLICATION_cardem +#define HAVE_CARDEM +#define HAVE_BOARD_CARDINSERT +struct cardem_inst; +void board_set_card_insert(struct cardem_inst *ci, bool card_insert); +#endif + +#ifdef APPLICATION_trace +#define HAVE_SNIFFER +#endif + +/* Card I/O data signal input/output (I/O_SIM in schematic) */ +#define PIN_SIM_IO {PIO_PA6A_TXD0, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} +/* Card CLK clock input (CLK_SIM in schematic) */ +#define PIN_SIM_CLK {PIO_PA2B_SCK0, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} +/* Card RST reset signal input (use as input since the phone will drive it) */ +#define PIN_SIM_RST_SNIFF {PIO_PA7, PIOA, ID_PIOA, PIO_INPUT, PIO_DEGLITCH | PIO_IT_EDGE} +/* Pins used to sniff phone-card communication */ +#define PINS_SIM_SNIFF PIN_SIM_IO, PIN_SIM_CLK, PIN_SIM_RST_SNIFF + +/* Pin to measure card I/O timing (to start measuring the ETU on I/O activity; connected I/O_SIM in schematic) */ +#define PIN_SIM_IO_INPUT {PIO_PA1B_TIOB0, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} +/* Pin used as clock input (to measure the ETU duration; connected to CLK_SIM in schematic) */ +#define PIN_SIM_CLK_INPUT {PIO_PA4B_TCLK0, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} +/* Pins used to measure ETU timing (using timer counter) */ +#define PINS_TC PIN_SIM_IO_INPUT, PIN_SIM_CLK_INPUT + +//default state: NO uart connected, modem connected to physical sim, NO sim presence override, modem powers sim slot +#define pin_conn_usim1_default {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +#define pin_conn_usim2_default {PIO_PA28, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +#define pin_conn_mdm_sim_default {PIO_PA0, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} +#define pin_conn_set_sim_det_default {PIO_PA13, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +#define pin_en_st_sim_vdd_default {PIO_PB2, PIOB, ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT} +#define pin_en_mdm_sim_vdd_default {PIO_PA16, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} + +//cardem state: uart2 (!) connected, NO modem connected to physical sim, sim presence override, NOTHING powers sim slot +#define pin_conn_usim1_cem {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +#define pin_conn_usim2_cem {PIO_PA28, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} +#define pin_conn_mdm_sim_cem {PIO_PA0, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +#define pin_en_st_sim_vdd_cem {PIO_PB2, PIOB, ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT} +#define pin_en_mdm_sim_vdd_cem {PIO_PA16, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} + +//trace state: uart2 (!) connected, modem connected to physical sim, st powers sim slot +#define pin_conn_usim1_trace {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +#define pin_conn_usim2_trace {PIO_PA28, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} +#define pin_conn_mdm_sim_trace {PIO_PA0, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} +#define pin_conn_set_sim_det_trace {PIO_PA13, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +#define pin_en_st_sim_vdd_trace {PIO_PB2, PIOB, ID_PIOB, PIO_OUTPUT_1, PIO_DEFAULT} +#define pin_en_mdm_sim_vdd_trace {PIO_PA16, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} + +#define PIN_MODEM_EN_off {PIO_PA11, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} + +#define PINS_SIM_DEFAULT pin_conn_usim1_default, pin_conn_usim2_default, pin_conn_mdm_sim_default, pin_conn_set_sim_det_default, PIN_N_MODEM_PWR_ON, PIN_MODEM_EN, pin_en_st_sim_vdd_default, pin_en_mdm_sim_vdd_default +#define PINS_SIM_CARDEM pin_conn_usim1_cem, pin_conn_usim2_cem, pin_conn_mdm_sim_cem, pin_en_mdm_sim_vdd_cem, pin_en_st_sim_vdd_cem// , pin_conn_set_sim_det_cem + +#define PINS_BUS_SNIFF pin_conn_usim1_trace, pin_conn_usim2_trace, pin_conn_mdm_sim_trace, pin_conn_set_sim_det_trace,PIN_MODEM_EN_off +#define PINS_PWR_SNIFF PIN_N_MODEM_PWR_ON, PIN_MODEM_EN, pin_en_st_sim_vdd_trace, pin_en_mdm_sim_vdd_trace diff --git a/firmware/libboard/ngff_cardem/include/card_pres.h b/firmware/libboard/ngff_cardem/include/card_pres.h new file mode 100644 index 0000000..e06642e --- /dev/null +++ b/firmware/libboard/ngff_cardem/include/card_pres.h @@ -0,0 +1,18 @@ +/* card presence utilities + * + * (C) 2016-2017 by Harald Welte <hwelte@hmw-consulting.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#pragma once + +int is_card_present(int port); +int card_present_init(void); diff --git a/firmware/libboard/ngff_cardem/include/wwan_led.h b/firmware/libboard/ngff_cardem/include/wwan_led.h new file mode 100644 index 0000000..a0f060a --- /dev/null +++ b/firmware/libboard/ngff_cardem/include/wwan_led.h @@ -0,0 +1,16 @@ +/* Code to read/track the status of the WWAN LEDs of attached modems + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#pragma once + +int wwan_led_active(int wwan); +int wwan_led_init(void); diff --git a/firmware/libboard/ngff_cardem/include/wwan_perst.h b/firmware/libboard/ngff_cardem/include/wwan_perst.h new file mode 100644 index 0000000..623184e --- /dev/null +++ b/firmware/libboard/ngff_cardem/include/wwan_perst.h @@ -0,0 +1,17 @@ +/* Code to control the PERST lines of attached modems + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#pragma once + +int wwan_perst_set(int modem_nr, int active); +int wwan_perst_do_reset_pulse(int modem_nr, unsigned int duration_ms); +int wwan_perst_init(void); diff --git a/firmware/libboard/ngff_cardem/product_string.txt b/firmware/libboard/ngff_cardem/product_string.txt new file mode 100644 index 0000000..09a33c6 --- /dev/null +++ b/firmware/libboard/ngff_cardem/product_string.txt @@ -0,0 +1 @@ +ngff-cardem diff --git a/firmware/libboard/ngff_cardem/source/board_ngff_cardem.c b/firmware/libboard/ngff_cardem/source/board_ngff_cardem.c new file mode 100644 index 0000000..fea64d3 --- /dev/null +++ b/firmware/libboard/ngff_cardem/source/board_ngff_cardem.c @@ -0,0 +1,155 @@ +/* sysmocom ngff-cardem application code + * + * (C) 2021 Harald Welte <laforge@osmocom.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "board.h" +#include "simtrace.h" +#include "utils.h" +#include "led.h" +#include "wwan_led.h" +#include "wwan_perst.h" +#include "sim_switch.h" +#include "boardver_adc.h" +#include "card_pres.h" +#include <osmocom/core/timer.h> +#include "usb_buf.h" + +/* array of generated USB Strings */ +extern unsigned char *usb_strings[]; + +/* returns '1' in case we should break any endless loop */ +void board_exec_dbg_cmd(int ch) +{ + switch (ch) { + case '?': + printf("\t?\thelp\n\r"); + printf("\tR\treset SAM3\n\r"); + printf("\tl\tswitch off LED 1\n\r"); + printf("\tL\tswitch on LED 1\n\r"); + printf("\tg\tswitch off LED 2\n\r"); + printf("\tG\tswitch on LED 2\n\r"); + printf("\t1\tGenerate 1ms reset pulse on WWAN1\n\r"); + printf("\t!\tSwitch Channel A from physical -> remote\n\r"); + printf("\tt\t(pseudo)talloc report\n\r"); + break; + case 'R': + printf("Asking NVIC to reset us\n\r"); + USBD_Disconnect(); + NVIC_SystemReset(); + break; + case 'l': + led_blink(LED_GREEN, BLINK_ALWAYS_OFF); + printf("LED 1 switched off\n\r"); + break; + case 'L': + led_blink(LED_GREEN, BLINK_ALWAYS_ON); + printf("LED 1 switched on\n\r"); + break; + case 'g': + led_blink(LED_RED, BLINK_ALWAYS_OFF); + printf("LED 2 switched off\n\r"); + break; + case 'G': + led_blink(LED_RED, BLINK_ALWAYS_ON); + printf("LED 2 switched on\n\r"); + break; + case '1': + printf("Resetting Modem\n\r"); + wwan_perst_do_reset_pulse(0, 300); + break; + case '!': + sim_switch_use_physical(0, 0); + break; + case 't': + talloc_report(NULL, stdout); + break; + default: + printf("Unknown command '%c'\n\r", ch); + break; + } +} + +void board_main_top(void) +{ +#ifndef APPLICATION_dfu + usb_buf_init(); + + wwan_led_init(); + wwan_perst_init(); + sim_switch_init(); +#endif + + /* Obtain the circuit board version (currently just prints voltage) */ + get_board_version_adc(); +#ifndef APPLICATION_dfu + /* Initialize checking for card insert/remove events */ + card_present_init(); +#endif + wwan_perst_set(0, 0); +} + +static int uart_has_loopback_jumper(void) +{ + unsigned int i; + const Pin uart_loopback_pins[] = { + {PIO_PA9A_URXD0, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT}, + {PIO_PA10A_UTXD0, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} + }; + + /* Configure UART pins as I/O */ + PIO_Configure(uart_loopback_pins, PIO_LISTSIZE(uart_loopback_pins)); + + /* Send pattern over UART TX and check if it is received on RX + * If the loop doesn't get interrupted, RxD always follows TxD and thus a + * loopback jumper has been placed on RxD/TxD, and we will boot + * into DFU unconditionally + */ + int has_loopback_jumper = 1; + for (i = 0; i < 10; i++) { + /* Set TxD high; abort if RxD doesn't go high either */ + PIO_Set(&uart_loopback_pins[1]); + if (!PIO_Get(&uart_loopback_pins[0])) { + has_loopback_jumper = 0; + break; + } + /* Set TxD low, abort if RxD doesn't go low either */ + PIO_Clear(&uart_loopback_pins[1]); + if (PIO_Get(&uart_loopback_pins[0])) { + has_loopback_jumper = 0; + break; + } + } + + /* Put pins back to UART mode */ + const Pin uart_pins[] = {PINS_UART}; + PIO_Configure(uart_pins, PIO_LISTSIZE(uart_pins)); + + return has_loopback_jumper; +} + +int board_override_enter_dfu(void) +{ + /* If the loopback jumper is set, we enter DFU mode */ + if (uart_has_loopback_jumper()) + return 1; + + return 0; +} + + static const Pin deton = {PIO_PA13, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}; + static const Pin detoff = {PIO_PA13, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}; + +void board_set_card_insert(struct cardem_inst *ci, bool card_insert) +{ + PIO_Configure(card_insert ? &deton : &detoff, 1); +}
\ No newline at end of file diff --git a/firmware/libboard/ngff_cardem/source/card_pres.c b/firmware/libboard/ngff_cardem/source/card_pres.c new file mode 100644 index 0000000..d425ec5 --- /dev/null +++ b/firmware/libboard/ngff_cardem/source/card_pres.c @@ -0,0 +1,72 @@ +/* card presence utilities + * + * (C) 2016-2021 by Harald Welte <hwelte@hmw-consulting.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <osmocom/core/timer.h> +#include "board.h" +#include "utils.h" +#include "card_pres.h" + +#define NUM_CARDPRES 1 + +#define TIMER_INTERVAL_MS 500 + +static const Pin pin_cardpres[NUM_CARDPRES] = { PIN_DET_USIM1_PRES }; +static int last_state[NUM_CARDPRES] = { -1 }; +static struct osmo_timer_list cardpres_timer; + +/* Determine if a SIM card is present in the given slot */ +int is_card_present(int port) +{ + const Pin *pin; + int present; + + if (port < 0 || port >= NUM_CARDPRES) + return -1; + pin = &pin_cardpres[port]; + + + /* high active here */ + present = PIO_Get(pin); + + return present; +} + +static void cardpres_tmr_cb(void *data) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(pin_cardpres); i++) { + int state = is_card_present(i); + if (state != last_state[i]) { + TRACE_INFO("%u: Card Detect Status %d -> %d\r\n", i, last_state[i], state); + /* FIXME: report to USB host */ + last_state[i] = state; + } + } + + osmo_timer_schedule(&cardpres_timer, 0, TIMER_INTERVAL_MS*1000); +} + +int card_present_init(void) +{ + unsigned int i; + + PIO_Configure(pin_cardpres, ARRAY_SIZE(pin_cardpres)); + + /* start timer */ + cardpres_timer.cb = cardpres_tmr_cb; + osmo_timer_schedule(&cardpres_timer, 0, TIMER_INTERVAL_MS*1000); + + return 2; +} diff --git a/firmware/libboard/ngff_cardem/source/sim_switch.c b/firmware/libboard/ngff_cardem/source/sim_switch.c new file mode 100644 index 0000000..999d7a7 --- /dev/null +++ b/firmware/libboard/ngff_cardem/source/sim_switch.c @@ -0,0 +1,77 @@ +/* Code to switch between local (physical) and remote (emulated) SIM + * + * (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "board.h" +#include "trace.h" +#include "led.h" +#include "sim_switch.h" + +//uart12bus 2-20e pa20 +//uart22bus 1-20e pa28 +//usim2bus 1-10e pa0 pivot +//sim det 2-10e pa13 + +static const Pin pins_default[] = {PINS_SIM_DEFAULT}; +static const Pin pins_cem[] = {PINS_SIM_CARDEM}; + +static int initialized = 0; + +int sim_switch_use_physical(unsigned int nr, int physical) +{ + const Pin pin = PIN_MODEM_EN;// PIN_N_MODEM_PWR_ON; + enum led led; + + if (!initialized) { + TRACE_ERROR("Somebody forgot to call sim_switch_init()\r\n"); + sim_switch_init(); + } + + TRACE_INFO("Modem %d: %s SIM\n\r", nr, + physical ? "physical" : "virtual"); + + switch (nr) { + case 0: + led = LED_USIM1; + break; + + default: + TRACE_ERROR("Invalid SIM%u\n\r", nr); + return -1; + } + + if (physical) { + TRACE_INFO("%u: Use local/physical SIM\r\n", nr); + PIO_Configure(pins_default, PIO_LISTSIZE(pins_default)); + led_blink(led, BLINK_ALWAYS_ON); + } else { + TRACE_INFO("%u: Use remote/emulated SIM\r\n", nr); + PIO_Configure(pins_cem, PIO_LISTSIZE(pins_cem)); + led_blink(led, BLINK_5O_5F); + } + + /* just power cycle the modem because this circumvents weird issues with unreliable signals */ + PIO_Clear(&pin); + mdelay(200); + PIO_Set(&pin); + + + return 0; +} + +int sim_switch_init(void) +{ + PIO_Configure(pins_default, PIO_LISTSIZE(pins_default)); + initialized = 1; + return 1; +} diff --git a/firmware/libboard/ngff_cardem/source/wwan_led.c b/firmware/libboard/ngff_cardem/source/wwan_led.c new file mode 100644 index 0000000..619d5c8 --- /dev/null +++ b/firmware/libboard/ngff_cardem/source/wwan_led.c @@ -0,0 +1,89 @@ +/* Code to read/track the status of the WWAN LEDs of attached modems + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +/* Depending on the board this is running on, it might be possible + * for the controller to read the status of the WWAN LED output lines of + * the cellular modem. If the board supports this, it sets the + * PIN_WWAN1 and/or PIN_WWAN2 defines in its board.h file. + */ +#include "board.h" +#include "wwan_led.h" + +#ifdef PIN_WWAN1 +static const Pin pin_wwan1 = PIN_WWAN1; + +static void wwan1_irqhandler(const Pin *pPin) +{ + int active = wwan_led_active(0); + + TRACE_INFO("0: WWAN LED %u\r\n", active); + + /* TODO: notify host via USB */ +} +#endif + +#ifdef PIN_WWAN2 +static const Pin pin_wwan2 = PIN_WWAN2; + +static void wwan2_irqhandler(const Pin *pPin) +{ + int active = wwan_led_active(1); + TRACE_INFO("1: WWAN LED %u\r\n", active); + + /* TODO: notify host via USB */ +} +#endif + +/* determine if a given WWAN led is currently active or not */ +int wwan_led_active(int wwan) +{ + const Pin *pin; + int active; + + switch (wwan) { +#ifdef PIN_WWAN1 + case 0: + pin = &pin_wwan1; + break; +#endif +#ifdef PIN_WWAN2 + case 1: + pin = &pin_wwan2; + break; +#endif + default: + return -1; + } + + active = PIO_Get(pin) ? 0 : 1; + return active; +} + +int wwan_led_init(void) +{ + int num_leds = 0; + +#ifdef PIN_WWAN1 + PIO_Configure(&pin_wwan1, 1); + PIO_ConfigureIt(&pin_wwan1, wwan1_irqhandler); + PIO_EnableIt(&pin_wwan1); + num_leds++; +#endif + +#ifdef PIN_WWAN2 + PIO_Configure(&pin_wwan2, 1); + PIO_ConfigureIt(&pin_wwan2, wwan2_irqhandler); + PIO_EnableIt(&pin_wwan2); + num_leds++; +#endif + return num_leds; +} diff --git a/firmware/libboard/ngff_cardem/source/wwan_perst.c b/firmware/libboard/ngff_cardem/source/wwan_perst.c new file mode 100644 index 0000000..b314781 --- /dev/null +++ b/firmware/libboard/ngff_cardem/source/wwan_perst.c @@ -0,0 +1,123 @@ +/* Code to control the PERST lines of attached modems + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +/* Depending on the board this is running on, it might be possible + * for the controller to set the status of the PERST input line of + * the cellular modem. If the board supports this, it sets the + * PIN_PERST1 and/or PIN_PERST2 defines in its board.h file. + */ +#include "board.h" +#include "trace.h" +#include "wwan_perst.h" +#include <osmocom/core/timer.h> + +struct wwan_perst { + uint8_t idx; + const Pin pin; + struct osmo_timer_list timer; +}; + +#ifdef PIN_PERST1 +static struct wwan_perst perst1 = { + .idx = 0, + .pin = PIN_PERST1, +}; +#endif + +#ifdef PIN_PERST2 +static struct wwan_perst perst2 = { + .idx = 1, + .pin = PIN_PERST2, +}; +#endif + +static int initialized = 0; + +static void perst_tmr_cb(void *data) +{ + struct wwan_perst *perst = data; + /* release the (low-active) reset */ + TRACE_INFO("%u: De-asserting modem reset\r\n", perst->idx); + PIO_Clear(&perst->pin); +} + +static struct wwan_perst *get_perst_for_modem(int modem_nr) +{ + if (!initialized) { + TRACE_ERROR("Somebody forgot to call wwan_perst_init()\r\n"); + wwan_perst_init(); + } + + switch (modem_nr) { +#ifdef PIN_PERST1 + case 0: + return &perst1; +#endif +#ifdef PIN_PERST2 + case 1: + return &perst2; +#endif + default: + return NULL; + } +} + +int wwan_perst_do_reset_pulse(int modem_nr, unsigned int duration_ms) +{ + struct wwan_perst *perst = get_perst_for_modem(modem_nr); + if (!perst) + return -1; + + TRACE_INFO("%u: Asserting modem reset\r\n", modem_nr); + PIO_Set(&perst->pin); + osmo_timer_schedule(&perst->timer, duration_ms/1000, (duration_ms%1000)*1000); + + return 0; +} + +int wwan_perst_set(int modem_nr, int active) +{ + struct wwan_perst *perst = get_perst_for_modem(modem_nr); + if (!perst) + return -1; + + osmo_timer_del(&perst->timer); + if (active) { + TRACE_INFO("%u: Asserting modem reset\r\n", modem_nr); + PIO_Set(&perst->pin); + } else { + TRACE_INFO("%u: De-asserting modem reset\r\n", modem_nr); + PIO_Clear(&perst->pin); + } + + return 0; +} + +int wwan_perst_init(void) +{ + int num_perst = 0; +#ifdef PIN_PERST1 + PIO_Configure(&perst1.pin, 1); + perst1.timer.cb = perst_tmr_cb; + perst1.timer.data = (void *) &perst1; + num_perst++; +#endif + +#ifdef PIN_PERST2 + PIO_Configure(&perst2.pin, 1); + perst2.timer.cb = perst_tmr_cb; + perst2.timer.data = (void *) &perst2; + num_perst++; +#endif + initialized = 1; + return num_perst; +} diff --git a/firmware/libboard/octsimtest/include/board.h b/firmware/libboard/octsimtest/include/board.h new file mode 100644 index 0000000..3540aa2 --- /dev/null +++ b/firmware/libboard/octsimtest/include/board.h @@ -0,0 +1,119 @@ +/* octSIMtest with SAM3S board definition + * + * (C) 2019 by sysmocom -s.f.m.c. GmbH, Author:Joachim Steiger <jsteiger@sysmocom.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#pragma once +#include "board_common.h" +#include "simtrace_usb.h" + +/* Name of the board */ +#define BOARD_NAME "OCTSIMTEST" +/* Board definition */ +#define octsimtest + +/** oscillator used as main clock source (in Hz) */ +#define BOARD_MAINOSC 18432000 +/** desired main clock frequency (in Hz, based on BOARD_MAINOSC) */ +#define BOARD_MCK 58982400 // 18.432 * 16 / 5 + +/** Pin configuration **/ + +/** there is no red LED, but the code needs this second LED, thus we provide an unused pin */ +#define PIO_LED_RED PIO_PB13 +/** MCU pin connected to green LED, which is actually amber, and the logic is inverted since it is connected to an NPN transistor (used as open drain) */ +#define PIO_LED_GREEN PIO_PA4 +/** red LED pin definition */ +#define PIN_LED_RED {PIO_LED_RED, PIOB, ID_PIOB, PIO_OUTPUT_1, PIO_DEFAULT} +/** green LED pin definition */ +#define PIN_LED_GREEN {PIO_LED_GREEN, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +/** LEDs pin definition */ +#define PINS_LEDS PIN_LED_RED, PIN_LED_GREEN +/** index for red LED in LEDs pin definition array */ +#define LED_NUM_RED 0 +/** index for green LED in LEDs pin definition array */ +#define LED_NUM_GREEN 1 + +/* Button to force bootloader start (shorted to ground when pressed */ +#define PIN_BOOTLOADER_SW {PIO_PA5, PIOA, ID_PIOA, PIO_INPUT, PIO_PULLUP} + +// FIXME PA8 is 32khz xtal on octsimtest +/* Pull card presence pin high (shorted to ground in card slot when card is present) */ + +/** Phone connection **/ +/* Phone USIM slot 1 VCC pin (VCC_PHONE in schematic) */ +#define PIN_USIM1_VCC {PIO_PA25, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT} +/* Phone USIM slot 1 RST pin (active low; RST_PHONE in schematic) */ +#define PIN_USIM1_nRST {PIO_PA24, PIOA, ID_PIOA, PIO_INPUT, PIO_IT_EDGE | PIO_DEGLITCH } +/* Phone I/O data signal input/output (I/O_PHONE in schematic) */ +#define PIN_PHONE_IO {PIO_PA22A_TXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} +/* Phone CLK clock input (CLK_PHONE in schematic) */ +#define PIN_PHONE_CLK {PIO_PA23A_SCK1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} +/* Pin used to switch level shifter in I/O line between rx (0) and tx (1) */ +#define PIN_USIM1_IO_DIR {PIO_PA26, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} +/* Pin used for phone USIM slot 1 communication */ +#define PINS_USIM1 PIN_PHONE_IO, PIN_PHONE_CLK, PIN_PHONE_CLK_INPUT, PIN_USIM1_VCC, PIN_PHONE_IO_INPUT, PIN_USIM1_nRST, PIN_USIM1_IO_DIR +/* Phone I/O data signal input/output (unused USART RX input; connected to I/O_PHONE in schematic) */ +#define PIN_PHONE_IO_INPUT {PIO_PA21A_RXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} +/* Pin used as clock input (to measure the ETU duration; connected to CLK_PHONE in schematic) */ +#define PIN_PHONE_CLK_INPUT {PIO_PA29B_TCLK2, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} + +/** Default pin configuration **/ + +/** External SPI flash interface **/ +/* SPI MISO pin definition */ +#define PIN_SPI_MISO {PIO_PA12A_MISO, PIOA, PIOA, PIO_PERIPH_A, PIO_PULLUP} +/* SPI MOSI pin definition */ +#define PIN_SPI_MOSI {PIO_PA13A_MOSI, PIOA, PIOA, PIO_PERIPH_A, PIO_DEFAULT} +/* SPI SCK pin definition */ +#define PIN_SPI_SCK {PIO_PA14A_SPCK, PIOA, PIOA, PIO_PERIPH_A, PIO_DEFAULT} +/* SPI pins definition. Contains MISO, MOSI & SCK */ +#define PINS_SPI PIN_SPI_MISO, PIN_SPI_MOSI, PIN_SPI_SCK +/* SPI chip select 0 pin definition */ +#define PIN_SPI_NPCS0 {PIO_PA11A_NPCS0, PIOA, PIOA, PIO_PERIPH_A, PIO_DEFAULT} +/* SPI flash write protect pin (active low, pulled low) */ +#define PIN_SPI_WP {PA15, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} + +/** USB definitions */ +/* OpenMoko SIMtrace 2 USB vendor ID */ +#define BOARD_USB_VENDOR_ID USB_VENDOR_OPENMOKO +/* OpenMoko SIMtrace 2 USB product ID (main application/runtime mode) */ +#define BOARD_USB_PRODUCT_ID USB_PRODUCT_OCTSIMTEST +/* OpenMoko SIMtrace 2 DFU USB product ID (DFU bootloader/DFU mode) */ +#define BOARD_DFU_USB_PRODUCT_ID USB_PRODUCT_OCTSIMTEST +/* USB release number (bcdDevice, shown as 0.00) */ +#define BOARD_USB_RELEASE 0x000 +/* Indicate SIMtrace is bus power in USB attributes */ +#define BOARD_USB_BMATTRIBUTES USBConfigurationDescriptor_BUSPOWERED_NORWAKEUP + +#define DETECT_VCC_BY_ADC +/* we have a resistive voltage divider of 47 + 30 kOhms to also detect 5V supply power */ +#define VCC_UV_THRESH_1V8 (1500000*47)/(47+30) +#define VCC_UV_THRESH_3V (2500000*47)/(47+30) + +#define HAVE_SLOT_MUX + +#define HAVE_BOARD_CARDINSERT +struct cardem_inst; +void board_set_card_insert(struct cardem_inst *ci, bool card_insert); + +/** Supported modes */ +/* SIMtrace board supports sniffer mode */ +//#define HAVE_SNIFFER +/* SIMtrace board supports CCID mode */ +//#define HAVE_CCID +/* SIMtrace board supports card emulation mode */ +#define HAVE_CARDEM +/* SIMtrace board supports man-in-the-middle mode */ +//#define HAVE_MITM +/* octsimtest board supports gpio_test mode */ +#define HAVE_GPIO_TEST diff --git a/firmware/libboard/octsimtest/include/i2c.h b/firmware/libboard/octsimtest/include/i2c.h new file mode 100644 index 0000000..7edad2f --- /dev/null +++ b/firmware/libboard/octsimtest/include/i2c.h @@ -0,0 +1,24 @@ +/* I2C EEPROM memory read and write utilities + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#pragma once + +#include <stdbool.h> + +void i2c_pin_init(void); + +bool i2c_write_byte(bool send_start, bool send_stop, uint8_t byte); +uint8_t i2c_read_byte(bool nack, bool send_stop); +void i2c_stop_cond(void); + +int eeprom_write_byte(uint8_t slave, uint8_t addr, uint8_t byte); +int eeprom_read_byte(uint8_t slave, uint8_t addr); diff --git a/firmware/libboard/octsimtest/include/mcp23017.h b/firmware/libboard/octsimtest/include/mcp23017.h new file mode 100644 index 0000000..1f05d3d --- /dev/null +++ b/firmware/libboard/octsimtest/include/mcp23017.h @@ -0,0 +1,23 @@ +/* mcp23017 i2c gpio expander read and write utilities + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#pragma once + +#define MCP23017_ADDRESS 0x20 + +int mcp23017_init(uint8_t slave, uint8_t iodira, uint8_t iodirb); +int mcp23017_test(uint8_t slave); +int mcp23017_toggle(uint8_t slave); +int mcp23017_set_output_a(uint8_t slave, uint8_t val); +int mcp23017_set_output_b(uint8_t slave, uint8_t val); +//int mcp23017_write_byte(uint8_t slave, uint8_t addr, uint8_t byte); +//int mcp23017_read_byte(uint8_t slave, uint8_t addr); diff --git a/firmware/libboard/octsimtest/include/mux.h b/firmware/libboard/octsimtest/include/mux.h new file mode 100644 index 0000000..3181478 --- /dev/null +++ b/firmware/libboard/octsimtest/include/mux.h @@ -0,0 +1,17 @@ +#pragma once + +void mux_init(void); +int mux_set_slot(uint8_t s); +int mux_get_slot(void); +void mux_set_freq(uint8_t s); + +/* this reflects the wiring between U5 and U4 */ +#define MUX_FREQ_DIV_2 0 +#define MUX_FREQ_DIV_4 1 +#define MUX_FREQ_DIV_16 2 +#define MUX_FREQ_DIV_32 3 +#define MUX_FREQ_DIV_32 3 +#define MUX_FREQ_DIV_128 4 +#define MUX_FREQ_DIV_512 5 +#define MUX_FREQ_DIV_2048 6 +#define MUX_FREQ_DIV_4096 7 diff --git a/firmware/libboard/octsimtest/product_string.txt b/firmware/libboard/octsimtest/product_string.txt new file mode 100644 index 0000000..83cbcf5 --- /dev/null +++ b/firmware/libboard/octsimtest/product_string.txt @@ -0,0 +1 @@ +sysmoOCTSIM-Tester diff --git a/firmware/libboard/octsimtest/source/board_octsimtest.c b/firmware/libboard/octsimtest/source/board_octsimtest.c new file mode 100644 index 0000000..92496da --- /dev/null +++ b/firmware/libboard/octsimtest/source/board_octsimtest.c @@ -0,0 +1,120 @@ +/* SIMtrace with SAM3S specific application code + * + * (C) 2017 by Harald Welte <laforge@gnumonks.org> + * (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <stdbool.h> +#include "board.h" +#include "simtrace.h" +#include "utils.h" +#include "sim_switch.h" +#include <osmocom/core/timer.h> +#include "usb_buf.h" +#include "i2c.h" +#include "mcp23017.h" +#include "mux.h" + +static bool mcp2317_present = false; + +void board_exec_dbg_cmd(int ch) +{ + switch (ch) { + case '?': + printf("\t?\thelp\n\r"); + printf("\t0-8\tselect physical SIM slot\n\r"); + printf("\tR\treset SAM3\n\r"); + printf("\tm\trun mcp23017 test\n\r"); + printf("\ti\tset card insert via I2C\n\r"); + printf("\tI\tdisable card insert\n\r"); + break; + case '0': mux_set_slot(0); break; + case '1': mux_set_slot(1); break; + case '2': mux_set_slot(2); break; + case '3': mux_set_slot(3); break; + case '4': mux_set_slot(4); break; + case '5': mux_set_slot(5); break; + case '6': mux_set_slot(6); break; + case '7': mux_set_slot(7); break; + case 'R': + printf("Asking NVIC to reset us\n\r"); + USBD_Disconnect(); + NVIC_SystemReset(); + break; + case 'm': + mcp23017_test(MCP23017_ADDRESS); + break; + case 'i': + printf("Setting card insert (slot=%u)\r\n", mux_get_slot()); + mcp23017_set_output_a(MCP23017_ADDRESS, (1 << mux_get_slot())); + break; + case 'I': + printf("Releasing card insert (slot=%u)\r\n", mux_get_slot()); + mcp23017_set_output_a(MCP23017_ADDRESS, 0); + break; + default: + printf("Unknown command '%c'\n\r", ch); + break; + } +} + +void board_main_top(void) +{ +#ifndef APPLICATION_dfu + usb_buf_init(); + + mux_init(); + i2c_pin_init(); + /* PORT A: all outputs, Port B0 output, B1..B7 unused */ + if (mcp23017_init(MCP23017_ADDRESS, 0x00, 0xfe) == 0) { + mcp2317_present = true; + mcp23017_set_output_a(MCP23017_ADDRESS, 0); + } + /* Initialize checking for card insert/remove events */ + //card_present_init(); +#endif +} + +int board_override_enter_dfu(void) +{ + const Pin bl_sw_pin = PIN_BOOTLOADER_SW; + + PIO_Configure(&bl_sw_pin, 1); + + /* Enter DFU bootloader in case the respective button is pressed */ + if (PIO_Get(&bl_sw_pin) == 0) { + /* do not print to early since the console is not initialized yet */ + //printf("BOOTLOADER switch pressed -> Force DFU\n\r"); + return 1; + } else + return 0; +} + +void board_set_card_insert(struct cardem_inst *ci, bool card_insert) +{ + int s = mux_get_slot(); + + /* A0 .. A7 of the MCP are each connected to the gate of a FET which closes + * the sim-present signal of the respective slot */ + + if (mcp2317_present) { + if (card_insert) { + /* we must enable card-presence of the active slot and disable it on all others */ + mcp23017_set_output_a(MCP23017_ADDRESS, (1 << s)); + } else { + /* we disable all card insert signals */ + mcp23017_set_output_a(MCP23017_ADDRESS, 0); + } + } else { + TRACE_WARNING("No MCP23017 present; cannot set CARD_INSERT\r\n"); + } +} diff --git a/firmware/libboard/octsimtest/source/i2c.c b/firmware/libboard/octsimtest/source/i2c.c new file mode 100644 index 0000000..8627b69 --- /dev/null +++ b/firmware/libboard/octsimtest/source/i2c.c @@ -0,0 +1,221 @@ +/* I2C EEPROM memory read and write utilities + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "board.h" +#include <stdbool.h> + +/* Low-Level I2C Routines */ + +static const Pin pin_sda = {PIO_PA30, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_OPENDRAIN }; +static const Pin pin_sda_in = {PIO_PA30, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT }; +static const Pin pin_scl = {PIO_PA31, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_OPENDRAIN }; + +static void i2c_delay() +{ + volatile int v; + int i; + + /* 100 cycles results in SCL peak length of 44us, so it's about + * 440ns per cycle here */ + for (i = 0; i < 14; i++) { + v = 0; + } +} + +void i2c_pin_init(void) +{ + PIO_Configure(&pin_scl, PIO_LISTSIZE(pin_scl)); + PIO_Configure(&pin_sda, PIO_LISTSIZE(pin_sda)); +} + +static void set_scl(void) +{ + PIO_Set(&pin_scl); + i2c_delay(); +} + +static void set_sda(void) +{ + PIO_Set(&pin_sda); + i2c_delay(); +} + +static void clear_scl(void) +{ + PIO_Clear(&pin_scl); + i2c_delay(); +} + +static void clear_sda(void) +{ + PIO_Clear(&pin_sda); + i2c_delay(); +} + +static bool read_sda(void) +{ + bool ret; + + PIO_Configure(&pin_sda_in, PIO_LISTSIZE(pin_sda_in)); + if (PIO_Get(&pin_sda_in)) + ret = true; + else + ret = false; + PIO_Configure(&pin_sda, PIO_LISTSIZE(pin_sda)); + + return ret; +} + +/* Core I2C Routines */ + +static bool i2c_started = false; + +static void i2c_start_cond(void) +{ + if (i2c_started) { + set_sda(); + set_scl(); + } + + clear_sda(); + i2c_delay(); + clear_scl(); + i2c_started = true; +} + +void i2c_stop_cond(void) +{ + clear_sda(); + set_scl(); + set_sda(); + i2c_delay(); + i2c_started = false; +} + +static void i2c_write_bit(bool bit) +{ + if (bit) + set_sda(); + else + clear_sda(); + i2c_delay(); // ? + set_scl(); + clear_scl(); +} + +static bool i2c_read_bit(void) +{ + bool bit; + + set_sda(); + set_scl(); + bit = read_sda(); + clear_scl(); + + return bit; +} + +bool i2c_write_byte(bool send_start, bool send_stop, uint8_t byte) +{ + uint8_t bit; + bool nack; + + if (send_start) + i2c_start_cond(); + + for (bit = 0; bit < 8; bit++) { + i2c_write_bit((byte & 0x80) != 0); + byte <<= 1; + } + + nack = i2c_read_bit(); + + if (send_stop) + i2c_stop_cond(); + + return nack; +} + +uint8_t i2c_read_byte(bool nack, bool send_stop) +{ + uint8_t byte = 0; + uint8_t bit; + + for (bit = 0; bit < 8; bit++) { + byte = (byte << 1) | i2c_read_bit(); + } + + i2c_write_bit(nack); + + if (send_stop) + i2c_stop_cond(); + + return byte; +} + + +/* EEPROM related code */ + +int eeprom_write_byte(uint8_t slave, uint8_t addr, uint8_t byte) +{ + bool nack; + + WDT_Restart(WDT); + + /* Write slave address */ + nack = i2c_write_byte(true, false, slave << 1); + if (nack) + goto out_stop; + nack = i2c_write_byte(false, false, addr); + if (nack) + goto out_stop; + nack = i2c_write_byte(false, true, byte); + if (nack) + goto out_stop; + /* Wait tWR time to ensure EEPROM is writing correctly (tWR = 5 ms for AT24C02) */ + mdelay(5); + +out_stop: + i2c_stop_cond(); + if (nack) + return -1; + else + return 0; +} + +int eeprom_read_byte(uint8_t slave, uint8_t addr) +{ + bool nack; + + WDT_Restart(WDT); + + /* dummy write cycle */ + nack = i2c_write_byte(true, false, slave << 1); + if (nack) + goto out_stop; + nack = i2c_write_byte(false, false, addr); + if (nack) + goto out_stop; + /* Re-start with read */ + nack = i2c_write_byte(true, false, (slave << 1) | 1); + if (nack) + goto out_stop; + + return i2c_read_byte(true, true); + +out_stop: + i2c_stop_cond(); + if (nack) + return -1; + else + return 0; +} diff --git a/firmware/libboard/octsimtest/source/mcp23017.c b/firmware/libboard/octsimtest/source/mcp23017.c new file mode 100644 index 0000000..959f2c6 --- /dev/null +++ b/firmware/libboard/octsimtest/source/mcp23017.c @@ -0,0 +1,156 @@ +#include "board.h" +#include <stdbool.h> +#include "i2c.h" +#include "mcp23017.h" + + +//defines from https://github.com/adafruit/Adafruit-MCP23017-Arduino-Library/blob/master/Adafruit_MCP23017.h under BSD license + +// registers +#define MCP23017_IODIRA 0x00 +#define MCP23017_IPOLA 0x02 +#define MCP23017_GPINTENA 0x04 +#define MCP23017_DEFVALA 0x06 +#define MCP23017_INTCONA 0x08 +#define MCP23017_IOCONA 0x0A +#define MCP23017_GPPUA 0x0C +#define MCP23017_INTFA 0x0E +#define MCP23017_INTCAPA 0x10 +#define MCP23017_GPIOA 0x12 +#define MCP23017_OLATA 0x14 + + +#define MCP23017_IODIRB 0x01 +#define MCP23017_IPOLB 0x03 +#define MCP23017_GPINTENB 0x05 +#define MCP23017_DEFVALB 0x07 +#define MCP23017_INTCONB 0x09 +#define MCP23017_IOCONB 0x0B +#define MCP23017_GPPUB 0x0D +#define MCP23017_INTFB 0x0F +#define MCP23017_INTCAPB 0x11 +#define MCP23017_GPIOB 0x13 +#define MCP23017_OLATB 0x15 + +#define MCP23017_INT_ERR 255 + + +//bool i2c_write_byte(bool send_start, bool send_stop, uint8_t byte) +//uint8_t i2c_read_byte(bool nack, bool send_stop) +//static void i2c_stop_cond(void) + +int mcp23017_write_byte(uint8_t slave, uint8_t addr, uint8_t byte) +{ + bool nack; + + WDT_Restart(WDT); + +// Write slave address + nack = i2c_write_byte(true, false, slave << 1); + if (nack) + goto out_stop; + nack = i2c_write_byte(false, false, addr); + if (nack) + goto out_stop; + nack = i2c_write_byte(false, true, byte); + if (nack) + goto out_stop; + +out_stop: + i2c_stop_cond(); + if (nack) + return -1; + else + return 0; +} + +int mcp23017_read_byte(uint8_t slave, uint8_t addr) +{ + bool nack; + + WDT_Restart(WDT); + + // dummy write cycle + nack = i2c_write_byte(true, false, slave << 1); + if (nack) + goto out_stop; + nack = i2c_write_byte(false, false, addr); + if (nack) + goto out_stop; + // Re-start with read + nack = i2c_write_byte(true, false, (slave << 1) | 1); + if (nack) + goto out_stop; + + return i2c_read_byte(true, true); + +out_stop: + i2c_stop_cond(); + if (nack) + return -1; + else + return 0; +} + +int mcp23017_init(uint8_t slave, uint8_t iodira, uint8_t iodirb) +{ + TRACE_DEBUG("mcp23017_init\n\r"); + + // all gpio input + if (mcp23017_write_byte(slave, MCP23017_IODIRA, iodira)) + goto out_err; + // msb of portb output, rest input + if (mcp23017_write_byte(slave, MCP23017_IODIRB, iodirb)) + goto out_err; + if (mcp23017_write_byte(slave, MCP23017_IOCONA, 0x20)) //disable SEQOP (autoinc addressing) + goto out_err; + + TRACE_DEBUG("mcp23017 found\n\r"); + return 0; + +out_err: + TRACE_WARNING("mcp23017 NOT found!\n\r"); + return -1; +} + +int mcp23017_test(uint8_t slave) +{ + printf("mcp23017_test\n\r"); + printf("GPIOA 0x%x\n\r", mcp23017_read_byte(slave,MCP23017_GPIOA)); + printf("GPIOB 0x%x\n\r", mcp23017_read_byte(slave,MCP23017_GPIOB)); + printf("IODIRA 0x%x\n\r", mcp23017_read_byte(slave,MCP23017_IODIRA)); + printf("IODIRB 0x%x\n\r", mcp23017_read_byte(slave,MCP23017_IODIRB)); + printf("IOCONA 0x%x\n\r", mcp23017_read_byte(slave,MCP23017_IOCONA)); + printf("IOCONB 0x%x\n\r", mcp23017_read_byte(slave,MCP23017_IOCONB)); + + return 0; +} + +int mcp23017_set_output_a(uint8_t slave, uint8_t val) +{ + return mcp23017_write_byte(slave, MCP23017_OLATA, val); +} + +int mcp23017_set_output_b(uint8_t slave, uint8_t val) +{ + return mcp23017_write_byte(slave, MCP23017_OLATB, val); +} + +int mcp23017_toggle(uint8_t slave) +{ + // example writing MSB of gpio + static bool foo=false; + if (foo) + { + printf("+\n\r"); + mcp23017_write_byte(slave, MCP23017_OLATB, 0x80); + foo=false; + } + else + { + printf("-\n\r"); + mcp23017_write_byte(slave, MCP23017_OLATB, 0x00); + foo=true; + } + return 0; +} diff --git a/firmware/libboard/octsimtest/source/mux.c b/firmware/libboard/octsimtest/source/mux.c new file mode 100644 index 0000000..d37adfb --- /dev/null +++ b/firmware/libboard/octsimtest/source/mux.c @@ -0,0 +1,109 @@ +/* sysmoOCTSIMTEST support for multiplexers + * + * (C) 2021 by Harald Welte <laforge@gnumonks.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "board.h" +#include "mux.h" +#include <stdbool.h> +#include <errno.h> + +/* 3-bit S0..S2 signal for slot selection */ +static const Pin pin_in_sel[3] = { + { PIO_PA1, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT }, + { PIO_PA2, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT }, + { PIO_PA3, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT }, +}; + +/* 3-bit S0..S2 signal for frequency divider selection */ +static const Pin pin_freq_sel[3] = { + { PIO_PA16, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT }, + { PIO_PA17, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT }, + { PIO_PA18, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT }, +}; + +/* low-active output enable for all muxes */ +static const Pin pin_oe = { PIO_PA19, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT }; + +static uint8_t g_mux_slot = 0; + +/* initialize the external 1:8 multiplexers */ +void mux_init(void) +{ + PIO_Configure(&pin_oe, PIO_LISTSIZE(pin_oe)); + PIO_Configure(pin_in_sel, PIO_LISTSIZE(pin_in_sel)); + PIO_Configure(pin_freq_sel, PIO_LISTSIZE(pin_freq_sel)); + + mux_set_slot(0); +} + +/* set the slot selection mux */ +int mux_set_slot(uint8_t s) +{ + TRACE_INFO("%s(%u)\r\n", __func__, s); + + if (s > 7) + return -EINVAL; + + /* !OE = H: disconnect input and output of muxes */ + PIO_Set(&pin_oe); + + if (s & 1) + PIO_Set(&pin_in_sel[0]); + else + PIO_Clear(&pin_in_sel[0]); + if (s & 2) + PIO_Set(&pin_in_sel[1]); + else + PIO_Clear(&pin_in_sel[1]); + if (s & 4) + PIO_Set(&pin_in_sel[2]); + else + PIO_Clear(&pin_in_sel[2]); + + /* !OE = L: (re-)enable the output of muxes */ + PIO_Clear(&pin_oe); + + g_mux_slot = s; + return s; +} + +int mux_get_slot(void) +{ + return g_mux_slot; +} + +/* set the frequency divider mux */ +void mux_set_freq(uint8_t s) +{ + TRACE_INFO("%s(%u)\r\n", __func__, s); + + /* no need for 'break before make' here, this would also affect + * the SIM card I/O signals which we don't want to disturb */ + + if (s & 1) + PIO_Set(&pin_freq_sel[0]); + else + PIO_Clear(&pin_freq_sel[0]); + if (s & 2) + PIO_Set(&pin_freq_sel[1]); + else + PIO_Clear(&pin_freq_sel[1]); + if (s & 4) + PIO_Set(&pin_freq_sel[2]); + else + PIO_Clear(&pin_freq_sel[2]); + + /* !OE = L: ensure enable the output of muxes */ + PIO_Clear(&pin_oe); +} diff --git a/firmware/libboard/octsimtest/source/sim_switch.c b/firmware/libboard/octsimtest/source/sim_switch.c new file mode 100644 index 0000000..f001360 --- /dev/null +++ b/firmware/libboard/octsimtest/source/sim_switch.c @@ -0,0 +1,33 @@ +/* Code to switch between local (physical) and remote (emulated) SIM + * + * (C) 2021 by Harald Welte <hwelte@hmw-consulting.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "board.h" +#include "trace.h" +#include "sim_switch.h" + +int sim_switch_use_physical(unsigned int nr, int physical) +{ + if (physical) { + TRACE_ERROR("%u: Use local/physical SIM - UNSUPPORTED!\r\n", nr); + } else { + TRACE_INFO("%u: Use remote/emulated SIM\r\n", nr); + } + + return 0; +} + +int sim_switch_init(void) +{ + return 1; // SIMtrace hardware has only one switchable interface +} diff --git a/firmware/libboard/owhw/include/board.h b/firmware/libboard/owhw/include/board.h index 8c0052d..1980324 100644 --- a/firmware/libboard/owhw/include/board.h +++ b/firmware/libboard/owhw/include/board.h @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #pragma once #include "board_common.h" @@ -31,6 +27,24 @@ /** desired main clock frequency (in Hz, based on BOARD_MAINOSC) */ #define BOARD_MCK 58982400 // 18.432 * 16 / 5 +/** MCU pin connected to red LED */ +#define PIO_LED_RED PIO_PA17 +/** MCU pin connected to green LED */ +#define PIO_LED_GREEN PIO_PA18 +/** red LED pin definition */ +#define PIN_LED_RED {PIO_LED_RED, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +/** green LED pin definition */ +#define PIN_LED_GREEN {PIO_LED_GREEN, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +/** LEDs pin definition */ +#define PINS_LEDS PIN_LED_RED, PIN_LED_GREEN +/** index for red LED in LEDs pin definition array */ +#define LED_NUM_RED 0 +/** index for green LED in LEDs pin definition array */ +#define LED_NUM_GREEN 1 + +/* pin connected to the SIMTRACE_BOOTLOADER signal. set high to force DFU bootloader start */ +#define PIN_BOOTLOADER {PIO_PA31, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT} + /* USIM 2 interface (USART) */ #define PIN_USIM2_CLK {PIO_PA2, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} #define PIN_USIM2_IO {PIO_PA6, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} diff --git a/firmware/libboard/owhw/product_string.txt b/firmware/libboard/owhw/product_string.txt new file mode 100644 index 0000000..77c3b1b --- /dev/null +++ b/firmware/libboard/owhw/product_string.txt @@ -0,0 +1 @@ +OWHW diff --git a/firmware/libboard/owhw/source/owhw.c b/firmware/libboard/owhw/source/owhw.c index 3bf51ec..1238082 100644 --- a/firmware/libboard/owhw/source/owhw.c +++ b/firmware/libboard/owhw/source/owhw.c @@ -1,7 +1,7 @@ /* Card simulator specific functions * * (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de> - * (C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de> + * (C) 2018-2019, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #include "chip.h" @@ -65,3 +61,16 @@ void cardsim_gpio_init(void) { PIO_Configure(pins_cardsim, ARRAY_SIZE(pins_cardsim)); } + +int board_override_enter_dfu(void) +{ + const Pin bl_pin = PIN_BOOTLOADER; + + PIO_Configure(&bl_pin, 1); + + if (PIO_Get(&bl_pin) == 0) { // signal low + return 0; // do not override enter DFU + } else { + return 1; // override enter DFU + } +} diff --git a/firmware/libboard/common/source/sim_switch.c b/firmware/libboard/owhw/source/sim_switch.c index 59513ad..0b829b6 100644 --- a/firmware/libboard/common/source/sim_switch.c +++ b/firmware/libboard/owhw/source/sim_switch.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #include "board.h" #include "trace.h" diff --git a/firmware/libboard/qmod/include/board.h b/firmware/libboard/qmod/include/board.h index a738daa..7ea5bd7 100644 --- a/firmware/libboard/qmod/include/board.h +++ b/firmware/libboard/qmod/include/board.h @@ -11,18 +11,11 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #pragma once #include "board_common.h" #include "simtrace_usb.h" -#define LED_USIM1 LED_GREEN -#define LED_USIM2 LED_RED - /** Name of the board */ #define BOARD_NAME "QMOD" /** Board definition */ @@ -32,6 +25,27 @@ #define BOARD_MAINOSC 12000000 /** desired main clock frequency (in Hz, based on BOARD_MAINOSC) */ #define BOARD_MCK 58000000 // 18.432 * 29 / 6 +/** board has external clock, not crystal */ +#define BOARD_MAINOSC_BYPASS + +/** MCU pin connected to red LED */ +#define PIO_LED_RED PIO_PA17 +/** MCU pin connected to green LED */ +#define PIO_LED_GREEN PIO_PA18 +/** red LED pin definition */ +#define PIN_LED_RED {PIO_LED_RED, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +/** green LED pin definition */ +#define PIN_LED_GREEN {PIO_LED_GREEN, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +/** LEDs pin definition */ +#define PINS_LEDS PIN_LED_RED, PIN_LED_GREEN +/** index for red LED in LEDs pin definition array */ +#define LED_NUM_RED 0 +/** index for green LED in LEDs pin definition array */ +#define LED_NUM_GREEN 1 +/** the green LED is actually red and used as indication for USIM1 */ +#define LED_USIM1 LED_GREEN +/** the green LED is actually red and used as indication for USIM2 */ +#define LED_USIM2 LED_RED /* USIM 2 interface (USART) */ #define PIN_USIM2_CLK {PIO_PA2, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} @@ -93,6 +107,9 @@ #define BOARD_USB_RELEASE 0x010 #define CARDEMU_SECOND_UART + #define DETECT_VCC_BY_ADC +#define VCC_UV_THRESH_1V8 1500000 +#define VCC_UV_THRESH_3V 2500000 #define HAVE_CARDEM diff --git a/firmware/libboard/qmod/include/card_pres.h b/firmware/libboard/qmod/include/card_pres.h index 81f0613..e06642e 100644 --- a/firmware/libboard/qmod/include/card_pres.h +++ b/firmware/libboard/qmod/include/card_pres.h @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #pragma once diff --git a/firmware/libboard/qmod/include/i2c.h b/firmware/libboard/qmod/include/i2c.h index 30f57ce..aff1ea6 100644 --- a/firmware/libboard/qmod/include/i2c.h +++ b/firmware/libboard/qmod/include/i2c.h @@ -9,10 +9,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #pragma once diff --git a/firmware/libboard/qmod/include/wwan_led.h b/firmware/libboard/qmod/include/wwan_led.h index 77887c7..a0f060a 100644 --- a/firmware/libboard/qmod/include/wwan_led.h +++ b/firmware/libboard/qmod/include/wwan_led.h @@ -9,10 +9,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #pragma once diff --git a/firmware/libboard/qmod/include/wwan_perst.h b/firmware/libboard/qmod/include/wwan_perst.h index c934afc..623184e 100644 --- a/firmware/libboard/qmod/include/wwan_perst.h +++ b/firmware/libboard/qmod/include/wwan_perst.h @@ -9,10 +9,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #pragma once diff --git a/firmware/libboard/qmod/product_string.txt b/firmware/libboard/qmod/product_string.txt new file mode 100644 index 0000000..2407b9d --- /dev/null +++ b/firmware/libboard/qmod/product_string.txt @@ -0,0 +1 @@ +sysmoQMOD (Quad Modem) diff --git a/firmware/libboard/qmod/source/board_qmod.c b/firmware/libboard/qmod/source/board_qmod.c index 4d75b98..189fb58 100644 --- a/firmware/libboard/qmod/source/board_qmod.c +++ b/firmware/libboard/qmod/source/board_qmod.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #include "board.h" #include "simtrace.h" @@ -28,6 +24,7 @@ #include "card_pres.h" #include <osmocom/core/timer.h> #include "usb_buf.h" +#include "i2c.h" static const Pin pin_hubpwr_override = PIN_PRTPWR_OVERRIDE; static const Pin pin_hub_rst = {PIO_PA13, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}; @@ -46,6 +43,7 @@ static int qmod_sam3_is_12(void) return 0; } +#if (ALLOW_PEER_ERASE > 0) const unsigned char __eeprom_bin[256] = { USB_VENDOR_OPENMOKO & 0xff, USB_VENDOR_OPENMOKO >> 8, @@ -69,7 +67,6 @@ const unsigned char __eeprom_bin[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x56, 0x23, 0x71, 0x04, 0x00, /* 0xf0 - 0xff */ }; -#include "i2c.h" static int write_hub_eeprom(void) { int i; @@ -126,7 +123,7 @@ static int erase_hub_eeprom(void) return 0; } - +#endif /* ALLOW_PEER_ERASE */ static void board_exec_dbg_cmd_st12only(int ch) { @@ -137,12 +134,14 @@ static void board_exec_dbg_cmd_st12only(int ch) return; switch (ch) { +#if (ALLOW_PEER_ERASE > 0) case 'E': write_hub_eeprom(); break; case 'e': erase_hub_eeprom(); break; +#endif /* ALLOW_PEER_ERASE */ case 'O': printf("Setting PRTPWR_OVERRIDE\n\r"); PIO_Set(&pin_hubpwr_override); @@ -151,6 +150,7 @@ static void board_exec_dbg_cmd_st12only(int ch) printf("Clearing PRTPWR_OVERRIDE\n\r"); PIO_Clear(&pin_hubpwr_override); break; +#if (ALLOW_PEER_ERASE > 0) case 'H': printf("Clearing _HUB_RESET -> HUB_RESET high (inactive)\n\r"); PIO_Clear(&pin_hub_rst); @@ -170,6 +170,7 @@ static void board_exec_dbg_cmd_st12only(int ch) printf("Writing value 0x%02lx to EEPROM offset 0x%02lx\n\r", val, addr); eeprom_write_byte(0x50, addr, val); break; +#endif /* ALLOW_PEER_ERASE */ case 'r': printf("Please enter EEPROM offset:\n\r"); UART_GetIntegerMinMax(&addr, 0, 255); @@ -189,7 +190,7 @@ void board_exec_dbg_cmd(int ch) this is done to prevent accidental ERASE on noisy serial input since only one character can trigger the ERASE. */ static bool allow_erase = false; -#endif +#endif /* ALLOW_PEER_ERASE */ switch (ch) { case '?': @@ -200,13 +201,17 @@ void board_exec_dbg_cmd(int ch) printf("\tg\tswitch off LED 2\n\r"); printf("\tG\tswitch off LED 2\n\r"); if (qmod_sam3_is_12()) { +#if (ALLOW_PEER_ERASE > 0) printf("\tE\tprogram EEPROM\n\r"); printf("\te\tErase EEPROM\n\r"); +#endif /* ALLOW_PEER_ERASE */ printf("\tO\tEnable PRTPWR_OVERRIDE\n\r"); printf("\to\tDisable PRTPWR_OVERRIDE\n\r"); +#if (ALLOW_PEER_ERASE > 0) printf("\tH\tRelease HUB RESET (high)\n\r"); printf("\th\tAssert HUB RESET (low)\n\r"); printf("\tw\tWrite single byte in EEPROM\n\r"); +#endif /* ALLOW_PEER_ERASE */ printf("\tr\tRead single byte from EEPROM\n\r"); } printf("\tX\tRelease peer SAM3 from reset\n\r"); @@ -215,10 +220,13 @@ void board_exec_dbg_cmd(int ch) printf("\tY\tRelease peer SAM3 ERASE signal\n\r"); printf("\ta\tAllow asserting peer SAM3 ERASE signal\n\r"); printf("\ty\tAssert peer SAM3 ERASE signal\n\r"); -#endif +#endif /* ALLOW_PEER_ERASE */ printf("\tU\tProceed to USB Initialization\n\r"); printf("\t1\tGenerate 1ms reset pulse on WWAN1\n\r"); printf("\t2\tGenerate 1ms reset pulse on WWAN2\n\r"); + printf("\t!\tSwitch Channel A from physical -> remote\n\r"); + printf("\t@\tSwitch Channel B from physical -> remote\n\r"); + printf("\tt\t(pseudo)talloc report\n\r"); break; case 'R': printf("Asking NVIC to reset us\n\r"); @@ -266,7 +274,7 @@ void board_exec_dbg_cmd(int ch) printf("Please first allow setting SIMTRACExx_ERASE\n\r"); } break; -#endif +#endif /* ALLOW_PEER_ERASE */ case '1': printf("Resetting Modem 1 (of this SAM3)\n\r"); wwan_perst_do_reset_pulse(0, 300); @@ -281,6 +289,9 @@ void board_exec_dbg_cmd(int ch) case '@': sim_switch_use_physical(0, 0); break; + case 't': + talloc_report(NULL, stdout); + break; default: if (!qmod_sam3_is_12()) printf("Unknown command '%c'\n\r", ch); @@ -294,7 +305,7 @@ void board_exec_dbg_cmd(int ch) if ('a' != ch) { allow_erase = false; } -#endif +#endif /* ALLOW_PEER_ERASE */ } void board_main_top(void) @@ -327,11 +338,13 @@ void board_main_top(void) TRACE_INFO("Detected Quad-Modem ST12\n\r"); } else { TRACE_INFO("Detected Quad-Modem ST34\n\r"); +#ifndef APPLICATION_dfu /* make sure we use the second set of USB Strings * calling the interfaces "Modem 3" and "Modem 4" rather * than 1+2 */ usb_strings[7] = usb_strings[9]; usb_strings[8] = usb_strings[10]; +#endif } /* Obtain the circuit board version (currently just prints voltage */ diff --git a/firmware/libboard/qmod/source/card_pres.c b/firmware/libboard/qmod/source/card_pres.c index 7a32b57..21ce1fb 100644 --- a/firmware/libboard/qmod/source/card_pres.c +++ b/firmware/libboard/qmod/source/card_pres.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #include <osmocom/core/timer.h> #include "board.h" diff --git a/firmware/libboard/qmod/source/i2c.c b/firmware/libboard/qmod/source/i2c.c index a708704..7aa3d1d 100644 --- a/firmware/libboard/qmod/source/i2c.c +++ b/firmware/libboard/qmod/source/i2c.c @@ -9,10 +9,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #include "board.h" #include <stdbool.h> diff --git a/firmware/libboard/qmod/source/sim_switch.c b/firmware/libboard/qmod/source/sim_switch.c new file mode 100644 index 0000000..0b829b6 --- /dev/null +++ b/firmware/libboard/qmod/source/sim_switch.c @@ -0,0 +1,86 @@ +/* Code to switch between local (physical) and remote (emulated) SIM + * + * (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "board.h" +#include "trace.h" +#include "led.h" +#include "sim_switch.h" + +#ifdef PIN_SIM_SWITCH1 +static const Pin pin_conn_usim1 = {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}; +#endif +#ifdef PIN_SIM_SWITCH2 +static const Pin pin_conn_usim2 = {PIO_PA28, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}; +#endif + +static int initialized = 0; + +int sim_switch_use_physical(unsigned int nr, int physical) +{ + const Pin *pin; + enum led led; + + if (!initialized) { + TRACE_ERROR("Somebody forgot to call sim_switch_init()\r\n"); + sim_switch_init(); + } + + TRACE_INFO("Modem %d: %s SIM\n\r", nr, + physical ? "physical" : "virtual"); + + switch (nr) { +#ifdef PIN_SIM_SWITCH1 + case 0: + pin = &pin_conn_usim1; + led = LED_USIM1; + break; +#endif +#ifdef PIN_SIM_SWITCH2 + case 1: + pin = &pin_conn_usim2; + led = LED_USIM2; + break; +#endif + default: + TRACE_ERROR("Invalid SIM%u\n\r", nr); + return -1; + } + + if (physical) { + TRACE_INFO("%u: Use local/physical SIM\r\n", nr); + PIO_Clear(pin); + led_blink(led, BLINK_ALWAYS_ON); + } else { + TRACE_INFO("%u: Use remote/emulated SIM\r\n", nr); + PIO_Set(pin); + led_blink(led, BLINK_ALWAYS_OFF); + } + + return 0; +} + +int sim_switch_init(void) +{ + int num_switch = 0; +#ifdef PIN_SIM_SWITCH1 + PIO_Configure(&pin_conn_usim1, 1); + num_switch++; +#endif +#ifdef PIN_SIM_SWITCH2 + PIO_Configure(&pin_conn_usim2, 1); + num_switch++; +#endif + initialized = 1; + return num_switch; +} diff --git a/firmware/libboard/qmod/source/wwan_led.c b/firmware/libboard/qmod/source/wwan_led.c index b3b5693..f055080 100644 --- a/firmware/libboard/qmod/source/wwan_led.c +++ b/firmware/libboard/qmod/source/wwan_led.c @@ -9,10 +9,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ /* Depending on the board this is running on, it might be possible * for the controller to read the status of the WWAN LED output lines of diff --git a/firmware/libboard/qmod/source/wwan_perst.c b/firmware/libboard/qmod/source/wwan_perst.c index 95a7c7b..b314781 100644 --- a/firmware/libboard/qmod/source/wwan_perst.c +++ b/firmware/libboard/qmod/source/wwan_perst.c @@ -9,10 +9,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ /* Depending on the board this is running on, it might be possible * for the controller to set the status of the PERST input line of diff --git a/firmware/libboard/sam3p256/include/board.h b/firmware/libboard/sam3p256/include/board.h index bd2ab49..ff87c99 100644 --- a/firmware/libboard/sam3p256/include/board.h +++ b/firmware/libboard/sam3p256/include/board.h @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #pragma once #include "board_common.h" @@ -30,6 +26,21 @@ /** desired main clock frequency (in Hz, based on BOARD_MAINOSC) */ #define BOARD_MCK 58000000 +/** MCU pin connected to yellow LED2 */ +#define PIO_LED_RED PIO_PA17 +/** MCU pin connected to green LED1 */ +#define PIO_LED_GREEN PIO_PA18 +/** red LED pin definition */ +#define PIN_LED_RED {PIO_LED_RED, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +/** green LED pin definition */ +#define PIN_LED_GREEN {PIO_LED_GREEN, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +/** LEDs pin definition */ +#define PINS_LEDS PIN_LED_RED, PIN_LED_GREEN +/** index for red LED in LEDs pin definition array */ +#define LED_NUM_RED 0 +/** index for green LED in LEDs pin definition array */ +#define LED_NUM_GREEN 1 + /** Pin configuration **/ /* Button to force bootloader start (shorted to ground when pressed */ #define PIN_BOOTLOADER_SW {PIO_PA20, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT} @@ -120,11 +131,6 @@ #define PIN_SPI_WP {PA15, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} #endif -/** Pin configuration to control USB pull-up on D+ - * @details the USB pull-up on D+ is enable by default on the board but can be disabled by setting PA16 high - */ -#define PIN_USB_PULLUP {PIO_PA16, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} - /** USB definitions */ /* OpenMoko SIMtrace 2 USB vendor ID */ #define BOARD_USB_VENDOR_ID USB_VENDOR_OPENMOKO diff --git a/firmware/libboard/sam3p256/source/board_sam3p256.c b/firmware/libboard/sam3p256/source/board_sam3p256.c index 4b6a451..47f8ea7 100644 --- a/firmware/libboard/sam3p256/source/board_sam3p256.c +++ b/firmware/libboard/sam3p256/source/board_sam3p256.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #include "board.h" #include "simtrace.h" diff --git a/firmware/libboard/simtrace/include/board.h b/firmware/libboard/simtrace/include/board.h index 0c1e533..7cb30b0 100644 --- a/firmware/libboard/simtrace/include/board.h +++ b/firmware/libboard/simtrace/include/board.h @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #pragma once #include "board_common.h" @@ -31,11 +27,26 @@ /** desired main clock frequency (in Hz, based on BOARD_MAINOSC) */ #define BOARD_MCK 58982400 // 18.432 * 16 / 5 +/** MCU pin connected to red LED */ +#define PIO_LED_RED PIO_PA17 +/** MCU pin connected to green LED */ +#define PIO_LED_GREEN PIO_PA18 +/** red LED pin definition */ +#define PIN_LED_RED {PIO_LED_RED, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +/** green LED pin definition */ +#define PIN_LED_GREEN {PIO_LED_GREEN, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +/** LEDs pin definition */ +#define PINS_LEDS PIN_LED_RED, PIN_LED_GREEN +/** index for red LED in LEDs pin definition array */ +#define LED_NUM_RED 0 +/** index for green LED in LEDs pin definition array */ +#define LED_NUM_GREEN 1 + /** Pin configuration **/ /* Button to force bootloader start (shorted to ground when pressed */ #define PIN_BOOTLOADER_SW {PIO_PA31, PIOA, ID_PIOA, PIO_INPUT, PIO_PULLUP} /* Enable powering the card using the second 3.3 V output of the LDO (active high) */ -#define SIM_PWEN_PIN {SIM_PWEN, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +#define SIM_PWEN_PIN {PIO_PA5, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} /* Enable powering the SIM card */ #define PWR_PINS SIM_PWEN_PIN /* Card presence pin */ @@ -59,15 +70,15 @@ /** Phone connection **/ /* Phone USIM slot 1 VCC pin (VCC_PHONE in schematic) */ -#define PIN_USIM1_VCC {PIO_PA25, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT} +#define PIN_USIM1_VCC {PIO_PA25, PIOA, ID_PIOA, PIO_INPUT, PIO_IT_EDGE | PIO_DEGLITCH } /* Phone USIM slot 1 RST pin (active low; RST_PHONE in schematic) */ -#define PIN_USIM1_nRST {PIO_PA24, PIOA, ID_PIOA, PIO_INPUT, PIO_IT_RISE_EDGE | PIO_DEGLITCH } +#define PIN_USIM1_nRST {PIO_PA24, PIOA, ID_PIOA, PIO_INPUT, PIO_IT_EDGE | PIO_DEGLITCH } /* Phone I/O data signal input/output (I/O_PHONE in schematic) */ -#define PIN_PHONE_IO {PIO_PA22A_TXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} +#define PIN_USIM1_IO {PIO_PA22A_TXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} /* Phone CLK clock input (CLK_PHONE in schematic) */ -#define PIN_PHONE_CLK {PIO_PA23A_SCK1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} +#define PIN_USIM1_CLK {PIO_PA23A_SCK1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} /* Pin used for phone USIM slot 1 communication */ -#define PINS_USIM1 PIN_PHONE_IO, PIN_PHONE_CLK, PIN_PHONE_CLK_INPUT, PIN_USIM1_VCC, PIN_PHONE_IO_INPUT, PIN_USIM1_nRST +#define PINS_USIM1 PIN_USIM1_IO, PIN_USIM1_CLK, PIN_PHONE_CLK_INPUT, PIN_USIM1_VCC, PIN_PHONE_IO_INPUT, PIN_USIM1_nRST /* Phone I/O data signal input/output (unused USART RX input; connected to I/O_PHONE in schematic) */ #define PIN_PHONE_IO_INPUT {PIO_PA21A_RXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} /* Pin used as clock input (to measure the ETU duration; connected to CLK_PHONE in schematic) */ @@ -93,9 +104,9 @@ /* Pins used to sniff phone-card communication */ #define PINS_SIM_SNIFF PIN_SIM_IO, PIN_SIM_CLK, PIN_SIM_RST_SNIFF /* Disable power converter 4.5-6V to 3.3V (active high) */ -#define PIN_SIM_PWEN_SNIFF {SIM_PWEN, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} +#define PIN_SIM_PWEN_SNIFF {PIO_PA5, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} /* Enable power switch to forward VCC_PHONE to VCC_SIM (active high) */ -#define PIN_VCC_FWD_SNIFF {VCC_FWD, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} +#define PIN_VCC_FWD_SNIFF {PIO_PA26, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} /* Use phone VCC to power card */ #define PINS_PWR_SNIFF PIN_SIM_PWEN_SNIFF, PIN_VCC_FWD_SNIFF @@ -119,11 +130,6 @@ /* SPI flash write protect pin (active low, pulled low) */ #define PIN_SPI_WP {PA15, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} -/** Pin configuration to control USB pull-up on D+ - * @details the USB pull-up on D+ is enable by default on the board but can be disabled by setting PA16 high - */ -#define PIN_USB_PULLUP {PIO_PA16, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} - /** USB definitions */ /* OpenMoko SIMtrace 2 USB vendor ID */ #define BOARD_USB_VENDOR_ID USB_VENDOR_OPENMOKO @@ -138,10 +144,14 @@ /** Supported modes */ /* SIMtrace board supports sniffer mode */ +#ifdef APPLICATION_trace #define HAVE_SNIFFER +#endif /* SIMtrace board supports CCID mode */ //#define HAVE_CCID /* SIMtrace board supports card emulation mode */ -//#define HAVE_CARDEM +#ifdef APPLICATION_cardem +#define HAVE_CARDEM +#endif /* SIMtrace board supports man-in-the-middle mode */ //#define HAVE_MITM diff --git a/firmware/libboard/simtrace/product_string.txt b/firmware/libboard/simtrace/product_string.txt new file mode 100644 index 0000000..5634f3a --- /dev/null +++ b/firmware/libboard/simtrace/product_string.txt @@ -0,0 +1 @@ +SIMtrace 2 diff --git a/firmware/libboard/simtrace/source/board_simtrace.c b/firmware/libboard/simtrace/source/board_simtrace.c index 9d323cf..d15d6b9 100644 --- a/firmware/libboard/simtrace/source/board_simtrace.c +++ b/firmware/libboard/simtrace/source/board_simtrace.c @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #include "board.h" #include "simtrace.h" diff --git a/firmware/libboard/simtrace/source/sim_switch.c b/firmware/libboard/simtrace/source/sim_switch.c new file mode 100644 index 0000000..c3a8503 --- /dev/null +++ b/firmware/libboard/simtrace/source/sim_switch.c @@ -0,0 +1,50 @@ +/* Code to switch between local (physical) and remote (emulated) SIM + * + * (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de> + * (C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "board.h" +#include "trace.h" +#include "led.h" +#include "sim_switch.h" + +int sim_switch_use_physical(unsigned int nr, int physical) +{ + const Pin pin_sc = PIN_SC_SW_DEFAULT; // pin to control bus switch for VCC/RST/CLK signals + const Pin pin_io = PIN_IO_SW_DEFAULT; // pin to control bus switch for I/O signal + + if (nr > 0) { + TRACE_ERROR("SIM interface for Modem %d can't be switched\r\n", nr); + return -1; + } + + TRACE_INFO("Modem %u: %s SIM\n\r", nr, physical ? "physical" : "virtual"); + + if (physical) { + TRACE_INFO("%u: Use local/physical SIM\r\n", nr); + PIO_Set(&pin_sc); + PIO_Set(&pin_io); + } else { + TRACE_INFO("%u: Use remote/emulated SIM\r\n", nr); + PIO_Clear(&pin_sc); + PIO_Clear(&pin_io); + } + + return 0; +} + +int sim_switch_init(void) +{ + // the bus switch is already initialised + return 1; // SIMtrace hardware has only one switchable interface +} diff --git a/firmware/libcommon/include/assert.h b/firmware/libcommon/include/assert.h index 22bb101..dc6b1b5 100644 --- a/firmware/libcommon/include/assert.h +++ b/firmware/libcommon/include/assert.h @@ -89,7 +89,7 @@ /// \param condition Condition to verify. #define ASSERT(condition) { \ if (!(condition)) { \ - printf("-F- ASSERT: %s %s:%d\n\r", #condition, __BASE_FILE__, __LINE__); \ + printf_sync("-F- ASSERT: %s %s:%d\n\r", #condition, __BASE_FILE__, __LINE__); \ while (1); \ } \ } diff --git a/firmware/libcommon/include/card_emu.h b/firmware/libcommon/include/card_emu.h index a3c1cf2..2668d73 100644 --- a/firmware/libcommon/include/card_emu.h +++ b/firmware/libcommon/include/card_emu.h @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #pragma once @@ -29,8 +25,17 @@ enum card_io { CARD_IO_CLK, }; -struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uart_chan, - uint8_t in_ep, uint8_t irq_ep); +/** initialise card slot + * @param[in] slot_num slot number (arbitrary number) + * @param[in] uart_chan UART peripheral channel + * @param[in] in_ep USB IN end point number + * @param[in] irq_ep USB INTerrupt end point number + * @param[in] vcc_active initial VCC signal state (true = on) + * @param[in] in_reset initial RST signal state (true = reset asserted) + * @param[in] clocked initial CLK signat state (true = active) + * @return main card handle reference + */ +struct card_handle *card_emu_init(uint8_t slot_num, uint8_t uart_chan, uint8_t in_ep, uint8_t irq_ep, bool vcc_active, bool in_reset, bool clocked); /* process a single byte received from the reader */ void card_emu_process_rx_byte(struct card_handle *ch, uint8_t byte); @@ -46,13 +51,26 @@ int card_emu_set_atr(struct card_handle *ch, const uint8_t *atr, uint8_t len); struct llist_head *card_emu_get_uart_tx_queue(struct card_handle *ch); void card_emu_have_new_uart_tx(struct card_handle *ch); -void card_emu_report_status(struct card_handle *ch); +void card_emu_report_status(struct card_handle *ch, bool report_on_irq); + +void card_emu_wtime_half_expired(void *ch); +void card_emu_wtime_expired(void *ch); -#define ENABLE_TX 0x01 -#define ENABLE_RX 0x02 + +#define ENABLE_TX 0x01 +#define ENABLE_RX 0x02 +#define ENABLE_TX_TIMER_ONLY 0x03 int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi); +void card_emu_uart_update_wt(uint8_t uart_chan, uint32_t wt); +void card_emu_uart_reset_wt(uint8_t uart_chan); int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte); void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx); void card_emu_uart_wait_tx_idle(uint8_t uart_chan); void card_emu_uart_interrupt(uint8_t uart_chan); + +int card_emu_get_vcc(uint8_t uart_chan); + +struct cardemu_usb_msg_config; +int card_emu_set_config(struct card_handle *ch, const struct cardemu_usb_msg_config *scfg, + unsigned int scfg_len); diff --git a/firmware/libcommon/include/cciddriver.h b/firmware/libcommon/include/cciddriver.h index f9be027..df77fa3 100644 --- a/firmware/libcommon/include/cciddriver.h +++ b/firmware/libcommon/include/cciddriver.h @@ -175,11 +175,11 @@ typedef struct { /// Number of seconds. If 00h then CCID default value is used. unsigned char bTimeOut; - /// Several parameters for the PIN format options (defined in § 6.1.11.4) + /// Several parameters for the PIN format options (defined in § 6.1.11.4) unsigned char bmFormatString4; /// Define the length of the PIN to present in the APDU command unsigned char bmPINBlockString; - /// Allows the length PIN insertion in the APDU command (defined in § 6.1.11.6) + /// Allows the length PIN insertion in the APDU command (defined in § 6.1.11.6) unsigned char bmPinLengthFormat; /// Insertion position offset in byte for the current PIN unsigned char bInsertionOffsetOld; @@ -218,13 +218,13 @@ typedef struct /// Protocol Data Structure for Protocol T=0 (bProtocolNum=0, dwLength=00000005h) typedef struct { - /// B7-4 – FI – Index into the table 7 in ISO/IEC 7816-3:1997 selecting a + /// B7-4 - FI - Index into the table 7 in ISO/IEC 7816-3:1997 selecting a /// clock rate conversion factor - /// B3-0 – DI - Index into the table 8 in ISO/IEC 7816-3:1997 selecting a + /// B3-0 - DI - Index into the table 8 in ISO/IEC 7816-3:1997 selecting a /// baud rate conversion factor unsigned char bmFindexDindex; - /// For T=0 ,B0 – 0b, B7-2 – 000000b - /// B1 – Convention used (b1=0 for direct, b1=1 for inverse) + /// For T=0 ,B0 - 0b, B7-2 - 000000b + /// B1 - Convention used (b1=0 for direct, b1=1 for inverse) unsigned char bmTCCKST0; // 0 to 2 /// Extra Guardtime between two characters. Add 0 to 254 etu to the normal /// guardtime of 12etu. FFh is the same as 00h. @@ -243,14 +243,14 @@ typedef struct /// Protocol Data Structure for Protocol T=1 (bProtocolNum=1, dwLength=00000007h) typedef struct { - /// B7-4 – FI – Index into the table 7 in ISO/IEC 7816-3:1997 selecting a + /// B7-4 - FI - Index into the table 7 in ISO/IEC 7816-3:1997 selecting a /// clock rate conversion factor - /// B3-0 – DI - Index into the table 8 in ISO/IEC 7816-3:1997 selecting a + /// B3-0 - DI - Index into the table 8 in ISO/IEC 7816-3:1997 selecting a /// baud rate conversion factor unsigned char bmFindexDindex; - /// For T=1, B7-2 – 000100b - /// B0 – Checksum type (b0=0 for LRC, b0=1 for CRC - /// B1 – Convention used (b1=0 for direct, b1=1 for inverse) + /// For T=1, B7-2 - 000100b + /// B0 - Checksum type (b0=0 for LRC, b0=1 for CRC + /// B1 - Convention used (b1=0 for direct, b1=1 for inverse) unsigned char bmTCCKST1; // 10h, 11h, 12h, 13h /// Extra Guardtime (0 to 254 etu between two characters). /// If value is FFh, then guardtime is reduced by 1. @@ -292,8 +292,8 @@ typedef struct /// - 04h 1.8V /// Other bits are RFU. unsigned char bVoltageSupport; - /// RRRR –Upper Word- is RFU = 0000h - /// PPPP –Lower Word- Encodes the supported protocol types. A ‘1’ in a given + /// RRRR -Upper Word- is RFU = 0000h + /// PPPP -Lower Word- Encodes the supported protocol types. A "1" in a given /// bit position indicates support for the associated ISO protocol. /// 0001h = Protocol T=0 /// 0002h = Protocol T=1 @@ -318,7 +318,7 @@ typedef struct /// Indicates the maximum IFSD supported by CCID for protocol T=1. unsigned long dwMaxIFSD; /// - RRRR-Upper Word- is RFU = 0000h - /// - PPPP-Lower Word- encodes the supported protocol types. A ‘1’ in a given + /// - PPPP-Lower Word- encodes the supported protocol types. A "1" in a given /// bit position indicates support for the associated protocol. /// 0001h indicates support for the 2-wire protocol 1 /// 0002h indicates support for the 3-wire protocol 1 diff --git a/firmware/libcommon/include/iso7816_fidi.h b/firmware/libcommon/include/iso7816_fidi.h index c56478b..823e7ab 100644 --- a/firmware/libcommon/include/iso7816_fidi.h +++ b/firmware/libcommon/include/iso7816_fidi.h @@ -11,20 +11,16 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #pragma once #include <stdint.h> /* Table 7 of ISO 7816-3:2006 */ -extern const uint16_t fi_table[]; +extern const uint16_t iso7816_3_fi_table[16]; /* Table 8 from ISO 7816-3:2006 */ -extern const uint8_t di_table[]; +extern const uint8_t iso7816_3_di_table[16]; -/* compute the F/D ratio based on Fi and Di values */ -int compute_fidi_ratio(uint8_t fi, uint8_t di); +/* compute the F/D ratio based on F_index and D_index values */ +int iso7816_3_compute_fd_ratio(uint8_t f_index, uint8_t d_index); diff --git a/firmware/libcommon/include/llist_irqsafe.h b/firmware/libcommon/include/llist_irqsafe.h index 9171ccf..8aafcfb 100644 --- a/firmware/libcommon/include/llist_irqsafe.h +++ b/firmware/libcommon/include/llist_irqsafe.h @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #pragma once diff --git a/firmware/libcommon/include/main_common.h b/firmware/libcommon/include/main_common.h new file mode 100644 index 0000000..ce19f81 --- /dev/null +++ b/firmware/libcommon/include/main_common.h @@ -0,0 +1,3 @@ +#pragma once + +void print_banner(void); diff --git a/firmware/libcommon/include/ringbuffer.h b/firmware/libcommon/include/ringbuffer.h index a6eddc9..99fe96b 100644 --- a/firmware/libcommon/include/ringbuffer.h +++ b/firmware/libcommon/include/ringbuffer.h @@ -9,10 +9,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #ifndef SIMTRACE_RINGBUF_H #define SIMTRACE_RINGBUF_H @@ -21,7 +17,7 @@ #include <stdbool.h> #include <sys/types.h> -#define RING_BUFLEN 512 +#define RING_BUFLEN 1024 typedef struct ringbuf { uint8_t buf[RING_BUFLEN]; @@ -36,4 +32,22 @@ int rbuf_write(volatile ringbuf * rb, uint8_t item); bool rbuf_is_empty(volatile ringbuf * rb); bool rbuf_is_full(volatile ringbuf * rb); + +/* same as above but with 16bit values instead of 8bit */ + +#define RING16_BUFLEN 512 + +typedef struct ringbuf16 { + uint16_t buf[RING16_BUFLEN]; + size_t ird; + size_t iwr; +} ringbuf16; + +void rbuf16_reset(volatile ringbuf16 * rb); +uint16_t rbuf16_read(volatile ringbuf16 * rb); +uint16_t rbuf16_peek(volatile ringbuf16 * rb); +int rbuf16_write(volatile ringbuf16 * rb, uint16_t item); +bool rbuf16_is_empty(volatile ringbuf16 * rb); +bool rbuf16_is_full(volatile ringbuf16 * rb); + #endif /* end of include guard: SIMTRACE_RINGBUF_H */ diff --git a/firmware/libcommon/include/simtrace.h b/firmware/libcommon/include/simtrace.h index 0486581..a37ec4f 100644 --- a/firmware/libcommon/include/simtrace.h +++ b/firmware/libcommon/include/simtrace.h @@ -1,6 +1,7 @@ /* SIMtrace 2 mode definitions * - * (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de> + * Copyright (c) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de> + * Copyright (c) 2018-2019, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -11,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #ifndef SIMTRACE_H #define SIMTRACE_H @@ -57,6 +54,7 @@ enum confNum { #ifdef HAVE_MITM CFG_NUM_MITM, #endif + CFG_NUM_VERSION, NUM_CONF }; diff --git a/firmware/libcommon/include/simtrace_prot.h b/firmware/libcommon/include/simtrace_prot.h index 878bc34..d1eb89b 100644 --- a/firmware/libcommon/include/simtrace_prot.h +++ b/firmware/libcommon/include/simtrace_prot.h @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #pragma once @@ -62,6 +58,8 @@ enum simtrace_msg_type_cardem { SIMTRACE_MSGT_DO_CEMU_RX_DATA, /* Indicate PTS request from phone */ SIMTRACE_MSGT_DO_CEMU_PTS, + /* Set configurable parameters */ + SIMTRACE_MSGT_BD_CEMU_CONFIG, }; /* SIMTRACE_MSGC_MODEM */ @@ -228,11 +226,17 @@ struct cardemu_usb_msg_status { uint32_t flags; /* phone-applied target voltage in mV */ uint16_t voltage_mv; - /* Fi/Di related information */ - uint8_t fi; - uint8_t di; - uint8_t wi; - uint32_t waiting_time; + /* F/D related information. Not actual Fn/Dn values but indexes into tables! */ + union { + uint8_t F_index; /* <! Index to ISO7816-3 Table 7 (F and f_max values) */ + uint8_t fi; /* <! old, wrong name for API compatibility */ + }; + union { + uint8_t D_index; /* <! Index to ISO7816-3 Table 8 (D value) */ + uint8_t di; /* <! old, wrong name for API compatibility */ + }; + uint8_t wi; /* <! Waiting Integer as defined in ISO7816-3 Section 10.2 */ + uint32_t waiting_time; /* <! Waiting Time in etu as defined in ISO7816-3 Section 8.1 */ } __attribute__ ((packed)); /* CEMU_USB_MSGT_DO_PTS */ @@ -254,6 +258,17 @@ struct cardemu_usb_msg_error { uint8_t msg[0]; } __attribute__ ((packed)); +/* enable/disable the generation of DO_STATUS on IRQ endpoint */ +#define CEMU_FEAT_F_STATUS_IRQ 0x00000001 + +/* SIMTRACE_MSGT_BD_CEMU_CONFIG */ +struct cardemu_usb_msg_config { + /* bit-mask of CEMU_FEAT_F flags */ + uint32_t features; + /* the selected slot number (if an external mux is present) */ + uint8_t slot_mux_nr; +} __attribute__ ((packed)); + /*********************************************************************** * MODEM CONTROL ***********************************************************************/ @@ -298,6 +313,9 @@ struct st_modem_status { #define SNIFF_DATA_FLAG_ERROR_INCOMPLETE (1<<5) #define SNIFF_DATA_FLAG_ERROR_MALFORMED (1<<6) #define SNIFF_DATA_FLAG_ERROR_CHECKSUM (1<<7) +#define SNIFF_DATA_FLAG_ERROR_OVERRUN (1<<8) +#define SNIFF_DATA_FLAG_ERROR_FRAMING (1<<9) +#define SNIFF_DATA_FLAG_ERROR_PARITY (1<<10) /* SIMTRACE_MSGT_SNIFF_CHANGE */ struct sniff_change { diff --git a/firmware/libcommon/include/simtrace_usb.h b/firmware/libcommon/include/simtrace_usb.h index c0da9c5..1473762 100644 --- a/firmware/libcommon/include/simtrace_usb.h +++ b/firmware/libcommon/include/simtrace_usb.h @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ /* SIMtrace USB IDs */ #define USB_VENDOR_OPENMOKO 0x1d50 @@ -25,6 +21,8 @@ #define USB_PRODUCT_QMOD_SAM3 0x4004 #define USB_PRODUCT_SIMTRACE2_DFU 0x60e3 /* was 0x60e2 */ #define USB_PRODUCT_SIMTRACE2 0x60e3 +#define USB_PRODUCT_OCTSIMTEST 0x616d +#define USB_PRODUCT_NGFF_CARDEM 0x616e /* USB proprietary class */ #define USB_CLASS_PROPRIETARY 0xff @@ -64,4 +62,4 @@ #define SIMTRACE_CARDEM_USB_EP_USIM2_INT 3 /*! Maximum number of endpoints */ -#define BOARD_USB_NUMENDPOINTS 6 +#define BOARD_USB_NUMENDPOINTS 7 /* 0 (control) + 2 (interfaces) * 3 (endpoints) */ diff --git a/firmware/libcommon/include/talloc.h b/firmware/libcommon/include/talloc.h index 0bd75d2..1e95603 100644 --- a/firmware/libcommon/include/talloc.h +++ b/firmware/libcommon/include/talloc.h @@ -9,14 +9,11 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #pragma once #include <stdlib.h> +#include <stdio.h> #include <stdarg.h> /* minimalistic emulation of core talloc API functions used by msgb.c */ @@ -39,3 +36,4 @@ void *talloc_named_const(const void *context, size_t size, const char *name); void talloc_set_name_const(const void *ptr, const char *name); char *talloc_strdup(const void *t, const char *p); void *talloc_pool(const void *context, size_t size); +void talloc_report(const void *ptr, FILE *f); diff --git a/firmware/libcommon/include/usb_buf.h b/firmware/libcommon/include/usb_buf.h index bd6947b..39198f3 100644 --- a/firmware/libcommon/include/usb_buf.h +++ b/firmware/libcommon/include/usb_buf.h @@ -9,10 +9,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #pragma once @@ -29,6 +25,8 @@ struct usb_buffered_ep { volatile uint32_t in_progress; /* Tx queue (IN) / Rx queue (OUT) */ struct llist_head queue; + /* current length of queue */ + unsigned int queue_len; }; struct msgb *usb_buf_alloc(uint8_t ep); diff --git a/firmware/libcommon/include/utils.h b/firmware/libcommon/include/utils.h index 2c966f9..234d278 100644 --- a/firmware/libcommon/include/utils.h +++ b/firmware/libcommon/include/utils.h @@ -9,10 +9,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #pragma once diff --git a/firmware/libcommon/source/card_emu.c b/firmware/libcommon/source/card_emu.c index b7d0e1f..e6907e6 100644 --- a/firmware/libcommon/source/card_emu.c +++ b/firmware/libcommon/source/card_emu.c @@ -1,6 +1,6 @@ /* ISO7816-3 state machine for the card side * - * (C) 2010-2017 by Harald Welte <laforge@gnumonks.org> + * (C) 2010-2021 by Harald Welte <laforge@gnumonks.org> * (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de> * * This program is free software; you can redistribute it and/or modify @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #include <stdio.h> #include <assert.h> @@ -27,16 +23,21 @@ #include "utils.h" #include "trace.h" #include "iso7816_fidi.h" -#include "tc_etu.h" #include "card_emu.h" #include "simtrace_prot.h" #include "usb_buf.h" #include <osmocom/core/linuxlist.h> #include <osmocom/core/msgb.h> +#ifdef HAVE_SLOT_MUX +#include "mux.h" +#endif #define NUM_SLOTS 2 +/* bit-mask of supported CEMU_FEAT_F_ flags */ +#define SUPPORTED_FEATURES (CEMU_FEAT_F_STATUS_IRQ) + #define ISO7816_3_INIT_WTIME 9600 #define ISO7816_3_DEFAULT_WI 10 #define ISO7816_3_ATR_LEN_MAX (1+32) /* TS plus 32 chars */ @@ -55,42 +56,15 @@ enum iso7816_3_card_state { }; const struct value_string iso7816_3_card_state_names[] = { - { - .value = ISO_S_WAIT_POWER, - .str = "WAIT_POWER", - }, - { - .value = ISO_S_WAIT_CLK, - .str = "WAIT_CLK", - }, - { - .value = ISO_S_WAIT_RST, - .str = "WAIT_RST", - }, - { - .value = ISO_S_WAIT_ATR, - .str = "WAIT_ATR", - }, - { - .value = ISO_S_IN_ATR, - .str = "IN_ATR", - }, - { - .value = ISO_S_IN_PTS, - .str = "IN_PTS", - }, - { - .value = ISO_S_WAIT_TPDU, - .str = "WAIT_TPDU", - }, - { - .value = ISO_S_IN_TPDU, - .str = "IN_TPDU", - }, - { - .value = 0, - .str = NULL, - }, + { ISO_S_WAIT_POWER, "WAIT_POWER" }, + { ISO_S_WAIT_CLK, "WAIT_CLK" }, + { ISO_S_WAIT_RST, "WAIT_RST" }, + { ISO_S_WAIT_ATR, "WAIT_ATR" }, + { ISO_S_IN_ATR, "IN_ATR" }, + { ISO_S_IN_PTS, "IN_PTS" }, + { ISO_S_WAIT_TPDU, "WAIT_TPDU" }, + { ISO_S_IN_TPDU, "IN_TPDU" }, + { 0, NULL } }; @@ -110,6 +84,22 @@ enum pts_state { PTS_S_WAIT_RESP_PCK = PTS_S_WAIT_REQ_PCK | 0x10, }; +const struct value_string pts_state_names[] = { + { PTS_S_WAIT_REQ_PTSS, "WAIT_REQ_PTSS" }, + { PTS_S_WAIT_REQ_PTS0, "WAIT_REQ_PTS0" }, + { PTS_S_WAIT_REQ_PTS1, "WAIT_REQ_PTS1" }, + { PTS_S_WAIT_REQ_PTS2, "WAIT_REQ_PTS2" }, + { PTS_S_WAIT_REQ_PTS3, "WAIT_REQ_PTS3" }, + { PTS_S_WAIT_REQ_PCK, "WAIT_REQ_PCK" }, + { PTS_S_WAIT_RESP_PTSS, "WAIT_RESP_PTSS" }, + { PTS_S_WAIT_RESP_PTS0, "WAIT_RESP_PTS0" }, + { PTS_S_WAIT_RESP_PTS1, "WAIT_RESP_PTS1" }, + { PTS_S_WAIT_RESP_PTS2, "WAIT_RESP_PTS2" }, + { PTS_S_WAIT_RESP_PTS3, "WAIT_RESP_PTS3" }, + { PTS_S_WAIT_RESP_PCK, "WAIT_RESP_PCK" }, + { 0, NULL } +}; + /* PTS field byte index */ #define _PTSS 0 #define _PTS0 1 @@ -131,42 +121,15 @@ enum tpdu_state { }; const struct value_string tpdu_state_names[] = { - { - .value = TPDU_S_WAIT_CLA, - .str = "WAIT_CLA", - }, - { - .value = TPDU_S_WAIT_INS, - .str = "WAIT_INS", - }, - { - .value = TPDU_S_WAIT_P1, - .str = "WAIT_P1", - }, - { - .value = TPDU_S_WAIT_P2, - .str = "WAIT_P2", - }, - { - .value = TPDU_S_WAIT_P3, - .str = "WAIT_P3", - }, - { - .value = TPDU_S_WAIT_PB, - .str = "WAIT_PB", - }, - { - .value = TPDU_S_WAIT_RX, - .str = "WAIT_RX", - }, - { - .value = TPDU_S_WAIT_TX, - .str = "WAIT_TX", - }, - { - .value = 0, - .str = NULL, - }, + { TPDU_S_WAIT_CLA, "WAIT_CLA" }, + { TPDU_S_WAIT_INS, "WAIT_INS" }, + { TPDU_S_WAIT_P1, "WAIT_P1" }, + { TPDU_S_WAIT_P2, "WAIT_P2" }, + { TPDU_S_WAIT_P3, "WAIT_P3" }, + { TPDU_S_WAIT_PB, "WAIT_PB" }, + { TPDU_S_WAIT_RX, "WAIT_RX" }, + { TPDU_S_WAIT_TX, "WAIT_TX" }, + { 0, NULL } }; /* TPDU field byte index */ @@ -179,26 +142,44 @@ const struct value_string tpdu_state_names[] = { struct card_handle { unsigned int num; + /* bit-mask of enabled optional features (CEMU_FEAT_F_*) */ + uint32_t features; + enum iso7816_3_card_state state; /* signal levels */ - uint8_t vcc_active; /* 1 = on, 0 = off */ - uint8_t in_reset; /* 1 = RST low, 0 = RST high */ - uint8_t clocked; /* 1 = active, 0 = inactive */ - - /* timing parameters, from PTS */ - uint8_t fi; - uint8_t di; + bool vcc_active; /*< if VCC is active (true = active/ON) */ + bool in_reset; /*< if card is in reset (true = RST low/asserted, false = RST high/ released) */ + bool clocked; /*< if clock is active ( true = active, false = inactive) */ + + /* All below variables with _index suffix are indexes from 0..15 into Tables 7 + 8 + * of ISO7816-3. */ + + /*! Index to clock rate conversion integer Fi (ISO7816-3 Table 7). + * \note this represents the maximum value supported by the card, and can be indicated in TA1 */ + uint8_t Fi_index; + /*! Current value of index to clock rate conversion integer F (ISO 7816-3 Section 7.1). */ + uint8_t F_index; + + /*! Index to baud rate adjustment factor Di (ISO7816-3 Table 8). + * \note this represents the maximum value supported by the card, and can be indicated in TA1 */ + uint8_t Di_index; + /*! Current value of index to baud rate adjustment factor D (ISO 7816-3 Section 7.1). */ + uint8_t D_index; + + /*! Waiting Integer (ISO7816-3 Section 10.2). + * \note this value can be set in TA2 */ uint8_t wi; - uint8_t tc_chan; /* TC channel number */ + /*! Waiting Time, in ETU (ISO7816-3 Section 8.1). + * \note this depends on Fi, Di, and WI if T=0 is used */ + uint32_t waiting_time; /* in etu */ + uint8_t uart_chan; /* UART channel */ uint8_t in_ep; /* USB IN EP */ uint8_t irq_ep; /* USB IN EP */ - uint32_t waiting_time; /* in clocks */ - /* ATR state machine */ struct { uint8_t idx; @@ -233,6 +214,27 @@ struct card_handle { } stats; }; +/* reset all the 'dynamic' state of the card handle to the initial/default values */ +static void card_handle_reset(struct card_handle *ch) +{ + struct msgb *msg; + + card_emu_uart_update_wt(ch->uart_chan, 0); + + /* release any buffers we may still own */ + if (ch->uart_tx_msg) { + usb_buf_free(ch->uart_tx_msg); + ch->uart_tx_msg = NULL; + } + if (ch->uart_rx_msg) { + usb_buf_free(ch->uart_rx_msg); + ch->uart_rx_msg = NULL; + } + while ((msg = msgb_dequeue(&ch->uart_tx_queue))) { + usb_buf_free(msg); + } +} + struct llist_head *card_emu_get_uart_tx_queue(struct card_handle *ch) { return &ch->uart_tx_queue; @@ -254,12 +256,35 @@ void usb_buf_upd_len_and_submit(struct msgb *msg) /* Allocate USB buffer and push + initialize simtrace_msg_hdr */ struct msgb *usb_buf_alloc_st(uint8_t ep, uint8_t msg_class, uint8_t msg_type) { - struct msgb *msg; + struct msgb *msg = NULL; struct simtrace_msg_hdr *sh; - msg = usb_buf_alloc(ep); - if (!msg) - return NULL; + while (!msg) { + msg = usb_buf_alloc(ep); // try to allocate some memory + if (!msg) { // allocation failed, we might be out of memory + struct usb_buffered_ep *bep = usb_get_buf_ep(ep); + if (!bep) { + TRACE_ERROR("ep %u: %s queue does not exist\n\r", + ep, __func__); + return NULL; + } + if (llist_empty(&bep->queue)) { + TRACE_ERROR("ep %u: %s EOMEM (queue already empty)\n\r", + ep, __func__); + return NULL; + } + msg = msgb_dequeue_count(&bep->queue, &bep->queue_len); + if (!msg) { + TRACE_ERROR("ep %u: %s no msg in non-empty queue\n\r", + ep, __func__); + return NULL; + } + usb_buf_free(msg); + msg = NULL; + TRACE_DEBUG("ep %u: %s queue msg dropped\n\r", + ep, __func__); + } + } msg->l1h = msgb_put(msg, sizeof(*sh)); sh = (struct simtrace_msg_hdr *) msg->l1h; @@ -349,16 +374,14 @@ static void emu_update_fidi(struct card_handle *ch) { int rc; - rc = compute_fidi_ratio(ch->fi, ch->di); + rc = iso7816_3_compute_fd_ratio(ch->F_index, ch->D_index); if (rc > 0 && rc < 0x400) { - TRACE_INFO("%u: computed Fi(%u) Di(%u) ratio: %d\r\n", - ch->num, ch->fi, ch->di, rc); + TRACE_INFO("%u: computed F(%u)/D(%u) ratio: %d\r\n", ch->num, + ch->F_index, ch->D_index, rc); /* make sure UART uses new F/D ratio */ card_emu_uart_update_fidi(ch->uart_chan, rc); - /* notify ETU timer about this */ - tc_etu_set_etu(ch->tc_chan, rc); } else - TRACE_INFO("%u: computed FiDi ration %d unsupported\r\n", + TRACE_INFO("%u: computed F/D ratio %d unsupported\r\n", ch->num, rc); } @@ -380,19 +403,23 @@ static void card_set_state(struct card_handle *ch, case ISO_S_WAIT_RST: /* disable Rx and Tx of UART */ card_emu_uart_enable(ch->uart_chan, 0); + /* disable timeout */ + card_emu_uart_update_wt(ch->uart_chan, 0); break; case ISO_S_WAIT_ATR: /* Reset to initial Fi / Di ratio */ - ch->fi = 1; - ch->di = 1; + ch->Fi_index = ch->F_index = 1; + ch->Di_index = ch->D_index = 1; + ch->wi = ISO7816_3_DEFAULT_WI; + ch->waiting_time = ISO7816_3_INIT_WTIME; emu_update_fidi(ch); + /* enable TX to be able to use the timeout */ + card_emu_uart_enable(ch->uart_chan, ENABLE_TX_TIMER_ONLY); /* the ATR should only be sent 400 to 40k clock cycles after the RESET. - * we use the tc_etu mechanism to wait this time. + * we use the UART timeout mechanism to wait this time. * since the initial ETU is Fd=372/Dd=1 clock cycles long, we have to wait 2-107 ETU. */ - tc_etu_set_wtime(ch->tc_chan, 2); - /* ensure the TC_ETU timer is enabled */ - tc_etu_enable(ch->tc_chan); + card_emu_uart_update_wt(ch->uart_chan, 2); break; case ISO_S_IN_ATR: /* initialize to default WI, this will be overwritten if we @@ -402,7 +429,7 @@ static void card_set_state(struct card_handle *ch, /* update waiting time to initial waiting time */ ch->waiting_time = ISO7816_3_INIT_WTIME; /* set initial waiting time */ - tc_etu_set_wtime(ch->tc_chan, ch->waiting_time); + card_emu_uart_update_wt(ch->uart_chan, ch->waiting_time); /* Set ATR sub-state to initial state */ ch->atr.idx = 0; /* enable USART transmission to reader */ @@ -477,11 +504,11 @@ static int tx_byte_atr(struct card_handle *ch) } } } - /* update waiting time (see ISO 7816-3 10.2) */ - ch->waiting_time = ch->wi * 960 * ch->fi; - tc_etu_set_wtime(ch->tc_chan, ch->waiting_time); - /* reset PTS to initial state */ - set_pts_state(ch, PTS_S_WAIT_REQ_PTSS); + /* update waiting time (see ISO 7816-3 10.2). We can drop the Fi + * multiplier as we store the waiting time in units of 'etu', and + * don't really care what the number of clock cycles or the absolute + * wall clock time is */ + ch->waiting_time = ch->wi * 960; /* go to next state */ card_set_state(ch, ISO_S_WAIT_TPDU); return 0; @@ -498,8 +525,9 @@ static int tx_byte_atr(struct card_handle *ch) /* Update the PTS sub-state */ static void set_pts_state(struct card_handle *ch, enum pts_state new_ptss) { - TRACE_DEBUG("%u: 7816 PTS state %u -> %u\r\n", - ch->num, ch->pts.state, new_ptss); + TRACE_DEBUG("%u: 7816 PTS state %s -> %s\r\n", ch->num, + get_value_string(pts_state_names, ch->pts.state), + get_value_string(pts_state_names, new_ptss)); ch->pts.state = new_ptss; } @@ -579,8 +607,8 @@ process_byte_pts(struct card_handle *ch, uint8_t byte) memcpy(ch->pts.resp, ch->pts.req, sizeof(ch->pts.resp)); break; default: - TRACE_ERROR("%u: process_byte_pts() in invalid state %u\r\n", - ch->num, ch->pts.state); + TRACE_ERROR("%u: process_byte_pts() in invalid PTS state %s\r\n", ch->num, + get_value_string(pts_state_names, ch->pts.state)); break; } /* calculate the next state and set it */ @@ -615,10 +643,11 @@ static int tx_byte_pts(struct card_handle *ch) case PTS_S_WAIT_RESP_PTS1: byte = ch->pts.resp[_PTS1]; /* This must be TA1 */ - ch->fi = byte >> 4; - ch->di = byte & 0xf; - TRACE_DEBUG("%u: found Fi=%u Di=%u\r\n", ch->num, - ch->fi, ch->di); + ch->F_index = byte >> 4; + ch->D_index = byte & 0xf; + TRACE_DEBUG("%u: found F=%u D=%u\r\n", ch->num, + iso7816_3_fi_table[ch->F_index], iso7816_3_di_table[ch->D_index]); + /* FIXME: if F or D are 0, become unresponsive to signal error condition */ break; case PTS_S_WAIT_RESP_PTS2: byte = ch->pts.resp[_PTS2]; @@ -630,8 +659,8 @@ static int tx_byte_pts(struct card_handle *ch) byte = ch->pts.resp[_PCK]; break; default: - TRACE_ERROR("%u: get_byte_pts() in invalid state %u\r\n", - ch->num, ch->pts.state); + TRACE_ERROR("%u: get_byte_pts() in invalid PTS state %s\r\n", ch->num, + get_value_string(pts_state_names, ch->pts.state)); return 0; } @@ -643,7 +672,7 @@ static int tx_byte_pts(struct card_handle *ch) switch (ch->pts.state) { case PTS_S_WAIT_RESP_PCK: card_emu_uart_wait_tx_idle(ch->uart_chan); - /* update baud rate generator with Fi/Di */ + /* update baud rate generator with F/D */ emu_update_fidi(ch); /* Wait for the next TPDU */ card_set_state(ch, ISO_S_WAIT_TPDU); @@ -723,14 +752,37 @@ static void set_tpdu_state(struct card_handle *ch, enum tpdu_state new_ts) switch (new_ts) { case TPDU_S_WAIT_CLA: + /* switch back to receiving mode */ + card_emu_uart_enable(ch->uart_chan, ENABLE_RX); + /* disable waiting time since we don't expect any data */ + card_emu_uart_update_wt(ch->uart_chan, 0); + break; + case TPDU_S_WAIT_INS: + /* start waiting for the rest of the header/body */ + card_emu_uart_update_wt(ch->uart_chan, ch->waiting_time); + break; case TPDU_S_WAIT_RX: + /* switch to receive mode to receive the body */ card_emu_uart_enable(ch->uart_chan, ENABLE_RX); + /* start waiting for the body */ + card_emu_uart_update_wt(ch->uart_chan, ch->waiting_time); break; case TPDU_S_WAIT_PB: /* we just completed the TPDU header from reader to card * and now need to disable the receiver, enable the * transmitter and transmit the procedure byte */ card_emu_uart_enable(ch->uart_chan, ENABLE_TX); + /* prepare to extend the waiting time once half of it is reached */ + card_emu_uart_update_wt(ch->uart_chan, ch->waiting_time); + break; + case TPDU_S_WAIT_TX: + /* If we came from WAIT_RX, disable the receiver and + * enable the transmitter. If we came from WAIT_RX or + * WAIT_PB, reset the waiting time so that we can extend + * waiting time if needed. */ + card_emu_uart_enable(ch->uart_chan, ENABLE_TX); + /* prepare to extend the waiting time once half of it is reached */ + card_emu_uart_update_wt(ch->uart_chan, ch->waiting_time); break; default: break; @@ -837,8 +889,8 @@ process_byte_tpdu(struct card_handle *ch, uint8_t byte) add_tpdu_byte(ch, byte); break; default: - TRACE_ERROR("%u: process_byte_tpdu() in invalid state %u\r\n", - ch->num, ch->tpdu.state); + TRACE_ERROR("%u: process_byte_tpdu() in invalid TPDU state %s\r\n", ch->num, + get_value_string(tpdu_state_names, ch->tpdu.state)); } /* ensure we stay in TPDU ISO state */ @@ -875,6 +927,7 @@ static int tx_byte_tpdu(struct card_handle *ch) byte = msgb_pull_u8(msg); card_emu_uart_tx(ch->uart_chan, byte); + card_emu_uart_reset_wt(ch->uart_chan); /* this must happen _after_ the byte has been transmitted */ switch (ch->tpdu.state) { @@ -925,6 +978,8 @@ void card_emu_process_rx_byte(struct card_handle *ch, uint8_t byte) switch (ch->state) { case ISO_S_WAIT_TPDU: if (byte == 0xff) { + /* reset PTS to initial state */ + set_pts_state(ch, PTS_S_WAIT_REQ_PTSS); new_state = process_byte_pts(ch, byte); ch->stats.pps++; goto out_silent; @@ -937,8 +992,8 @@ void card_emu_process_rx_byte(struct card_handle *ch, uint8_t byte) new_state = process_byte_pts(ch, byte); goto out_silent; default: - TRACE_ERROR("%u: Received UART char in invalid 7816 state " - "%u\r\n", ch->num, ch->state); + TRACE_ERROR("%u: Received UART char in invalid 7816 state %s\r\n", ch->num, + get_value_string(iso7816_3_card_state_names, ch->state)); break; } @@ -991,13 +1046,16 @@ void card_emu_have_new_uart_tx(struct card_handle *ch) } } -void card_emu_report_status(struct card_handle *ch) +void card_emu_report_status(struct card_handle *ch, bool report_on_irq) { struct msgb *msg; struct cardemu_usb_msg_status *sts; + uint8_t ep = ch->in_ep; + + if (report_on_irq) + ep = ch->irq_ep; - msg = usb_buf_alloc_st(ch->in_ep, SIMTRACE_MSGC_CARDEM, - SIMTRACE_MSGT_BD_CEMU_STATUS); + msg = usb_buf_alloc_st(ep, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_BD_CEMU_STATUS); if (!msg) return; @@ -1009,27 +1067,61 @@ void card_emu_report_status(struct card_handle *ch) sts->flags |= CEMU_STATUS_F_CLK_ACTIVE; if (ch->in_reset) sts->flags |= CEMU_STATUS_F_RESET_ACTIVE; - /* FIXME: voltage + card insert */ - sts->fi = ch->fi; - sts->di = ch->di; +#ifdef DETECT_VCC_BY_ADC + sts->voltage_mv = card_emu_get_vcc(ch->num); +#endif + /* FIXME: card insert */ + sts->F_index = ch->F_index; + sts->D_index = ch->D_index; sts->wi = ch->wi; sts->waiting_time = ch->waiting_time; usb_buf_upd_len_and_submit(msg); } +static void card_emu_report_config(struct card_handle *ch) +{ + struct msgb *msg; + struct cardemu_usb_msg_config *cfg; + uint8_t ep = ch->in_ep; + + msg = usb_buf_alloc_st(ch->in_ep, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_BD_CEMU_CONFIG); + if (!msg) + return; + + cfg = (struct cardemu_usb_msg_config *) msgb_put(msg, sizeof(*cfg)); + cfg->features = ch->features; +#ifdef HAVE_SLOT_MUX + cfg->slot_mux_nr = mux_get_slot(); +#else + cfg->slot_mux_nr = 0; +#endif + + + usb_buf_upd_len_and_submit(msg); +} + /* hardware driver informs us that a card I/O signal has changed */ void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active) { + uint32_t chg_mask = 0; + switch (io) { case CARD_IO_VCC: if (active == 0 && ch->vcc_active == 1) { TRACE_INFO("%u: VCC deactivated\r\n", ch->num); - tc_etu_disable(ch->tc_chan); + card_handle_reset(ch); card_set_state(ch, ISO_S_WAIT_POWER); + chg_mask |= CEMU_STATUS_F_VCC_PRESENT; } else if (active == 1 && ch->vcc_active == 0) { +#ifdef DETECT_VCC_BY_ADC + TRACE_INFO("%u: VCC activated (%d mV)\r\n", ch->num, + card_emu_get_vcc(ch->num)); +#else TRACE_INFO("%u: VCC activated\r\n", ch->num); +#endif card_set_state(ch, ISO_S_WAIT_CLK); + chg_mask |= CEMU_STATUS_F_VCC_PRESENT; } ch->vcc_active = active; break; @@ -1038,27 +1130,49 @@ void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active) TRACE_INFO("%u: CLK activated\r\n", ch->num); if (ch->state == ISO_S_WAIT_CLK) card_set_state(ch, ISO_S_WAIT_RST); + chg_mask |= CEMU_STATUS_F_CLK_ACTIVE; } else if (active == 0 && ch->clocked == 1) { TRACE_INFO("%u: CLK deactivated\r\n", ch->num); + chg_mask |= CEMU_STATUS_F_CLK_ACTIVE; } ch->clocked = active; break; case CARD_IO_RST: if (active == 0 && ch->in_reset) { TRACE_INFO("%u: RST released\r\n", ch->num); - if (ch->vcc_active && ch->clocked) { - /* enable the TC/ETU counter once reset has been released */ - tc_etu_enable(ch->tc_chan); + if (ch->vcc_active && ch->clocked && ch->state == ISO_S_WAIT_RST) { /* prepare to send the ATR */ card_set_state(ch, ISO_S_WAIT_ATR); } + chg_mask |= CEMU_STATUS_F_RESET_ACTIVE; } else if (active && !ch->in_reset) { TRACE_INFO("%u: RST asserted\r\n", ch->num); - tc_etu_disable(ch->tc_chan); + card_handle_reset(ch); + chg_mask |= CEMU_STATUS_F_RESET_ACTIVE; + card_set_state(ch, ISO_S_WAIT_RST); } ch->in_reset = active; break; } + + switch (ch->state) { + case ISO_S_WAIT_POWER: + case ISO_S_WAIT_CLK: + case ISO_S_WAIT_RST: + /* check end activation state (even if the reader does + * not respect the activation sequence) */ + if (ch->vcc_active && ch->clocked && !ch->in_reset) { + /* prepare to send the ATR */ + card_set_state(ch, ISO_S_WAIT_ATR); + } + break; + default: + break; + } + + /* notify the host about the state change */ + if ((ch->features & CEMU_FEAT_F_STATUS_IRQ) && chg_mask) + card_emu_report_status(ch, true); } /* User sets a new ATR to be returned during next card reset */ @@ -1085,7 +1199,7 @@ int card_emu_set_atr(struct card_handle *ch, const uint8_t *atr, uint8_t len) } /* hardware driver informs us that one (more) ETU has expired */ -void tc_etu_wtime_half_expired(void *handle) +void card_emu_wtime_half_expired(void *handle) { struct card_handle *ch = handle; /* transmit NULL procedure byte well before waiting time expires */ @@ -1095,7 +1209,10 @@ void tc_etu_wtime_half_expired(void *handle) case TPDU_S_WAIT_PB: case TPDU_S_WAIT_TX: putchar('N'); + /* we are waiting for data from the user. Send a procedure byte to ask the + * reader to wait more time */ card_emu_uart_tx(ch->uart_chan, ISO7816_3_PB_NULL); + card_emu_uart_reset_wt(ch->uart_chan); break; default: break; @@ -1107,7 +1224,7 @@ void tc_etu_wtime_half_expired(void *handle) } /* hardware driver informs us that one (more) ETU has expired */ -void tc_etu_wtime_expired(void *handle) +void card_emu_wtime_expired(void *handle) { struct card_handle *ch = handle; switch (ch->state) { @@ -1121,13 +1238,45 @@ void tc_etu_wtime_expired(void *handle) } } -/* shortest ATR found in smartcard_list.txt */ -static const uint8_t default_atr[] = { 0x3B, 0x02, 0x14, 0x50 }; +/* reasonable ATR offering all protocols and voltages + * smartphones might not care, but other readers do + * + * TS = 0x3B Direct Convention + * T0 = 0x80 Y(1): b1000, K: 0 (historical bytes) + * TD(1) = 0x80 Y(i+1) = b1000, Protocol T=0 + * ---- + * TD(2) = 0x81 Y(i+1) = b1000, Protocol T=1 + * ---- + * TD(3) = 0x1F Y(i+1) = b0001, Protocol T=15 + * ---- + * TA(4) = 0xC7 Clock stop: no preference - Class accepted by the card: (3G) A 5V B 3V C 1.8V + * ---- + * Historical bytes + * TCK = 0x59 correct checksum + */ +static const uint8_t default_atr[] = { 0x3B, 0x80, 0x80, 0x81 , 0x1F, 0xC7, 0x59 }; static struct card_handle card_handles[NUM_SLOTS]; -struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uart_chan, - uint8_t in_ep, uint8_t irq_ep) +int card_emu_set_config(struct card_handle *ch, const struct cardemu_usb_msg_config *scfg, + unsigned int scfg_len) +{ + if (scfg_len >= sizeof(uint32_t)) + ch->features = (scfg->features & SUPPORTED_FEATURES); + +#ifdef HAVE_SLOT_MUX + if (scfg_len >= sizeof(uint32_t)+sizeof(uint8_t)) { + mux_set_slot(scfg->slot_mux_nr); + } +#endif + + /* send back a report of our current configuration */ + card_emu_report_config(ch); + + return 0; +} + +struct card_handle *card_emu_init(uint8_t slot_num, uint8_t uart_chan, uint8_t in_ep, uint8_t irq_ep, bool vcc_active, bool in_reset, bool clocked) { struct card_handle *ch; @@ -1140,20 +1289,18 @@ struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uar INIT_LLIST_HEAD(&ch->uart_tx_queue); - /* initialize the card_handle with reasonable defaults */ ch->num = slot_num; ch->irq_ep = irq_ep; ch->in_ep = in_ep; ch->state = ISO_S_WAIT_POWER; - ch->vcc_active = 0; - ch->in_reset = 1; - ch->clocked = 0; + ch->vcc_active = vcc_active; + ch->in_reset = in_reset; + ch->clocked = clocked; - ch->fi = 0; - ch->di = 1; + ch->Fi_index = ch->F_index = 1; + ch->Di_index = ch->D_index = 1; ch->wi = ISO7816_3_DEFAULT_WI; - ch->tc_chan = tc_chan; ch->uart_chan = uart_chan; ch->waiting_time = ISO7816_3_INIT_WTIME; @@ -1164,7 +1311,7 @@ struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uar ch->pts.state = PTS_S_WAIT_REQ_PTSS; ch->tpdu.state = TPDU_S_WAIT_CLA; - tc_etu_init(ch->tc_chan, ch); + card_handle_reset(ch); return ch; } diff --git a/firmware/libcommon/source/cciddriver.c b/firmware/libcommon/source/cciddriver.c index 1dbdf23..b4ff451 100644 --- a/firmware/libcommon/source/cciddriver.c +++ b/firmware/libcommon/source/cciddriver.c @@ -193,8 +193,8 @@ static void RDRtoPCDatablock_ATR( void ) ccidDriver.ProtocolDataStructure[0] = Atr[2]; // TA(1) // bmTCCKST0 - // For T=0 ,B0 – 0b, B7-2 – 000000b - // B1 – Convention used (b1=0 for direct, b1=1 for inverse) + // For T=0 ,B0 - 0b, B7-2 - 000000b + // B1 - Convention used (b1=0 for direct, b1=1 for inverse) // bGuardTimeT0 // Extra Guardtime between two characters. Add 0 to 254 etu to the normal @@ -428,7 +428,7 @@ static void PCtoRDRXfrBlock( void ) uint16_t msglen = 0; uint32_t ret; - TRACE_DEBUG("PCtoRDRXfrBlock\n"); + TRACE_DEBUG("PCtoRDRXfrBlock\n\r"); // Check the block length if ( ccidDriver.sCcidCommand.wLength > (configurationDescriptorsFS->ccid.dwMaxCCIDMessageLength-10) ) { @@ -921,7 +921,7 @@ void USBDCallbacks_RequestReceived(const USBGenericRequest *request) void CCID_SmartCardRequest( void ) { unsigned char bStatus; - TRACE_DEBUG("CCID_req\n"); + TRACE_DEBUG("CCID_req\n\r"); do { @@ -1005,7 +1005,7 @@ unsigned char CCID_Removal( void ) //------------------------------------------------------------------------------ /// Interrupt-IN Messages /// This message is sent when any bit in the bHardwareErrorCode field is set. -/// If this message is sent when there is no “outstanding” command, the bSeq +/// If this message is sent when there is no "outstanding" command, the bSeq /// field will be undefined. /// \param bSlot ICC slot number /// \param bSeq Sequence number of the bulk OUT command when the hardware error diff --git a/firmware/libcommon/source/crcstub.c b/firmware/libcommon/source/crcstub.c new file mode 100644 index 0000000..ef52521 --- /dev/null +++ b/firmware/libcommon/source/crcstub.c @@ -0,0 +1,86 @@ +/* SIMtrace 2 firmware crc stub + * + * (C) 2021 by sysmocom -s.f.m.c. GmbH, Author: Eric Wild <ewild@sysmocom.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <stdint.h> +#include "board.h" +#include "core_cm3.h" +#include "usb/device/dfu/dfu.h" + +/* +* This file is a bit special, everything has to go to specific sections, and no globals are available. +* No external functions may be called, unless inlining is enforced! +*/ + +static void crc_check_stub(); +__attribute__((section(".crcstub_table"))) volatile uint32_t crcstub_dummy_table[] = { + (uint32_t)0xdeadc0de, /* deliberately choose invalid value so unpatched image will not be started */ + (uint32_t)crc_check_stub, /* must be valid flash addr */ + (uint32_t)0xf1, /* crc value calculated by the host */ + (uint32_t)0xf2, /* crc calc start address */ + (uint32_t)0xf3 /* crc calc length (byte) */ +}; + +__attribute__((section(".crcstub_code"))) static void do_crc32(int8_t c, uint32_t *crc_reg) +{ + int32_t i, mask; + *crc_reg ^= c; + + for (unsigned int j = 0; j < 8; j++) + if (*crc_reg & 1) + *crc_reg = (*crc_reg >> 1) ^ 0xEDB88320; + else + *crc_reg = *crc_reg >> 1; +} + +__attribute__((section(".crcstub_code"), noinline)) static void crc_check_stub() +{ + uint32_t crc_reg = 0xffffffff; + uint32_t expected_crc_val = crcstub_dummy_table[2]; + uint8_t *crc_calc_startaddr = (uint8_t *)crcstub_dummy_table[3]; + volatile uint32_t *actual_exc_tbl = (volatile uint32_t *)crc_calc_startaddr; + uint32_t crc_len = crcstub_dummy_table[4]; + + /* 4000ms wdt tickling */ + WDT->WDT_MR = WDT_MR_WDRSTEN | WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT | (((4000UL << 8) / 1000) << 16) | + ((4000UL << 8) / 1000); + + for (uint8_t *i = crc_calc_startaddr; i < crc_calc_startaddr + crc_len; i++) + do_crc32(*i, &crc_reg); + + crc_reg = ~crc_reg; + + if (crc_reg == expected_crc_val) { + /* this looks a bit awkward because we have to ensure the bx does not require a sp-relative load */ + __asm__ volatile("\ + mov r0, %0;\n\ + mov r1, %1;\n\ + MSR msp,r0;\n\ + bx r1;" + : + : "r"(actual_exc_tbl[0]), "r"(actual_exc_tbl[1])); + } else { + /* no globals ! */ + ((struct dfudata *)0x20000000)->magic = USB_DFU_MAGIC; + __DSB(); + for (;;) { + /* no functon call, since NVIC_SystemReset() might not be inlined! */ + SCB->AIRCR = ((0x5FA << SCB_AIRCR_VECTKEY_Pos) | (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | + SCB_AIRCR_SYSRESETREQ_Msk); + __DSB(); + while (1) + ; + } + } +} diff --git a/firmware/libcommon/source/fputs.c b/firmware/libcommon/source/fputs.c index 110f68e..8f2b21e 100644 --- a/firmware/libcommon/source/fputs.c +++ b/firmware/libcommon/source/fputs.c @@ -9,10 +9,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #include <stdio.h> #include "uart_console.h" diff --git a/firmware/libcommon/source/host_communication.c b/firmware/libcommon/source/host_communication.c index ea573bb..b2faf1b 100644 --- a/firmware/libcommon/source/host_communication.c +++ b/firmware/libcommon/source/host_communication.c @@ -9,10 +9,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #include "board.h" #include "llist_irqsafe.h" @@ -27,27 +23,36 @@ * USBD Integration API ***********************************************************************/ -/* call-back after (successful?) transfer of a buffer */ +/* call-back after (successful?) transfer of a write buffer on IN EP */ static void usb_write_cb(uint8_t *arg, uint8_t status, uint32_t transferred, uint32_t remaining) { struct msgb *msg = (struct msgb *) arg; struct usb_buffered_ep *bep = msg->dst; + uint16_t ep_size = USBD_GetEndpointSize(bep->ep); unsigned long x; TRACE_DEBUG("%s (EP=0x%02x)\r\n", __func__, bep->ep); + if (((msgb_length(msg) % ep_size) == 0) && (transferred == ep_size)) { + /* terminate with ZLP; pass in 'msg' again as 'arg' so we get + * called the second time and proceed with usb_buf_free below */ + USBD_Write(bep->ep, 0, 0, (TransferCallback) &usb_write_cb, msg); + return; + } + local_irq_save(x); bep->in_progress--; local_irq_restore(x); - TRACE_DEBUG("%u: in_progress=%d\n", bep->ep, bep->in_progress); + TRACE_DEBUG("%u: in_progress=%lu\r\n", bep->ep, bep->in_progress); if (status != USBD_STATUS_SUCCESS) - TRACE_ERROR("%s error, status=%d\n", __func__, status); + TRACE_ERROR("%s error, status=%d\r\n", __func__, status); usb_buf_free(msg); } +/* check if the spcified IN endpoint is idle and submit the next buffer from queue */ int usb_refill_to_host(uint8_t ep) { struct usb_buffered_ep *bep = usb_get_buf_ep(ep); @@ -75,44 +80,44 @@ int usb_refill_to_host(uint8_t ep) bep->in_progress++; - msg = msgb_dequeue(&bep->queue); + msg = msgb_dequeue_count(&bep->queue, &bep->queue_len); local_irq_restore(x); - TRACE_DEBUG("%s (EP=0x%02x), in_progress=%d\r\n", __func__, ep, bep->in_progress); + TRACE_DEBUG("%s (EP=0x%02x), in_progress=%lu\r\n", __func__, ep, bep->in_progress); msg->dst = bep; rc = USBD_Write(ep, msgb_data(msg), msgb_length(msg), (TransferCallback) &usb_write_cb, msg); if (rc != USBD_STATUS_SUCCESS) { - TRACE_ERROR("%s error %x\n", __func__, rc); + TRACE_ERROR("%s error %x\r\n", __func__, rc); /* re-insert to head of queue */ llist_add_irqsafe(&msg->list, &bep->queue); local_irq_save(x); bep->in_progress--; local_irq_restore(x); - TRACE_DEBUG("%02x: in_progress=%d\n", bep->ep, bep->in_progress); + TRACE_DEBUG("%02x: in_progress=%lu\r\n", bep->ep, bep->in_progress); return 0; } return 1; } -/* call-back after (successful?) transfer of a buffer */ +/* call-back after (successful?) read transfer of a buffer on OUT EP */ static void usb_read_cb(uint8_t *arg, uint8_t status, uint32_t transferred, uint32_t remaining) { struct msgb *msg = (struct msgb *) arg; struct usb_buffered_ep *bep = msg->dst; - TRACE_DEBUG("%s (EP=%u, len=%u, q=%p)\r\n", __func__, + TRACE_DEBUG("%s (EP=%u, len=%lu, q=%p)\r\n", __func__, bep->ep, transferred, &bep->queue); bep->in_progress = 0; if (status != USBD_STATUS_SUCCESS) { - TRACE_ERROR("%s error, status=%d\n", __func__, status); + TRACE_ERROR("%s error, status=%d\r\n", __func__, status); usb_buf_free(msg); return; } @@ -120,6 +125,7 @@ static void usb_read_cb(uint8_t *arg, uint8_t status, uint32_t transferred, llist_add_tail_irqsafe(&msg->list, &bep->queue); } +/* refill the read queue for data received from host PC on OUT EP, if needed */ int usb_refill_from_host(uint8_t ep) { struct usb_buffered_ep *bep = usb_get_buf_ep(ep); @@ -150,7 +156,7 @@ int usb_refill_from_host(uint8_t ep) rc = USBD_Read(ep, msg->head, msgb_tailroom(msg), (TransferCallback) &usb_read_cb, msg); if (rc != USBD_STATUS_SUCCESS) { - TRACE_ERROR("%s error %d\n", __func__, rc); + TRACE_ERROR("%s error %d\r\n", __func__, rc); usb_buf_free(msg); bep->in_progress = 0; } @@ -158,6 +164,7 @@ int usb_refill_from_host(uint8_t ep) return 1; } +/* drain any buffers from the queue of the endpoint and release their memory */ int usb_drain_queue(uint8_t ep) { struct usb_buffered_ep *bep = usb_get_buf_ep(ep); @@ -177,7 +184,7 @@ int usb_drain_queue(uint8_t ep) } /* free all queued msgbs */ - while ((msg = msgb_dequeue(&bep->queue))) { + while ((msg = msgb_dequeue_count(&bep->queue, &bep->queue_len))) { usb_buf_free(msg); ret++; } diff --git a/firmware/libcommon/source/iso7816_fidi.c b/firmware/libcommon/source/iso7816_fidi.c index 1c70467..024663b 100644 --- a/firmware/libcommon/source/iso7816_fidi.c +++ b/firmware/libcommon/source/iso7816_fidi.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #include <stdint.h> #include <errno.h> @@ -23,38 +19,38 @@ #include "iso7816_fidi.h" /* Table 7 of ISO 7816-3:2006 */ -const uint16_t fi_table[] = { +const uint16_t iso7816_3_fi_table[] = { 372, 372, 558, 744, 1116, 1488, 1860, 0, 0, 512, 768, 1024, 1536, 2048, 0, 0 }; /* Table 8 from ISO 7816-3:2006 */ -const uint8_t di_table[] = { +const uint8_t iso7816_3_di_table[] = { 0, 1, 2, 4, 8, 16, 32, 64, 12, 20, 2, 4, 8, 16, 32, 64, }; /* compute the F/D ratio based on Fi and Di values */ -int compute_fidi_ratio(uint8_t fi, uint8_t di) +int iso7816_3_compute_fd_ratio(uint8_t f_index, uint8_t d_index) { uint16_t f, d; int ret; - if (fi >= ARRAY_SIZE(fi_table) || - di >= ARRAY_SIZE(di_table)) + if (f_index >= ARRAY_SIZE(iso7816_3_fi_table) || + d_index >= ARRAY_SIZE(iso7816_3_di_table)) return -EINVAL; - f = fi_table[fi]; + f = iso7816_3_fi_table[f_index]; if (f == 0) return -EINVAL; - d = di_table[di]; + d = iso7816_3_di_table[d_index]; if (d == 0) return -EINVAL; /* See table 7 of ISO 7816-3: From 1000 on we divide by 1/d, * which equals a multiplication by d */ - if (di < 8) + if (d_index < 8) ret = f / d; else ret = f * d; diff --git a/firmware/libcommon/source/main_common.c b/firmware/libcommon/source/main_common.c new file mode 100644 index 0000000..cd3bced --- /dev/null +++ b/firmware/libcommon/source/main_common.c @@ -0,0 +1,50 @@ +/* SIMtrace 2 firmware common main helpers + * + * (C) 2015-2019 by Harald Welte <hwelte@hmw-consulting.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "board.h" +#include "utils.h" + +void print_banner(void) +{ + printf("\n\r\n\r" + "=============================================================================\n\r" + "SIMtrace2 firmware " GIT_VERSION ", BOARD=" BOARD ", APP=" APPLICATION "\n\r" + "(C) 2010-2019 by Harald Welte, 2018-2019 by Kevin Redon\n\r" + "=============================================================================\n\r"); + +#if (TRACE_LEVEL >= TRACE_LEVEL_INFO) + /* print chip-unique ID */ + unsigned int unique_id[4]; + EEFC_ReadUniqueID(unique_id); + TRACE_INFO("Chip ID: 0x%08lx (Ext 0x%08lx)\n\r", CHIPID->CHIPID_CIDR, CHIPID->CHIPID_EXID); + TRACE_INFO("Serial Nr. %08x-%08x-%08x-%08x\n\r", + unique_id[0], unique_id[1], unique_id[2], unique_id[3]); + + /* print reset cause */ + uint8_t reset_cause = (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos; + static const char* reset_causes[] = { + "general reset (first power-up reset)", + "backup reset (return from backup mode)", + "watchdog reset (watchdog fault occurred)", + "software reset (processor reset required by the software)", + "user reset (NRST pin detected low)", + }; + if (reset_cause < ARRAY_SIZE(reset_causes)) { + TRACE_INFO("Reset Cause: %s\n\r", reset_causes[reset_cause]); + } else { + TRACE_INFO("Reset Cause: 0x%lx\n\r", (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos); + } +#endif +} diff --git a/firmware/libcommon/source/mode_cardemu.c b/firmware/libcommon/source/mode_cardemu.c index 98818e1..a05840e 100644 --- a/firmware/libcommon/source/mode_cardemu.c +++ b/firmware/libcommon/source/mode_cardemu.c @@ -1,7 +1,7 @@ /* card emulation mode * * (C) 2015-2017 by Harald Welte <laforge@gnumonks.org> - * (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de> + * (C) 2018-2019 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #include "board.h" #include "boardver_adc.h" @@ -39,12 +35,28 @@ static const Pin pins_cardsim[] = PINS_CARDSIM; #endif /* UART pins */ +#if defined(ngff_cardem) +static const Pin pins_usim1[] = {PINS_USIM2}; +static const Pin pin_usim1_rst = PIN_USIM2_nRST; +#define FIRST_USART_BASE USART0 +#define FIRST_USART_ID ID_USART0 +#define FIRST_USART_IRQ USART0_IRQn +#else static const Pin pins_usim1[] = {PINS_USIM1}; static const Pin pin_usim1_rst = PIN_USIM1_nRST; +#define FIRST_USART_BASE USART1 +#define FIRST_USART_ID ID_USART1 +#define FIRST_USART_IRQ USART1_IRQn +#endif static const Pin pin_usim1_vcc = PIN_USIM1_VCC; +#ifdef PIN_USIM1_IO_DIR +static const Pin pin_io_dir = PIN_USIM1_IO_DIR; +#endif + + #ifdef CARDEMU_SECOND_UART -static const Pin pins_usim2[] = {PINS_USIM2}; +static const Pin pins_usim2[] = {PINS_USIM2}; static const Pin pin_usim2_rst = PIN_USIM2_nRST; static const Pin pin_usim2_vcc = PIN_USIM2_VCC; #endif @@ -55,21 +67,45 @@ struct cardem_inst { struct llist_head usb_out_queue; struct ringbuf rb; struct Usart_info usart_info; + struct { + /*! receiver waiting time to trigger timeout (0 to deactivate it) */ + uint32_t total; + /*! remaining waiting time (we may need multiple timer runs to reach total */ + uint32_t remaining; + /*! did we already notify about half the time having expired? */ + bool half_time_notified; + } wt; int usb_pending_old; uint8_t ep_out; uint8_t ep_in; uint8_t ep_int; const Pin pin_insert; +#ifdef DETECT_VCC_BY_ADC uint32_t vcc_uv; - uint32_t vcc_uv_last; +#endif + + /*! real-time state of VCC I/O line, irrespective of enabled flag */ + bool vcc_active; + + /*! last VCC state we reported to the card emu state machine (conditioned by enabled flag) */ + bool vcc_active_last; + + /*! real-time state of RST I/O line, irrespective of enabled flag */ + bool rst_active; + + /*! last RST state we reported to the card emu state machine (conditioned by enabled flag) */ + bool rst_active_last; + + /*! flag indicating whether this instance should perform card emulation, or not */ + bool enabled; }; struct cardem_inst cardem_inst[] = { { .num = 0, .usart_info = { - .base = USART1, - .id = ID_USART1, + .base = FIRST_USART_BASE, + .id = FIRST_USART_ID, .state = USART_RCV }, .ep_out = SIMTRACE_CARDEM_USB_EP_USIM1_DATAOUT, @@ -129,18 +165,54 @@ void card_emu_uart_wait_tx_idle(uint8_t uart_chan) wait_tx_idle(usart); } +static void card_emu_uart_set_direction(uint8_t uart_chan, bool tx) +{ + /* only on some boards (octsimtest) we hae an external level + * shifter that requires us to switch the direction between RX and TX */ +#ifdef PIN_USIM1_IO_DIR + if (uart_chan == 0) { + if (tx) + PIO_Set(&pin_io_dir); + else + PIO_Clear(&pin_io_dir); + } +#endif +} + +int card_emu_get_vcc(uint8_t uart_chan) +{ + struct cardem_inst *ci = &cardem_inst[uart_chan]; +#ifdef DETECT_VCC_BY_ADC + return ci->vcc_uv / 1000; +#else + return -1; +#endif +} + /* call-back from card_emu.c to enable/disable transmit and/or receive */ void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx) { Usart *usart = get_usart_by_chan(uart_chan); switch (rxtx) { case ENABLE_TX: - USART_DisableIt(usart, ~US_IER_TXRDY); + card_emu_uart_set_direction(uart_chan, true); + USART_DisableIt(usart, ~(US_IER_TXRDY | US_IER_TIMEOUT)); + /* as irritating as it is, we actually want to keep the + * receiver enabled during transmit */ + USART_SetReceiverEnabled(usart, 1); + usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK; + USART_EnableIt(usart, US_IER_TXRDY | US_IER_TIMEOUT); + USART_SetTransmitterEnabled(usart, 1); + break; + case ENABLE_TX_TIMER_ONLY: + /* enable the transmitter without generating TXRDY interrupts + * just so that the timer can run */ + USART_DisableIt(usart, ~US_IER_TIMEOUT); /* as irritating as it is, we actually want to keep the * receiver enabled during transmit */ USART_SetReceiverEnabled(usart, 1); usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK; - USART_EnableIt(usart, US_IER_TXRDY); + USART_EnableIt(usart, US_IER_TIMEOUT); USART_SetTransmitterEnabled(usart, 1); break; case ENABLE_RX: @@ -149,6 +221,7 @@ void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx) * transmitter enabled during receive */ USART_SetTransmitterEnabled(usart, 1); wait_tx_idle(usart); + card_emu_uart_set_direction(uart_chan, false);; usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK; USART_EnableIt(usart, US_IER_RXRDY); USART_SetReceiverEnabled(usart, 1); @@ -188,8 +261,25 @@ int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte) return 1; } +static uint16_t compute_next_timeout(struct cardem_inst *ci) +{ + uint32_t want_to_expire; + + if (ci->wt.total == 0) + return 0; + + if (!ci->wt.half_time_notified) { + /* we need to make sure to expire after half the total waiting time */ + OSMO_ASSERT(ci->wt.remaining > (ci->wt.total / 2)); + want_to_expire = ci->wt.remaining - (ci->wt.total / 2); + } else + want_to_expire = ci->wt.remaining; + /* if value exceeds the USART TO range, use the maximum possible value for one round */ + return OSMO_MIN(want_to_expire, 0xffff); +} -/* FIXME: integrate this with actual irq handler */ +/*! common handler if interrupt was received. + * \param[in] inst_num Instance number, range 0..1 (some boards only '0' permitted) */ static void usart_irq_rx(uint8_t inst_num) { Usart *usart = get_usart_by_chan(inst_num); @@ -197,32 +287,84 @@ static void usart_irq_rx(uint8_t inst_num) uint32_t csr; uint8_t byte = 0; + /* get one atomic snapshot of state/flags before they get changed */ csr = usart->US_CSR & usart->US_IMR; + /* check if one byte has been completely received and is now in the holding register */ if (csr & US_CSR_RXRDY) { + /* read the bye from the holding register */ byte = (usart->US_RHR) & 0xFF; + /* append it to the buffer */ if (rbuf_write(&ci->rb, byte) < 0) TRACE_ERROR("rbuf overrun\r\n"); } + /* check if the transmitter is ready for the next byte */ if (csr & US_CSR_TXRDY) { - if (card_emu_tx_byte(ci->ch) == 0) + /* transmit next byte and check if more bytes are to be transmitted */ + if (card_emu_tx_byte(ci->ch) == 0) { + /* stop the TX ready interrupt of no more bytes to transmit */ USART_DisableIt(usart, US_IER_TXRDY); + } } - if (csr & (US_CSR_OVRE|US_CSR_FRAME|US_CSR_PARE| - US_CSR_TIMEOUT|US_CSR_NACK|(1<<10))) { + /* check if any error flags are set */ + if (csr & (US_CSR_OVRE|US_CSR_FRAME|US_CSR_PARE|US_CSR_NACK|(1<<10))) { + /* clear any error flags */ usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK; - TRACE_ERROR("%u e 0x%x st: 0x%lx\n", ci->num, byte, csr); + TRACE_ERROR("%u USART error on 0x%x status: 0x%lx\n", ci->num, byte, csr); + } + + /* check if the timeout has expired. We "abuse" the receive timer for tracking + * how many etu have expired since we last sent a byte. See section + * 33.7.3.11 "Receiver Time-out" of the SAM3S8 Data Sheet */ + if (csr & US_CSR_TIMEOUT) { + /* clear timeout flag (and stop timeout until next character is received) */ + usart->US_CR |= US_CR_STTTO; + + /* RX has been inactive for some time */ + if (ci->wt.remaining <= (usart->US_RTOR & 0xffff)) { + /* waiting time is over; will stop the timer */ + ci->wt.remaining = 0; + } else { + /* subtract the actual timeout since the new might not have been set and + * reloaded yet */ + ci->wt.remaining -= (usart->US_RTOR & 0xffff); + } + if (ci->wt.remaining == 0) { + /* let the FSM know that WT has expired */ + card_emu_wtime_expired(ci->ch); + /* don't automatically re-start in this case */ + } else { + bool half_time_just_reached = false; + + if (ci->wt.remaining <= ci->wt.total / 2 && !ci->wt.half_time_notified) { + ci->wt.half_time_notified = true; + /* don't immediately call card_emu_wtime_half_expired(), as that + * in turn may calls card_emu_uart_update_wt() which will change + * the timeout but would be overridden 4 lines below */ + half_time_just_reached = true; + } + + /* update the counter no matter if we reached half time or not */ + usart->US_RTOR = compute_next_timeout(ci); + /* restart the counter (if wt is 0, the timeout is not started) */ + usart->US_CR |= US_CR_RETTO; + + if (half_time_just_reached) + card_emu_wtime_half_expired(ci->ch); + } } } +/*! ISR called for USART0 */ void mode_cardemu_usart0_irq(void) { /* USART0 == Instance 1 == USIM 2 */ usart_irq_rx(1); } +/*! ISR called for USART1 */ void mode_cardemu_usart1_irq(void) { /* USART1 == Instance 0 == USIM 1 */ @@ -241,13 +383,47 @@ int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi) return 0; } +/*! Update WT on USART peripheral. Will automatically re-start timer with new value. + * \param[in] usart USART peripheral to configure + * \param[in] wt inactivity Waiting Time before card_emu_wtime_expired is called (0 to disable) */ +void card_emu_uart_update_wt(uint8_t uart_chan, uint32_t wt) +{ + OSMO_ASSERT(uart_chan < ARRAY_SIZE(cardem_inst)); + struct cardem_inst *ci = &cardem_inst[uart_chan]; + Usart *usart = get_usart_by_chan(uart_chan); + + if (ci->wt.total != wt) { + TRACE_DEBUG("%u: USART WT changed from %lu to %lu ETU\r\n", uart_chan, + ci->wt.total, wt); + } + + ci->wt.total = wt; + /* reset and start the timer */ + card_emu_uart_reset_wt(uart_chan); +} + +/*! Reset and re-start waiting timeout count down on USART peripheral. + * \param[in] usart USART peripheral to configure */ +void card_emu_uart_reset_wt(uint8_t uart_chan) +{ + OSMO_ASSERT(uart_chan < ARRAY_SIZE(cardem_inst)); + struct cardem_inst *ci = &cardem_inst[uart_chan]; + Usart *usart = get_usart_by_chan(uart_chan); + + /* FIXME: guard against race with interrupt handler */ + ci->wt.remaining = ci->wt.total; + ci->wt.half_time_notified = false; + usart->US_RTOR = compute_next_timeout(ci); + /* restart the counter (if wt is 0, the timeout is not started) */ + usart->US_CR |= US_CR_RETTO; +} + /* call-back from card_emu.c to force a USART interrupt */ void card_emu_uart_interrupt(uint8_t uart_chan) { + OSMO_ASSERT(uart_chan < ARRAY_SIZE(cardem_inst)); Usart *usart = get_usart_by_chan(uart_chan); - if (!usart) { - return; - } + if (USART0 == usart) { NVIC_SetPendingIRQ(USART0_IRQn); } else if (USART1 == usart) { @@ -260,8 +436,11 @@ void card_emu_uart_interrupt(uint8_t uart_chan) ***********************************************************************/ #ifdef DETECT_VCC_BY_ADC +#if !defined(VCC_UV_THRESH_1V8) || !defined(VCC_UV_THRESH_3V) +#error "You must define VCC_UV_THRESH_{1V8,3V} if you use ADC VCC detection" +#endif -static int adc_triggered = 0; +static volatile int adc_triggered = 0; static int adc_sam3s_reva_errata = 0; static int card_vcc_adc_init(void) @@ -302,29 +481,23 @@ static int card_vcc_adc_init(void) ADC->ADC_CHER |= ADC_CHER_CH6; ADC->ADC_IER |= ADC_IER_EOC6; #endif + NVIC_SetPriority(ADC_IRQn, 13); NVIC_EnableIRQ(ADC_IRQn); ADC->ADC_CR |= ADC_CR_START; return 0; } -#define VCC_UV_THRESH_1V8 1500000 -#define VCC_UV_THRESH_3V 2800000 - static void process_vcc_adc(struct cardem_inst *ci) { - if (ci->vcc_uv >= VCC_UV_THRESH_3V && - ci->vcc_uv_last < VCC_UV_THRESH_3V) { - card_emu_io_statechg(ci->ch, CARD_IO_VCC, 1); - /* FIXME do this for real */ - card_emu_io_statechg(ci->ch, CARD_IO_CLK, 1); - } else if (ci->vcc_uv < VCC_UV_THRESH_3V && - ci->vcc_uv_last >= VCC_UV_THRESH_3V) { - /* FIXME do this for real */ - card_emu_io_statechg(ci->ch, CARD_IO_CLK, 0); - card_emu_io_statechg(ci->ch, CARD_IO_VCC, 0); - } - ci->vcc_uv_last = ci->vcc_uv; +#ifdef octsimtest + if (ci->vcc_uv >= VCC_UV_THRESH_1V8) +#else + if (ci->vcc_uv >= VCC_UV_THRESH_3V) +#endif + ci->vcc_active = true; + else + ci->vcc_active = false; } void ADC_IrqHandler(void) @@ -347,44 +520,60 @@ void ADC_IrqHandler(void) cardem_inst[0].vcc_uv = adc2uv(val); process_vcc_adc(&cardem_inst[0]); ADC->ADC_CR |= ADC_CR_START; + adc_triggered = 1; } } #endif /* DETECT_VCC_BY_ADC */ + +/** + * called from main loop; dispatches card I/O state changes to card_emu from main loop. + * NOTE: conditions I/O state on the ci->enabled flag; if the instance is disabled, we assume VCC is + * disabled and the device is not in reset + */ +static void process_io_statechg(struct cardem_inst *ci) +{ + const bool vcc_active = ci->vcc_active && ci->enabled; + if (vcc_active != ci->vcc_active_last) { + card_emu_io_statechg(ci->ch, CARD_IO_VCC, vcc_active); + /* FIXME do this for real */ + card_emu_io_statechg(ci->ch, CARD_IO_CLK, vcc_active); + ci->vcc_active_last = vcc_active; + } + + const bool rst_active = ci->rst_active && ci->enabled; + if (rst_active != ci->rst_active_last) { + card_emu_io_statechg(ci->ch, CARD_IO_RST, rst_active); + ci->rst_active_last = rst_active; + } +} + /*********************************************************************** * Core USB / main loop integration ***********************************************************************/ static void usim1_rst_irqhandler(const Pin *pPin) { - int active = PIO_Get(&pin_usim1_rst) ? 0 : 1; - card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_RST, active); + cardem_inst[0].rst_active = PIO_Get(&pin_usim1_rst) ? false : true; } #ifndef DETECT_VCC_BY_ADC static void usim1_vcc_irqhandler(const Pin *pPin) { - int active = PIO_Get(&pin_usim1_vcc) ? 1 : 0; - card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_VCC, active); - /* FIXME do this for real */ - card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_CLK, active); + cardem_inst[0].vcc_active = PIO_Get(&pin_usim1_vcc) ? true : false; } #endif /* !DETECT_VCC_BY_ADC */ #ifdef CARDEMU_SECOND_UART static void usim2_rst_irqhandler(const Pin *pPin) { - int active = PIO_Get(&pin_usim2_rst) ? 0 : 1; - card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_RST, active); + cardem_inst[1].rst_active = PIO_Get(&pin_usim2_rst) ? false : true; } #ifndef DETECT_VCC_BY_ADC static void usim2_vcc_irqhandler(const Pin *pPin) { - int active = PIO_Get(&pin_usim2_vcc) ? 1 : 0; - card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_VCC, active); - /* FIXME do this for real */ - card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_CLK, active); + cardem_inst[1].vcc_active = PIO_Get(&pin_usim2_vcc) ? true : false; } #endif /* !DETECT_VCC_BY_ADC */ #endif /* CARDEMU_SECOND_UART */ @@ -402,6 +591,8 @@ void mode_cardemu_init(void) TRACE_ENTRY(); + NVIC_SetPriority(UDP_IRQn, 14); + #ifdef PINS_CARDSIM PIO_Configure(pins_cardsim, PIO_LISTSIZE(pins_cardsim)); #endif @@ -412,15 +603,29 @@ void mode_cardemu_init(void) INIT_LLIST_HEAD(&cardem_inst[0].usb_out_queue); rbuf_reset(&cardem_inst[0].rb); PIO_Configure(pins_usim1, PIO_LISTSIZE(pins_usim1)); + + /* configure USART as ISO-7816 slave (e.g. card) */ ISO7816_Init(&cardem_inst[0].usart_info, CLK_SLAVE); - NVIC_EnableIRQ(USART1_IRQn); + NVIC_SetPriority(FIRST_USART_IRQ, 0); + NVIC_EnableIRQ(FIRST_USART_IRQ); PIO_ConfigureIt(&pin_usim1_rst, usim1_rst_irqhandler); PIO_EnableIt(&pin_usim1_rst); + + /* obtain current RST state */ + usim1_rst_irqhandler(&pin_usim1_rst); #ifndef DETECT_VCC_BY_ADC PIO_ConfigureIt(&pin_usim1_vcc, usim1_vcc_irqhandler); PIO_EnableIt(&pin_usim1_vcc); + + /* obtain current VCC state */ + usim1_vcc_irqhandler(&pin_usim1_vcc); +#else + do {} while (!adc_triggered); /* wait for first ADC reading */ #endif /* DETECT_VCC_BY_ADC */ - cardem_inst[0].ch = card_emu_init(0, 2, 0, SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN, SIMTRACE_CARDEM_USB_EP_USIM1_INT); + + cardem_inst[0].ch = card_emu_init(0, 0, SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN, + SIMTRACE_CARDEM_USB_EP_USIM1_INT, cardem_inst[0].vcc_active, + cardem_inst[0].rst_active, cardem_inst[0].vcc_active); sim_switch_use_physical(0, 1); #ifdef CARDEMU_SECOND_UART @@ -428,17 +633,26 @@ void mode_cardemu_init(void) rbuf_reset(&cardem_inst[1].rb); PIO_Configure(pins_usim2, PIO_LISTSIZE(pins_usim2)); ISO7816_Init(&cardem_inst[1].usart_info, CLK_SLAVE); + /* TODO enable timeout */ + NVIC_SetPriority(USART0_IRQn, 0); NVIC_EnableIRQ(USART0_IRQn); PIO_ConfigureIt(&pin_usim2_rst, usim2_rst_irqhandler); PIO_EnableIt(&pin_usim2_rst); + usim2_rst_irqhandler(&pin_usim2_rst); /* obtain current RST state */ #ifndef DETECT_VCC_BY_ADC PIO_ConfigureIt(&pin_usim2_vcc, usim2_vcc_irqhandler); PIO_EnableIt(&pin_usim2_vcc); + usim2_vcc_irqhandler(&pin_usim2_vcc); /* obtain current VCC state */ +#else + do {} while (!adc_triggered); /* wait for first ADC reading */ #endif /* DETECT_VCC_BY_ADC */ - cardem_inst[1].ch = card_emu_init(1, 0, 1, SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN, SIMTRACE_CARDEM_USB_EP_USIM2_INT); + + cardem_inst[1].ch = card_emu_init(1, 1, SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN, + SIMTRACE_CARDEM_USB_EP_USIM2_INT, cardem_inst[1].vcc_active, + cardem_inst[1].rst_active, cardem_inst[1].vcc_active); sim_switch_use_physical(1, 1); + /* TODO check RST and VCC */ #endif /* CARDEMU_SECOND_UART */ - } /* called if config is deactivated */ @@ -452,9 +666,9 @@ void mode_cardemu_exit(void) PIO_DisableIt(&pin_usim1_rst); PIO_DisableIt(&pin_usim1_vcc); - NVIC_DisableIRQ(USART1_IRQn); - USART_SetTransmitterEnabled(USART1, 0); - USART_SetReceiverEnabled(USART1, 0); + NVIC_DisableIRQ(FIRST_USART_IRQ); + USART_SetTransmitterEnabled(FIRST_USART_BASE, 0); + USART_SetReceiverEnabled(FIRST_USART_BASE, 0); #ifdef CARDEMU_SECOND_UART PIO_DisableIt(&pin_usim2_rst); @@ -481,12 +695,33 @@ static void dispatch_usb_command_generic(struct msgb *msg, struct cardem_inst *c usb_buf_free(msg); } +static void process_card_insert(struct cardem_inst *ci, bool card_insert) +{ + TRACE_INFO("%u: set card_insert to %s\r\n", ci->num, card_insert ? "INSERTED" : "REMOVED"); + +#ifdef HAVE_BOARD_CARDINSERT + board_set_card_insert(ci, card_insert); +#else + if (!ci->pin_insert.pio) { + TRACE_INFO("%u: skipping unsupported card_insert to %s\r\n", + ci->num, card_insert ? "INSERTED" : "REMOVED"); + return; + } + + if (card_insert) + PIO_Set(&ci->pin_insert); + else + PIO_Clear(&ci->pin_insert); +#endif +} + /* handle a single USB command as received from the USB host */ static void dispatch_usb_command_cardem(struct msgb *msg, struct cardem_inst *ci) { struct simtrace_msg_hdr *hdr; struct cardemu_usb_msg_set_atr *atr; struct cardemu_usb_msg_cardinsert *cardins; + struct cardemu_usb_msg_config *cfg; struct llist_head *queue; hdr = (struct simtrace_msg_hdr *) msg->l1h; @@ -503,21 +738,16 @@ static void dispatch_usb_command_cardem(struct msgb *msg, struct cardem_inst *ci break; case SIMTRACE_MSGT_DT_CEMU_CARDINSERT: cardins = (struct cardemu_usb_msg_cardinsert *) msg->l2h; - if (!ci->pin_insert.pio) { - TRACE_INFO("%u: skipping unsupported card_insert to %s\r\n", - ci->num, cardins->card_insert ? "INSERTED" : "REMOVED"); - break; - } - TRACE_INFO("%u: set card_insert to %s\r\n", ci->num, - cardins->card_insert ? "INSERTED" : "REMOVED"); - if (cardins->card_insert) - PIO_Set(&ci->pin_insert); - else - PIO_Clear(&ci->pin_insert); + process_card_insert(ci, cardins->card_insert); usb_buf_free(msg); break; case SIMTRACE_MSGT_BD_CEMU_STATUS: - card_emu_report_status(ci->ch); + card_emu_report_status(ci->ch, false); + usb_buf_free(msg); + break; + case SIMTRACE_MSGT_BD_CEMU_CONFIG: + cfg = (struct cardemu_usb_msg_config *) msg->l2h; + card_emu_set_config(ci->ch, cfg, msgb_l2len(msg)); usb_buf_free(msg); break; case SIMTRACE_MSGT_BD_CEMU_STATS: @@ -565,10 +795,8 @@ static int usb_command_sim_select(struct msgb *msg, struct cardem_inst *ci) if (msgb_l2len(msg) < sizeof(*mss)) return -1; - if (mss->remote_sim) - sim_switch_use_physical(ci->num, 0); - else - sim_switch_use_physical(ci->num, 1); + ci->enabled = mss->remote_sim ? true : false; + sim_switch_use_physical(ci->num, !ci->enabled); return 0; } @@ -653,9 +881,10 @@ static void dispatch_received_msg(struct msgb *msg, struct cardem_inst *ci) } if (mh->msg_len > msgb_length(msg)) { - TRACE_ERROR("%u: Unexpected large message (%u bytes)\n", + TRACE_ERROR("%u: Unexpected large message (%u bytes)\r\n", ci->num, mh->msg_len); usb_buf_free(segm); + break; } else { uint8_t *cur = msgb_put(segm, mh->msg_len); segm->l1h = segm->head; @@ -711,10 +940,15 @@ void mode_cardemu_run(void) } uint8_t byte = rbuf_read(&ci->rb); __enable_irq(); - card_emu_process_rx_byte(ci->ch, byte); + + if (ci->enabled) { + card_emu_process_rx_byte(ci->ch, byte); + } //TRACE_ERROR("%uRx%02x\r\n", i, byte); } + process_io_statechg(ci); + /* first try to send any pending messages on IRQ */ usb_refill_to_host(ci->ep_int); diff --git a/firmware/libcommon/source/pseudo_talloc.c b/firmware/libcommon/source/pseudo_talloc.c index 862fffd..5a4d1ca 100644 --- a/firmware/libcommon/source/pseudo_talloc.c +++ b/firmware/libcommon/source/pseudo_talloc.c @@ -9,19 +9,18 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #include <stdint.h> +#include <stdio.h> #include "talloc.h" #include "trace.h" #include "utils.h" #include <osmocom/core/utils.h> -#define NUM_RCTX_SMALL 10 +/* TODO: this number should dynamically scale. We need at least one per IN/IRQ endpoint, + * as well as at least 3 for every OUT endpoint. Plus some more depending on the application */ +#define NUM_RCTX_SMALL 20 #define RCTX_SIZE_SMALL 348 static uint8_t msgb_data[NUM_RCTX_SMALL][RCTX_SIZE_SMALL] __attribute__((aligned(sizeof(long)))); @@ -63,6 +62,7 @@ int _talloc_free(void *ptr, const char *location) if (ptr == msgb_data[i]) { if (!msgb_inuse[i]) { TRACE_ERROR("%s: double_free by %s\r\n", __func__, location); + OSMO_ASSERT(0); } else { msgb_inuse[i] = 0; } @@ -73,9 +73,24 @@ int _talloc_free(void *ptr, const char *location) local_irq_restore(x); TRACE_ERROR("%s: invalid pointer %p from %s\r\n", __func__, ptr, location); + OSMO_ASSERT(0); return -1; } +void talloc_report(const void *ptr, FILE *f) +{ + unsigned int i; + + fprintf(f, "talloc_report(): "); + for (i = 0; i < ARRAY_SIZE(msgb_inuse); i++) { + if (msgb_inuse[i]) + fputc('X', f); + else + fputc('_', f); + } + fprintf(f, "\r\n"); +} + void talloc_set_name_const(const void *ptr, const char *name) { /* do nothing */ diff --git a/firmware/libcommon/source/ringbuffer.c b/firmware/libcommon/source/ringbuffer.c index 70747a1..d3690be 100644 --- a/firmware/libcommon/source/ringbuffer.c +++ b/firmware/libcommon/source/ringbuffer.c @@ -9,10 +9,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #include "ringbuffer.h" #include "trace.h" @@ -32,6 +28,16 @@ void rbuf_reset(volatile ringbuf * rb) local_irq_restore(state); } +void rbuf16_reset(volatile ringbuf16 * rb) +{ + unsigned long state; + + local_irq_save(state); + rb->ird = 0; + rb->iwr = 0; + local_irq_restore(state); +} + uint8_t rbuf_read(volatile ringbuf * rb) { unsigned long state; @@ -45,21 +51,49 @@ uint8_t rbuf_read(volatile ringbuf * rb) return val; } +uint16_t rbuf16_read(volatile ringbuf16 * rb) +{ + unsigned long state; + uint16_t val; + + local_irq_save(state); + val = rb->buf[rb->ird]; + rb->ird = (rb->ird + 1) % RING16_BUFLEN; + local_irq_restore(state); + + return val; +} + uint8_t rbuf_peek(volatile ringbuf * rb) { return rb->buf[rb->ird]; } +uint16_t rbuf16_peek(volatile ringbuf16 * rb) +{ + return rb->buf[rb->ird]; +} + bool rbuf_is_empty(volatile ringbuf * rb) { return rb->ird == rb->iwr; } +bool rbuf16_is_empty(volatile ringbuf16 * rb) +{ + return rb->ird == rb->iwr; +} + static bool __rbuf_is_full(volatile ringbuf * rb) { return rb->ird == (rb->iwr + 1) % RING_BUFLEN; } +static bool __rbuf16_is_full(volatile ringbuf16 * rb) +{ + return rb->ird == (rb->iwr + 1) % RING16_BUFLEN; +} + bool rbuf_is_full(volatile ringbuf * rb) { unsigned long state; @@ -72,6 +106,18 @@ bool rbuf_is_full(volatile ringbuf * rb) return rc; } +bool rbuf16_is_full(volatile ringbuf16 * rb) +{ + unsigned long state; + bool rc; + + local_irq_save(state); + rc = rb->ird == (rb->iwr + 1) % RING16_BUFLEN; + local_irq_restore(state); + + return rc; +} + int rbuf_write(volatile ringbuf * rb, uint8_t item) { unsigned long state; @@ -88,4 +134,18 @@ int rbuf_write(volatile ringbuf * rb, uint8_t item) } } +int rbuf16_write(volatile ringbuf16 * rb, uint16_t item) +{ + unsigned long state; + local_irq_save(state); + if (!__rbuf16_is_full(rb)) { + rb->buf[rb->iwr] = item; + rb->iwr = (rb->iwr + 1) % RING16_BUFLEN; + local_irq_restore(state); + return 0; + } else { + local_irq_restore(state); + return -1; + } +} diff --git a/firmware/libcommon/source/simtrace_iso7816.c b/firmware/libcommon/source/simtrace_iso7816.c index 889ca2d..27677a6 100644 --- a/firmware/libcommon/source/simtrace_iso7816.c +++ b/firmware/libcommon/source/simtrace_iso7816.c @@ -71,7 +71,7 @@ void ISR_PhoneRST(const Pin * pPin) USBD_Write(SIMTRACE_USB_EP_PHONE_INT, "R", 1, (TransferCallback) & Callback_PhoneRST_ISR, 0)) != USBD_STATUS_SUCCESS) { - TRACE_ERROR("USB err status: %d (%s)\n", ret, __FUNCTION__); + TRACE_ERROR("USB err status: %d (%s)\r\n", ret, __FUNCTION__); return; } @@ -80,7 +80,7 @@ void ISR_PhoneRST(const Pin * pPin) } /* - * char_stat is zero if no error occured. + * char_stat is zero if no error occurred. * Otherwise it is filled with the content of the status register. */ void mode_trace_usart1_irq(void) @@ -109,8 +109,8 @@ void mode_trace_usart1_irq(void) /* Fill char into buffer */ rbuf_write(&sim_rcv_buf, c); } else { - TRACE_DEBUG("e %x st: %x\n", c, stat); - } /* else: error occured */ + TRACE_DEBUG("e %x st: %lx\r\n", c, stat); + } /* else: error occurred */ char_stat = stat; } @@ -125,7 +125,7 @@ void update_fidi(Usart_info *usart, uint8_t fidi) uint8_t fi = fidi >> 4; uint8_t di = fidi & 0xf; - int ratio = compute_fidi_ratio(fi, di); + int ratio = iso7816_3_compute_fd_ratio(fi, di); if (ratio > 0 && ratio < 0x8000) { /* make sure USART uses new F/D ratio */ diff --git a/firmware/libcommon/source/sniffer.c b/firmware/libcommon/source/sniffer.c index 33c16d3..948eee8 100644 --- a/firmware/libcommon/source/sniffer.c +++ b/firmware/libcommon/source/sniffer.c @@ -1,6 +1,6 @@ /* SIMtrace 2 sniffer mode * - * (C) 2016-2017 by Harald Welte <hwelte@hmw-consulting.de> + * (C) 2016-2022 by Harald Welte <hwelte@hmw-consulting.de> * (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de> * * This program is free software; you can redistribute it and/or modify @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ /* This code implement the Sniffer mode to sniff the communication between a * SIM card (or any ISO 7816 smart card) and a phone (or any ISO 7816 card @@ -115,6 +111,13 @@ enum tpdu_sniff_state { TPDU_S_SW2, /*!< second status word */ }; +/*! Error flags we use to report USART errors via the ringbuffer */ +#define RBUF16_F_OVERRUN 0x0100 +#define RBUF16_F_FRAMING 0x0200 +#define RBUF16_F_PARITY 0x0400 +#define RBUF16_F_TIMEOUT_WT 0x0800 +#define RBUF16_F_DATA_BYTE 0x8000 + /*------------------------------------------------------------------------------ * Internal variables *------------------------------------------------------------------------------*/ @@ -142,50 +145,58 @@ static struct Usart_info sniff_usart = { .state = USART_RCV, }; /*! Ring buffer to store sniffer communication data */ -static struct ringbuf sniff_buffer; +static struct ringbuf16 sniff_buffer; /* Flags to know is the card status changed (see SIMTRACE_MSGT_DT_SNIFF_CHANGE flags) */ -volatile uint32_t change_flags = 0; +static volatile uint32_t change_flags = 0; /* ISO 7816 variables */ /*! ISO 7816-3 state */ -enum iso7816_3_sniff_state iso_state = ISO7816_S_RESET; -/*! ATR state */ -enum atr_sniff_state atr_state; -/*! ATR data - * @remark can be used to check later protocol changes - */ -uint8_t atr[MAX_ATR_SIZE]; -/*! Current index in the ATR data */ -uint8_t atr_i = 0; +static enum iso7816_3_sniff_state iso_state = ISO7816_S_RESET; + +static struct { + /*! ATR state */ + enum atr_sniff_state state; + /*! ATR data + * @remark can be used to check later protocol changes + */ + uint8_t atr[MAX_ATR_SIZE]; + /*! Current index in the ATR data */ + uint8_t atr_i; +} g_atr; + /*! If convention conversion is needed */ -bool convention_convert = false; +static bool convention_convert = false; /*! The supported T protocols */ -uint16_t t_protocol_support = 0; -/*! PPS state - * @remark it is shared between request and response since they aren't simultaneous but follow the same procedure - */ -enum pps_sniff_state pps_state; -/*! PPS request data - * @remark can be used to check PPS response - */ -uint8_t pps_req[MAX_PPS_SIZE]; -/*! PPS response data */ -uint8_t pps_rsp[MAX_PPS_SIZE]; -/*! TPDU state */ -enum tpdu_sniff_state tpdu_state; -/*! Final TPDU packet - * @note this is the complete command+response TPDU, including header, data, and status words - * @remark this does not include the procedure bytes - */ -uint8_t tpdu_packet[5+256+2]; -/*! Current index in TPDU packet */ -uint16_t tpdu_packet_i = 0; +static uint16_t t_protocol_support = 0; + +static struct { + /*! PPS state + * @remark it is shared between request and response since they aren't simultaneous but + * follow the same procedure */ + enum pps_sniff_state state; + /*! PPS request data + * @remark can be used to check PPS response */ + uint8_t req[MAX_PPS_SIZE]; + /*! PPS response data */ + uint8_t rsp[MAX_PPS_SIZE]; +} g_pps; + +static struct { + /*! TPDU state */ + enum tpdu_sniff_state state; + /*! Final TPDU packet + * @note this is the complete command+response TPDU, including header, data, and status words + * @remark this does not include the procedure bytes */ + uint8_t packet[5+256+2]; + /*! Current index in TPDU packet */ + uint16_t packet_i; +} g_tpdu; /*! Waiting Time (WT) * @note defined in ISO/IEC 7816-3:2006(E) section 8.1 and 10.2 */ -uint32_t wt = 9600; +static uint32_t g_wt = 9600; /*------------------------------------------------------------------------------ * Internal functions @@ -200,10 +211,11 @@ static const uint8_t convention_convert_lut[256] = { 0xff, 0x7f, 0xbf, 0x3f, 0xd /*! Update Waiting Time (WT) * @param[in] wi Waiting Integer (0 if unchanged) * @param[in] d Baud Rate divider (0 if unchanged) + * @param[in] cause String describing the source of the change * @note set wt to be used by the receiver timeout * @note defined in ISO/IEC 7816-3:2006(E) section 8.1 and 10.2 */ -static void update_wt(uint8_t wi, uint8_t d) +static void update_wt(uint8_t wi, uint8_t d, const char *cause) { static uint8_t wt_wi = 10; /* Waiting time Integer (WI), used to calculate the Waiting Time (WT) */ static uint8_t wt_d = 1; /* baud rate adjustment integer (the actual value, not the table index) */ @@ -214,8 +226,8 @@ static void update_wt(uint8_t wi, uint8_t d) if (0 != d) { wt_d = d; } - wt = wt_wi*960UL*wt_d; - TRACE_INFO("WT updated to %lu\n\r", wt); + g_wt = wt_wi * 960UL * wt_d; + TRACE_INFO("WT updated (wi=%u, d=%u, cause=%s) to %lu ETU\n\r", wi, d, cause, g_wt); } /*! Allocate USB buffer and push + initialize simtrace_msg_hdr @@ -259,6 +271,15 @@ void usb_msg_upd_len_and_submit(struct msgb *usb_msg) usb_buf_submit(usb_msg); } +/*! Update the TPDU state + * @param[in] tpdu_state_new new TPDU state to update to + */ +static void change_tpdu_state(enum tpdu_sniff_state tpdu_state_new) +{ + //TRACE_ERROR("TPDU state %u->%u\n\r", g_tpdu.state, tpdu_state_new); + g_tpdu.state = tpdu_state_new; +} + /*! Update the ISO 7816-3 state * @param[in] iso_state_new new ISO 7816-3 state to update to */ @@ -274,51 +295,40 @@ static void change_state(enum iso7816_3_sniff_state iso_state_new) switch (iso_state_new) { case ISO7816_S_RESET: update_fidi(&sniff_usart, 0x11); /* reset baud rate to default Di/Fi values */ - update_wt(10, 1); /* reset WT time-out */ + update_wt(10, 1, "RESET"); /* reset WT time-out */ break; case ISO7816_S_WAIT_ATR: - rbuf_reset(&sniff_buffer); /* reset buffer for new communication */ + rbuf16_reset(&sniff_buffer); /* reset buffer for new communication */ break; case ISO7816_S_IN_ATR: - atr_i = 0; + g_atr.atr_i = 0; convention_convert = false; t_protocol_support = 0; - atr_state = ATR_S_WAIT_TS; + g_atr.state = ATR_S_WAIT_TS; break; case ISO7816_S_IN_PPS_REQ: case ISO7816_S_IN_PPS_RSP: - pps_state = PPS_S_WAIT_PPSS; + g_pps.state = PPS_S_WAIT_PPSS; break; case ISO7816_S_WAIT_TPDU: - tpdu_state = TPDU_S_CLA; - tpdu_packet_i = 0; + change_tpdu_state(TPDU_S_CLA); + g_tpdu.packet_i = 0; break; default: break; } + TRACE_INFO("ISO 7816-3 state %u->%u\n\r", iso_state, iso_state_new); + /* save new state */ iso_state = iso_state_new; - TRACE_INFO("Changed to ISO 7816-3 state %u\n\r", iso_state); } const struct value_string data_flags[] = { - { - .value = SNIFF_DATA_FLAG_ERROR_INCOMPLETE, - .str = "incomplete", - }, - { - .value = SNIFF_DATA_FLAG_ERROR_MALFORMED, - .str = "malformed", - }, - { - .value = SNIFF_DATA_FLAG_ERROR_CHECKSUM, - .str = "checksum error", - }, - { - .value = 0, - .str = NULL, - }, + { SNIFF_DATA_FLAG_ERROR_INCOMPLETE, "incomplete" }, + { SNIFF_DATA_FLAG_ERROR_MALFORMED, "malformed" }, + { SNIFF_DATA_FLAG_ERROR_CHECKSUM, "checksum error" }, + { 0, NULL } }; static void print_flags(const struct value_string* flag_meanings, uint32_t nb_flags, uint32_t flags) { @@ -396,13 +406,13 @@ static void usb_send_atr(uint32_t flags) TRACE_WARNING("Can't print ATR in ISO 7816-3 state %u\n\r", iso_state); return; } - if (atr_i >= ARRAY_SIZE(atr)) { + if (g_atr.atr_i >= ARRAY_SIZE(g_atr.atr)) { TRACE_ERROR("ATR buffer overflow\n\r"); return; } /* Send ATR over USB */ - usb_send_data(SIMTRACE_MSGT_SNIFF_ATR, atr, atr_i, flags); + usb_send_data(SIMTRACE_MSGT_SNIFF_ATR, g_atr.atr, g_atr.atr_i, flags); } /*! Process ATR byte @@ -420,16 +430,16 @@ static void process_byte_atr(uint8_t byte) TRACE_ERROR("Processing ATR data in wrong ISO 7816-3 state %u\n\r", iso_state); return; } - if (atr_i >= ARRAY_SIZE(atr)) { + if (g_atr.atr_i >= ARRAY_SIZE(g_atr.atr)) { TRACE_ERROR("ATR data overflow\n\r"); return; } /* save data for use by other functions */ - atr[atr_i++] = byte; + g_atr.atr[g_atr.atr_i++] = byte; /* handle ATR byte depending on current state */ - switch (atr_state) { + switch (g_atr.state) { case ATR_S_WAIT_TS: /* see ISO/IEC 7816-3:2006 section 8.1 */ flags = 0; switch (byte) { @@ -438,7 +448,7 @@ static void process_byte_atr(uint8_t byte) convention_convert = !convention_convert; case 0x3b: /* direct convention used and correctly decoded */ case 0x3f: /* inverse convention used and correctly decoded */ - atr_state = ATR_S_WAIT_T0; /* wait for format byte */ + g_atr.state = ATR_S_WAIT_T0; /* wait for format byte */ break; default: TRACE_WARNING("Invalid TS received\n\r"); @@ -451,41 +461,41 @@ static void process_byte_atr(uint8_t byte) break; case ATR_S_WAIT_T0: /* see ISO/IEC 7816-3:2006 section 8.2.2 */ case ATR_S_WAIT_TD: /* see ISO/IEC 7816-3:2006 section 8.2.3 */ - if (ATR_S_WAIT_T0 == atr_state) { + if (ATR_S_WAIT_T0 == g_atr.state) { atr_hist_len = (byte & 0x0f); /* save the number of historical bytes */ - } else if (ATR_S_WAIT_TD == atr_state) { + } else if (ATR_S_WAIT_TD == g_atr.state) { t_protocol_support |= (1<<(byte & 0x0f)); /* remember supported protocol to know if TCK will be present */ } y = (byte & 0xf0); /* remember upcoming interface bytes */ i++; /* next interface byte sub-group is coming */ if (y & 0x10) { - atr_state = ATR_S_WAIT_TA; /* wait for interface byte TA */ + g_atr.state = ATR_S_WAIT_TA; /* wait for interface byte TA */ break; } case ATR_S_WAIT_TA: /* see ISO/IEC 7816-3:2006 section 8.2.3 */ if (y & 0x20) { - atr_state = ATR_S_WAIT_TB; /* wait for interface byte TB */ + g_atr.state = ATR_S_WAIT_TB; /* wait for interface byte TB */ break; } case ATR_S_WAIT_TB: /* see ISO/IEC 7816-3:2006 section 8.2.3 */ if (y & 0x40) { - atr_state = ATR_S_WAIT_TC; /* wait for interface byte TC */ + g_atr.state = ATR_S_WAIT_TC; /* wait for interface byte TC */ break; } case ATR_S_WAIT_TC: /* see ISO/IEC 7816-3:2006 section 8.2.3 */ /* retrieve WI encoded in TC2*/ - if (ATR_S_WAIT_TC==atr_state && 2==i) { + if (ATR_S_WAIT_TC == g_atr.state && 2 == i) { if (0 == byte) { - update_wt(10, 0); + update_wt(10, 0, "TC2=0"); } else { - update_wt(byte, 0); + update_wt(byte, 0, "TC2"); } } if (y & 0x80) { - atr_state = ATR_S_WAIT_TD; /* wait for interface byte TD */ + g_atr.state = ATR_S_WAIT_TD; /* wait for interface byte TD */ break; } else if (atr_hist_len) { - atr_state = ATR_S_WAIT_HIST; /* wait for historical bytes */ + g_atr.state = ATR_S_WAIT_HIST; /* wait for historical bytes */ break; } case ATR_S_WAIT_HIST: /* see ISO/IEC 7816-3:2006 section 8.2.4 */ @@ -494,7 +504,7 @@ static void process_byte_atr(uint8_t byte) } if (0 == atr_hist_len) { if (t_protocol_support > 1) { - atr_state = ATR_S_WAIT_TCK; /* wait for check bytes */ + g_atr.state = ATR_S_WAIT_TCK; /* wait for check bytes */ break; } } else { @@ -502,11 +512,11 @@ static void process_byte_atr(uint8_t byte) } case ATR_S_WAIT_TCK: /* see ISO/IEC 7816-3:2006 section 8.2.5 */ /* verify checksum if present */ - if (ATR_S_WAIT_TCK == atr_state) { + if (ATR_S_WAIT_TCK == g_atr.state) { uint8_t ui; uint8_t checksum = 0; - for (ui = 1; ui < atr_i; ui++) { - checksum ^= atr[ui]; + for (ui = 1; ui < g_atr.atr_i; ui++) { + checksum ^= g_atr.atr[ui]; } if (checksum) { flags |= SNIFF_DATA_FLAG_ERROR_CHECKSUM; @@ -519,7 +529,7 @@ static void process_byte_atr(uint8_t byte) change_state(ISO7816_S_WAIT_TPDU); /* go to next state */ break; default: - TRACE_INFO("Unknown ATR state %u\n\r", atr_state); + TRACE_INFO("Unknown ATR state %u\n\r", g_atr.state); } } @@ -533,9 +543,9 @@ static void usb_send_pps(uint32_t flags) /* Sanity check */ if (ISO7816_S_IN_PPS_REQ == iso_state) { - pps_cur = pps_req; + pps_cur = g_pps.req; } else if (ISO7816_S_IN_PPS_RSP == iso_state) { - pps_cur = pps_rsp; + pps_cur = g_pps.rsp; } else { TRACE_ERROR("Can't print PPS in ISO 7816-3 state %u\n\r", iso_state); return; @@ -544,22 +554,22 @@ static void usb_send_pps(uint32_t flags) /* Get only relevant data */ uint8_t pps[6]; uint8_t pps_i = 0; - if (pps_state > PPS_S_WAIT_PPSS) { + if (g_pps.state > PPS_S_WAIT_PPSS) { pps[pps_i++] = pps_cur[0]; } - if (pps_state > PPS_S_WAIT_PPS0) { + if (g_pps.state > PPS_S_WAIT_PPS0) { pps[pps_i++] = pps_cur[1]; } - if (pps_state > PPS_S_WAIT_PPS1 && pps_cur[1] & 0x10) { + if (g_pps.state > PPS_S_WAIT_PPS1 && pps_cur[1] & 0x10) { pps[pps_i++] = pps_cur[2]; } - if (pps_state > PPS_S_WAIT_PPS2 && pps_cur[1] & 0x20) { + if (g_pps.state > PPS_S_WAIT_PPS2 && pps_cur[1] & 0x20) { pps[pps_i++] = pps_cur[3]; } - if (pps_state > PPS_S_WAIT_PPS3 && pps_cur[1] & 0x40) { + if (g_pps.state > PPS_S_WAIT_PPS3 && pps_cur[1] & 0x40) { pps[pps_i++] = pps_cur[4]; } - if (pps_state > PPS_S_WAIT_PCK) { + if (g_pps.state > PPS_S_WAIT_PCK) { pps[pps_i++] = pps_cur[5]; } @@ -589,21 +599,21 @@ static void process_byte_pps(uint8_t byte) /* sanity check */ if (ISO7816_S_IN_PPS_REQ == iso_state) { - pps_cur = pps_req; + pps_cur = g_pps.req; } else if (ISO7816_S_IN_PPS_RSP == iso_state) { - pps_cur = pps_rsp; + pps_cur = g_pps.rsp; } else { TRACE_ERROR("Processing PPS data in wrong ISO 7816-3 state %u\n\r", iso_state); return; } /* handle PPS byte depending on current state */ - switch (pps_state) { /* see ISO/IEC 7816-3:2006 section 9.2 */ + switch (g_pps.state) { /* see ISO/IEC 7816-3:2006 section 9.2 */ case PPS_S_WAIT_PPSS: /*!< initial byte */ flags = 0; - if (0xff) { + if (byte == 0xff) { pps_cur[0] = byte; - pps_state = PPS_S_WAIT_PPS0; /* go to next state */ + g_pps.state = PPS_S_WAIT_PPS0; /* go to next state */ } else { TRACE_INFO("Invalid PPSS received\n\r"); led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */ @@ -614,24 +624,24 @@ static void process_byte_pps(uint8_t byte) case PPS_S_WAIT_PPS0: /*!< format byte */ pps_cur[1] = byte; if (pps_cur[1] & 0x10) { - pps_state = PPS_S_WAIT_PPS1; /* go to next state */ + g_pps.state = PPS_S_WAIT_PPS1; /* go to next state */ break; } case PPS_S_WAIT_PPS1: /*!< first parameter byte */ pps_cur[2] = byte; /* not always right but doesn't affect the process */ if (pps_cur[1] & 0x20) { - pps_state = PPS_S_WAIT_PPS2; /* go to next state */ + g_pps.state = PPS_S_WAIT_PPS2; /* go to next state */ break; } case PPS_S_WAIT_PPS2: /*!< second parameter byte */ pps_cur[3] = byte; /* not always right but doesn't affect the process */ if (pps_cur[1] & 0x40) { - pps_state = PPS_S_WAIT_PPS3; /* go to next state */ + g_pps.state = PPS_S_WAIT_PPS3; /* go to next state */ break; } case PPS_S_WAIT_PPS3: /*!< third parameter byte */ pps_cur[4] = byte; /* not always right but doesn't affect the process */ - pps_state = PPS_S_WAIT_PCK; /* go to next state */ + g_pps.state = PPS_S_WAIT_PCK; /* go to next state */ break; case PPS_S_WAIT_PCK: /*!< check byte */ pps_cur[5] = byte; /* not always right but doesn't affect the process */ @@ -652,7 +662,7 @@ static void process_byte_pps(uint8_t byte) if (check) { flags |= SNIFF_DATA_FLAG_ERROR_CHECKSUM; } - pps_state = PPS_S_WAIT_END; + g_pps.state = PPS_S_WAIT_END; usb_send_pps(flags); /* send PPS to host software using USB */ if (ISO7816_S_IN_PPS_REQ == iso_state) { if (0 == check) { /* checksum is valid */ @@ -670,9 +680,10 @@ static void process_byte_pps(uint8_t byte) fn = 1; dn = 1; } - TRACE_INFO("PPS negotiation successful: Fn=%u Dn=%u\n\r", fi_table[fn], di_table[dn]); + TRACE_INFO("PPS negotiation successful: Fn=%u Dn=%u\n\r", + iso7816_3_fi_table[fn], iso7816_3_di_table[dn]); update_fidi(&sniff_usart, pps_cur[2]); - update_wt(0, di_table[dn]); + update_wt(0, iso7816_3_di_table[dn], "PPS"); usb_send_fidi(pps_cur[2]); /* send Fi/Di change notification to host software over USB */ } else { /* checksum is invalid */ TRACE_INFO("PPS negotiation failed\n\r"); @@ -681,10 +692,10 @@ static void process_byte_pps(uint8_t byte) } break; case PPS_S_WAIT_END: - TRACE_WARNING("Unexpected PPS received %u\n\r", pps_state); + TRACE_WARNING("Unexpected PPS received %u\n\r", g_pps.state); break; default: - TRACE_WARNING("Unknown PPS state %u\n\r", pps_state); + TRACE_WARNING("Unknown PPS state %u\n\r", g_pps.state); break; } } @@ -702,7 +713,7 @@ static void usb_send_tpdu(uint32_t flags) } /* Send ATR over USB */ - usb_send_data(SIMTRACE_MSGT_SNIFF_TPDU, tpdu_packet, tpdu_packet_i, flags); + usb_send_data(SIMTRACE_MSGT_SNIFF_TPDU, g_tpdu.packet, g_tpdu.packet_i, flags); } static void process_byte_tpdu(uint8_t byte) @@ -712,13 +723,13 @@ static void process_byte_tpdu(uint8_t byte) TRACE_ERROR("Processing TPDU data in wrong ISO 7816-3 state %u\n\r", iso_state); return; } - if (tpdu_packet_i >= ARRAY_SIZE(tpdu_packet)) { + if (g_tpdu.packet_i >= ARRAY_SIZE(g_tpdu.packet)) { TRACE_ERROR("TPDU data overflow\n\r"); return; } /* handle TPDU byte depending on current state */ - switch (tpdu_state) { + switch (g_tpdu.state) { case TPDU_S_CLA: if (0xff == byte) { TRACE_WARNING("0xff is not a valid class byte\n\r"); @@ -727,51 +738,51 @@ static void process_byte_tpdu(uint8_t byte) change_state(ISO7816_S_WAIT_TPDU); /* go back to TPDU state */ return; } - tpdu_packet_i = 0; - tpdu_packet[tpdu_packet_i++] = byte; - tpdu_state = TPDU_S_INS; + g_tpdu.packet_i = 0; + g_tpdu.packet[g_tpdu.packet_i++] = byte; + change_tpdu_state(TPDU_S_INS); break; case TPDU_S_INS: if ((0x60 == (byte & 0xf0)) || (0x90 == (byte & 0xf0))) { - TRACE_WARNING("invalid CLA 0x%02x\n\r", byte); + TRACE_WARNING("invalid INS 0x%02x\n\r", byte); led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */ usb_send_tpdu(SNIFF_DATA_FLAG_ERROR_MALFORMED); /* send ATR to host software using USB */ change_state(ISO7816_S_WAIT_TPDU); /* go back to TPDU state */ return; } - tpdu_packet_i = 1; - tpdu_packet[tpdu_packet_i++] = byte; - tpdu_state = TPDU_S_P1; + g_tpdu.packet_i = 1; + g_tpdu.packet[g_tpdu.packet_i++] = byte; + change_tpdu_state(TPDU_S_P1); break; case TPDU_S_P1: - tpdu_packet_i = 2; - tpdu_packet[tpdu_packet_i++] = byte; - tpdu_state = TPDU_S_P2; + g_tpdu.packet_i = 2; + g_tpdu.packet[g_tpdu.packet_i++] = byte; + change_tpdu_state(TPDU_S_P2); break; case TPDU_S_P2: - tpdu_packet_i = 3; - tpdu_packet[tpdu_packet_i++] = byte; - tpdu_state = TPDU_S_P3; + g_tpdu.packet_i = 3; + g_tpdu.packet[g_tpdu.packet_i++] = byte; + change_tpdu_state(TPDU_S_P3); break; case TPDU_S_P3: - tpdu_packet_i = 4; - tpdu_packet[tpdu_packet_i++] = byte; - tpdu_state = TPDU_S_PROCEDURE; + g_tpdu.packet_i = 4; + g_tpdu.packet[g_tpdu.packet_i++] = byte; + change_tpdu_state(TPDU_S_PROCEDURE); break; case TPDU_S_PROCEDURE: if (0x60 == byte) { /* wait for next procedure byte */ break; - } else if (tpdu_packet[1] == byte) { /* get all remaining data bytes */ - tpdu_state = TPDU_S_DATA_REMAINING; + } else if (g_tpdu.packet[1] == byte) { /* get all remaining data bytes */ + change_tpdu_state(TPDU_S_DATA_REMAINING); break; - } else if ((~tpdu_packet[1]) == byte) { /* get single data byte */ - tpdu_state = TPDU_S_DATA_SINGLE; + } else if ((~g_tpdu.packet[1]) == byte) { /* get single data byte */ + change_tpdu_state(TPDU_S_DATA_SINGLE); break; } case TPDU_S_SW1: if ((0x60 == (byte & 0xf0)) || (0x90 == (byte & 0xf0))) { /* this procedure byte is SW1 */ - tpdu_packet[tpdu_packet_i++] = byte; - tpdu_state = TPDU_S_SW2; + g_tpdu.packet[g_tpdu.packet_i++] = byte; + change_tpdu_state(TPDU_S_SW2); } else { TRACE_WARNING("invalid SW1 0x%02x\n\r", byte); led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */ @@ -781,28 +792,28 @@ static void process_byte_tpdu(uint8_t byte) } break; case TPDU_S_SW2: - tpdu_packet[tpdu_packet_i++] = byte; + g_tpdu.packet[g_tpdu.packet_i++] = byte; usb_send_tpdu(0); /* send TPDU to host software using USB */ change_state(ISO7816_S_WAIT_TPDU); /* this is the end of the TPDU */ break; case TPDU_S_DATA_SINGLE: case TPDU_S_DATA_REMAINING: - tpdu_packet[tpdu_packet_i++] = byte; - if (0 == tpdu_packet[4]) { - if (5+256 <= tpdu_packet_i) { - tpdu_state = TPDU_S_PROCEDURE; + g_tpdu.packet[g_tpdu.packet_i++] = byte; + if (0 == g_tpdu.packet[4]) { + if (5+256 <= g_tpdu.packet_i) { + change_tpdu_state(TPDU_S_PROCEDURE); } } else { - if (5+tpdu_packet[4] <= tpdu_packet_i) { - tpdu_state = TPDU_S_PROCEDURE; + if (5+g_tpdu.packet[4] <= g_tpdu.packet_i) { + change_tpdu_state(TPDU_S_PROCEDURE); } } - if (TPDU_S_DATA_SINGLE == tpdu_state) { - tpdu_state = TPDU_S_PROCEDURE; + if (TPDU_S_DATA_SINGLE == g_tpdu.state) { + change_tpdu_state(TPDU_S_PROCEDURE); } break; default: - TRACE_ERROR("unhandled TPDU state %u\n\r", tpdu_state); + TRACE_ERROR("unhandled TPDU state %u\n\r", g_tpdu.state); } } @@ -814,37 +825,37 @@ void Sniffer_usart_isr(void) /* Read channel status register */ uint32_t csr = sniff_usart.base->US_CSR; - /* Verify if there was an error */ - if (csr & US_CSR_OVRE) { - TRACE_WARNING("USART overrun error\n\r"); - sniff_usart.base->US_CR |= US_CR_RSTSTA; - } - if (csr & US_CSR_FRAME) { - TRACE_WARNING("USART framing error\n\r"); - sniff_usart.base->US_CR |= US_CR_RSTSTA; - } + + uint16_t byte = 0; /* Verify if character has been received */ if (csr & US_CSR_RXRDY) { /* Read communication data byte between phone and SIM */ - uint8_t byte = sniff_usart.base->US_RHR; + byte = RBUF16_F_DATA_BYTE | (sniff_usart.base->US_RHR & 0xff); /* Reset WT timer */ - wt_remaining = wt; - /* Store sniffed data into buffer (also clear interrupt */ - if (rbuf_is_full(&sniff_buffer)) { - TRACE_ERROR("USART buffer full\n\r"); - } else { - rbuf_write(&sniff_buffer, byte); - } + wt_remaining = g_wt; } + /* Verify if there was an error */ + if (csr & US_CSR_OVRE) + byte |= RBUF16_F_OVERRUN; + if (csr & US_CSR_FRAME) + byte |= RBUF16_F_FRAMING; + if (csr & US_CSR_PARE) + byte |= RBUF16_F_PARITY; + + if (csr & (US_CSR_OVRE|US_CSR_FRAME|US_CSR_PARE)) + sniff_usart.base->US_CR |= US_CR_RSTSTA; + /* Verify it WT timeout occurred, to detect unresponsive card */ if (csr & US_CSR_TIMEOUT) { if (wt_remaining <= (sniff_usart.base->US_RTOR & 0xffff)) { + /* ensure the timeout is enqueued in the ring-buffer */ + byte |= RBUF16_F_TIMEOUT_WT; /* Just set the flag and let the main loop handle it */ change_flags |= SNIFF_CHANGE_FLAG_TIMEOUT_WT; /* Reset timeout value */ - wt_remaining = wt; + wt_remaining = g_wt; } else { wt_remaining -= (sniff_usart.base->US_RTOR & 0xffff); /* be sure to subtract the actual timeout since the new might not have been set and reloaded yet */ } @@ -860,6 +871,12 @@ void Sniffer_usart_isr(void) sniff_usart.base->US_CR |= US_CR_RETTO; } } + + /* Store sniffed data (or error flags, or both) into buffer */ + if (byte) { + if (rbuf16_write(&sniff_buffer, byte) != 0) + TRACE_ERROR("USART buffer full\n\r"); + } } /** PIO interrupt service routine to checks if the card reset line has changed @@ -901,6 +918,8 @@ void Sniffer_usart0_irq(void) * Initialization routine *-----------------------------------------------------------------------------*/ +#define SNIFFER_IER (US_IER_RXRDY | US_IER_TIMEOUT | US_IER_OVRE | US_IER_FRAME | US_IER_PARE) + /* Called during USB enumeration after device is enumerated by host */ void Sniffer_configure(void) { @@ -912,7 +931,7 @@ void Sniffer_exit(void) { TRACE_INFO("Sniffer exit\n\r"); /* Disable USART */ - USART_DisableIt(sniff_usart.base, US_IER_RXRDY); + USART_DisableIt(sniff_usart.base, SNIFFER_IER); /* NOTE: don't forget to set the IRQ according to the USART peripheral used */ NVIC_DisableIRQ(IRQ_USART_SIM); USART_SetReceiverEnabled(sniff_usart.base, 0); @@ -940,15 +959,15 @@ void Sniffer_init(void) PIO_EnableIt(&pin_rst); /* Clear ring buffer containing the sniffed data */ - rbuf_reset(&sniff_buffer); + rbuf16_reset(&sniff_buffer); /* Configure USART to as ISO-7816 slave communication to sniff communication */ ISO7816_Init(&sniff_usart, CLK_SLAVE); /* Only receive data when sniffing */ USART_SetReceiverEnabled(sniff_usart.base, 1); /* Enable Receiver time-out to detect waiting time (WT) time-out (e.g. unresponsive cards) */ - sniff_usart.base->US_RTOR = wt; + sniff_usart.base->US_RTOR = g_wt; /* Enable interrupt to indicate when data has been received or timeout occurred */ - USART_EnableIt(sniff_usart.base, US_IER_RXRDY | US_IER_TIMEOUT); + USART_EnableIt(sniff_usart.base, SNIFFER_IER); /* Set USB priority lower than USART to not miss sniffing data (both at 0 per default) */ if (NVIC_GetPriority(IRQ_USART_SIM) >= NVIC_GetPriority(UDP_IRQn)) { NVIC_SetPriority(UDP_IRQn, NVIC_GetPriority(IRQ_USART_SIM) + 2); @@ -1006,101 +1025,114 @@ void Sniffer_run(void) * is remaining */ /* Handle sniffed data */ - if (!rbuf_is_empty(&sniff_buffer)) { /* use if instead of while to let the main loop restart the watchdog */ - uint8_t byte = rbuf_read(&sniff_buffer); - /* Convert convention if required */ - if (convention_convert) { - byte = convention_convert_lut[byte]; - } - //TRACE_ERROR_WP(">%02x", byte); - switch (iso_state) { /* Handle byte depending on state */ - case ISO7816_S_RESET: /* During reset we shouldn't receive any data */ - break; - case ISO7816_S_WAIT_ATR: /* After a reset we expect the ATR */ - change_state(ISO7816_S_IN_ATR); /* go to next state */ - case ISO7816_S_IN_ATR: /* More ATR data incoming */ - process_byte_atr(byte); - break; - case ISO7816_S_WAIT_TPDU: /* After the ATR we expect TPDU or PPS data */ - case ISO7816_S_WAIT_PPS_RSP: - if (0xff == byte) { - if (ISO7816_S_WAIT_PPS_RSP == iso_state) { - change_state(ISO7816_S_IN_PPS_RSP); /* Go to PPS state */ - } else { - change_state(ISO7816_S_IN_PPS_REQ); /* Go to PPS state */ + if (!rbuf16_is_empty(&sniff_buffer)) { /* use if instead of while to let the main loop restart the watchdog */ + uint16_t entry = rbuf16_read(&sniff_buffer); + + if (entry & RBUF16_F_DATA_BYTE) { + uint8_t byte = entry & 0xff; + /* Convert convention if required */ + if (convention_convert) { + byte = convention_convert_lut[byte]; + } + + //TRACE_ERROR_WP(">%02x", byte); + switch (iso_state) { /* Handle byte depending on state */ + case ISO7816_S_RESET: /* During reset we shouldn't receive any data */ + break; + case ISO7816_S_WAIT_ATR: /* After a reset we expect the ATR */ + change_state(ISO7816_S_IN_ATR); /* go to next state */ + case ISO7816_S_IN_ATR: /* More ATR data incoming */ + process_byte_atr(byte); + break; + case ISO7816_S_WAIT_TPDU: /* After the ATR we expect TPDU or PPS data */ + case ISO7816_S_WAIT_PPS_RSP: + if (0xff == byte) { + if (ISO7816_S_WAIT_PPS_RSP == iso_state) { + change_state(ISO7816_S_IN_PPS_RSP); /* Go to PPS state */ + } else { + change_state(ISO7816_S_IN_PPS_REQ); /* Go to PPS state */ + } + process_byte_pps(byte); + break; + } + case ISO7816_S_IN_TPDU: /* More TPDU data incoming */ + if (ISO7816_S_WAIT_TPDU == iso_state) { + change_state(ISO7816_S_IN_TPDU); } + process_byte_tpdu(byte); + break; + case ISO7816_S_IN_PPS_REQ: + case ISO7816_S_IN_PPS_RSP: process_byte_pps(byte); break; + default: + TRACE_ERROR("Data received in unknown state %u\n\r", iso_state); } - case ISO7816_S_IN_TPDU: /* More TPDU data incoming */ - if (ISO7816_S_WAIT_TPDU == iso_state) { - change_state(ISO7816_S_IN_TPDU); - } - process_byte_tpdu(byte); - break; - case ISO7816_S_IN_PPS_REQ: - case ISO7816_S_IN_PPS_RSP: - process_byte_pps(byte); - break; - default: - TRACE_ERROR("Data received in unknown state %u\n\r", iso_state); } - } - /* Handle flags */ - if (change_flags) { /* WARNING this is not synced with the data buffer handling */ - if (change_flags & SNIFF_CHANGE_FLAG_RESET_ASSERT) { + /* Use timeout to detect interrupted data transmission */ + if (entry & RBUF16_F_TIMEOUT_WT) { + TRACE_ERROR("USART TIMEOUT Error\n\r"); switch (iso_state) { case ISO7816_S_IN_ATR: led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */ usb_send_atr(SNIFF_DATA_FLAG_ERROR_INCOMPLETE); /* send incomplete ATR to host software using USB */ + change_state(ISO7816_S_WAIT_ATR); break; case ISO7816_S_IN_TPDU: led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */ usb_send_tpdu(SNIFF_DATA_FLAG_ERROR_INCOMPLETE); /* send incomplete PPS to host software using USB */ + change_state(ISO7816_S_WAIT_TPDU); break; case ISO7816_S_IN_PPS_REQ: case ISO7816_S_IN_PPS_RSP: led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */ usb_send_pps(SNIFF_DATA_FLAG_ERROR_INCOMPLETE); /* send incomplete TPDU to host software using USB */ + change_state(ISO7816_S_WAIT_TPDU); break; default: break; } - if (ISO7816_S_RESET != iso_state) { - change_state(ISO7816_S_RESET); - printf("reset asserted\n\r"); - } } - if (change_flags & SNIFF_CHANGE_FLAG_RESET_DEASSERT) { - if (ISO7816_S_WAIT_ATR != iso_state) { - change_state(ISO7816_S_WAIT_ATR); - printf("reset de-asserted\n\r"); - } - } - if (change_flags & SNIFF_CHANGE_FLAG_TIMEOUT_WT) { - /* Use timeout to detect interrupted data transmission */ + + if (entry & RBUF16_F_PARITY) + TRACE_ERROR("USART PARITY Error\r\n"); + if (entry & RBUF16_F_FRAMING) + TRACE_ERROR("USART FRAMING Error\r\n"); + if (entry & RBUF16_F_OVERRUN) + TRACE_ERROR("USART OVERRUN Error\r\n"); + } + + /* Handle flags */ + if (change_flags) { /* WARNING this is not synced with the data buffer handling */ + if (change_flags & SNIFF_CHANGE_FLAG_RESET_ASSERT) { switch (iso_state) { case ISO7816_S_IN_ATR: led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */ usb_send_atr(SNIFF_DATA_FLAG_ERROR_INCOMPLETE); /* send incomplete ATR to host software using USB */ - change_state(ISO7816_S_WAIT_ATR); break; case ISO7816_S_IN_TPDU: led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */ usb_send_tpdu(SNIFF_DATA_FLAG_ERROR_INCOMPLETE); /* send incomplete PPS to host software using USB */ - change_state(ISO7816_S_WAIT_TPDU); break; case ISO7816_S_IN_PPS_REQ: case ISO7816_S_IN_PPS_RSP: led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */ usb_send_pps(SNIFF_DATA_FLAG_ERROR_INCOMPLETE); /* send incomplete TPDU to host software using USB */ - change_state(ISO7816_S_WAIT_TPDU); break; default: - change_flags &= ~SNIFF_CHANGE_FLAG_TIMEOUT_WT; /* We don't care about the timeout is all other cases */ break; } + if (ISO7816_S_RESET != iso_state) { + change_state(ISO7816_S_RESET); + printf("reset asserted\n\r"); + } + } + if (change_flags & SNIFF_CHANGE_FLAG_RESET_DEASSERT) { + if (ISO7816_S_WAIT_ATR != iso_state) { + change_state(ISO7816_S_WAIT_ATR); + printf("reset de-asserted\n\r"); + } } if (change_flags) { usb_send_change(change_flags); /* send timeout to host software over USB */ diff --git a/firmware/libcommon/source/stack_check.c b/firmware/libcommon/source/stack_check.c new file mode 100644 index 0000000..3130dd8 --- /dev/null +++ b/firmware/libcommon/source/stack_check.c @@ -0,0 +1,14 @@ +#include <stdint.h> +#include <osmocom/core/panic.h> + +/* This is what's minimally required to fix builds on Ubuntu 20.04, + * where stack smashing protection is enabled by default when using dpkg + * - even when cross-compiling: https://osmocom.org/issues/4687 + */ + +uintptr_t __stack_chk_guard = 0xdeadbeef; + +void __stack_chk_fail(void) +{ + osmo_panic("Stack smashing detected!\r\n"); +} diff --git a/firmware/libcommon/source/stdio.c b/firmware/libcommon/source/stdio.c index a8612d1..1002c2d 100644 --- a/firmware/libcommon/source/stdio.c +++ b/firmware/libcommon/source/stdio.c @@ -358,6 +358,7 @@ signed int vsnprintf(char *pStr, size_t length, const char *pFormat, va_list ap) case 'i': num = PutSignedInt(pStr, fill, width, va_arg(ap, signed int)); break; case 'u': num = PutUnsignedInt(pStr, fill, width, va_arg(ap, unsigned int)); break; case 'x': num = PutHexa(pStr, fill, width, 0, va_arg(ap, unsigned int)); break; + case 'p': num = PutHexa(pStr, fill, width, 0, va_arg(ap, unsigned long)); break; case 'X': num = PutHexa(pStr, fill, width, 1, va_arg(ap, unsigned int)); break; case 's': num = PutString(pStr, va_arg(ap, char *)); break; case 'c': num = PutChar(pStr, va_arg(ap, unsigned int)); break; diff --git a/firmware/libcommon/source/tc_etu.c b/firmware/libcommon/source/tc_etu.c index 04a7324..a48da8c 100644 --- a/firmware/libcommon/source/tc_etu.c +++ b/firmware/libcommon/source/tc_etu.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #include <stdint.h> diff --git a/firmware/libcommon/source/usb.c b/firmware/libcommon/source/usb.c index 43c7bb2..25b35cf 100644 --- a/firmware/libcommon/source/usb.c +++ b/firmware/libcommon/source/usb.c @@ -2,7 +2,7 @@ * ATMEL Microcontroller Software Support * ---------------------------------------------------------------------------- * Copyright (c) 2009, Atmel Corporation - * Copyright (c) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de> + * Copyright (c) 2018-2019, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de> * * All rights reserved. * @@ -46,7 +46,10 @@ * USB String descriptors *------------------------------------------------------------------------------*/ #include "usb_strings_generated.h" + +// the index of the strings (must match the order in usb_strings.txt) enum strDescNum { + // static strings from usb_strings MANUF_STR = 1, PRODUCT_STRING, SNIFFER_CONF_STR, @@ -55,9 +58,82 @@ enum strDescNum { MITM_CONF_STR, CARDEM_USIM1_INTF_STR, CARDEM_USIM2_INTF_STR, + CARDEM_USIM3_INTF_STR, + CARDEM_USIM4_INTF_STR, + // runtime strings + SERIAL_STR, + VERSION_CONF_STR, + VERSION_STR, + // count STRING_DESC_CNT }; +/** array of static (from usb_strings) and runtime (serial, version) USB strings + */ +static const unsigned char *usb_strings_extended[ARRAY_SIZE(usb_strings) + 3]; + +/* USB string for the serial (using 128-bit device ID) */ +static unsigned char usb_string_serial[] = { + USBStringDescriptor_LENGTH(32), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('0'), + USBStringDescriptor_UNICODE('0'), + USBStringDescriptor_UNICODE('1'), + USBStringDescriptor_UNICODE('1'), + USBStringDescriptor_UNICODE('2'), + USBStringDescriptor_UNICODE('2'), + USBStringDescriptor_UNICODE('3'), + USBStringDescriptor_UNICODE('3'), + USBStringDescriptor_UNICODE('4'), + USBStringDescriptor_UNICODE('4'), + USBStringDescriptor_UNICODE('5'), + USBStringDescriptor_UNICODE('5'), + USBStringDescriptor_UNICODE('6'), + USBStringDescriptor_UNICODE('6'), + USBStringDescriptor_UNICODE('7'), + USBStringDescriptor_UNICODE('7'), + USBStringDescriptor_UNICODE('8'), + USBStringDescriptor_UNICODE('8'), + USBStringDescriptor_UNICODE('9'), + USBStringDescriptor_UNICODE('9'), + USBStringDescriptor_UNICODE('a'), + USBStringDescriptor_UNICODE('a'), + USBStringDescriptor_UNICODE('b'), + USBStringDescriptor_UNICODE('b'), + USBStringDescriptor_UNICODE('c'), + USBStringDescriptor_UNICODE('c'), + USBStringDescriptor_UNICODE('d'), + USBStringDescriptor_UNICODE('d'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('f'), + USBStringDescriptor_UNICODE('f'), +}; + +/* USB string for the version */ +static const unsigned char usb_string_version_conf[] = { + USBStringDescriptor_LENGTH(16), + USBGenericDescriptor_STRING, + USBStringDescriptor_UNICODE('f'), + USBStringDescriptor_UNICODE('i'), + USBStringDescriptor_UNICODE('r'), + USBStringDescriptor_UNICODE('m'), + USBStringDescriptor_UNICODE('w'), + USBStringDescriptor_UNICODE('a'), + USBStringDescriptor_UNICODE('r'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE(' '), + USBStringDescriptor_UNICODE('v'), + USBStringDescriptor_UNICODE('e'), + USBStringDescriptor_UNICODE('r'), + USBStringDescriptor_UNICODE('s'), + USBStringDescriptor_UNICODE('i'), + USBStringDescriptor_UNICODE('o'), + USBStringDescriptor_UNICODE('n'), +}; +static const char git_version[] = GIT_VERSION; +static unsigned char usb_string_version[2 + ARRAY_SIZE(git_version) * 2 - 2]; + /*------------------------------------------------------------------------------ * USB Device descriptors *------------------------------------------------------------------------------*/ @@ -130,7 +206,7 @@ static const SIMTraceDriverConfigurationDescriptorSniffer SIMTRACE_USB_EP_CARD_INT), .bmAttributes = USBEndpointDescriptor_INTERRUPT, .wMaxPacketSize = USBEndpointDescriptor_MAXINTERRUPTSIZE_FS, - .bInterval = 0x10, + .bInterval = 1, }, DFURT_IF_DESCRIPTOR(1, 0), }; @@ -306,7 +382,7 @@ static const SIMTraceDriverConfigurationDescriptorPhone SIMTRACE_CARDEM_USB_EP_USIM1_INT), .bmAttributes = USBEndpointDescriptor_INTERRUPT, .wMaxPacketSize = USBEndpointDescriptor_MAXINTERRUPTSIZE_FS, - .bInterval = 0x10 + .bInterval = 1 }, #ifdef CARDEMU_SECOND_UART /* Communication class interface standard descriptor */ @@ -353,7 +429,7 @@ static const SIMTraceDriverConfigurationDescriptorPhone SIMTRACE_CARDEM_USB_EP_USIM2_INT), .bmAttributes = USBEndpointDescriptor_INTERRUPT, .wMaxPacketSize = USBEndpointDescriptor_MAXINTERRUPTSIZE_FS, - .bInterval = 0x10, + .bInterval = 1, }, DFURT_IF_DESCRIPTOR(2, 0), #else @@ -471,7 +547,7 @@ static const SIMTraceDriverConfigurationDescriptorMITM CCID_EPT_NOTIFICATION), .bmAttributes = USBEndpointDescriptor_INTERRUPT, .wMaxPacketSize = USBEndpointDescriptor_MAXINTERRUPTSIZE_FS, - .bInterval = 0x10, + .bInterval = 1, }, /* Communication class interface standard descriptor */ @@ -517,12 +593,46 @@ static const SIMTraceDriverConfigurationDescriptorMITM SIMTRACE_USB_EP_PHONE_INT), .bmAttributes = USBEndpointDescriptor_INTERRUPT, .wMaxPacketSize = USBEndpointDescriptor_MAXINTERRUPTSIZE_FS, - .bInterval = 0x10 + .bInterval = 1 }, DFURT_IF_DESCRIPTOR(2, 0), }; #endif /* HAVE_CARDEM */ +/* USB descriptor just to show the version */ +typedef struct _SIMTraceDriverConfigurationDescriptorVersion { + /** Standard configuration descriptor. */ + USBConfigurationDescriptor configuration; + USBInterfaceDescriptor version; +} __attribute__ ((packed)) SIMTraceDriverConfigurationDescriptorVersion; + +static const SIMTraceDriverConfigurationDescriptorVersion + configurationDescriptorVersion = { + /* Standard configuration descriptor for the interface descriptor*/ + .configuration = { + .bLength = sizeof(USBConfigurationDescriptor), + .bDescriptorType = USBGenericDescriptor_CONFIGURATION, + .wTotalLength = sizeof(SIMTraceDriverConfigurationDescriptorVersion), + .bNumInterfaces = 1, + .bConfigurationValue = CFG_NUM_VERSION, + .iConfiguration = VERSION_CONF_STR, + .bmAttributes = USBD_BMATTRIBUTES, + .bMaxPower = USBConfigurationDescriptor_POWER(100), + }, + /* Interface standard descriptor just holding the version information */ + .version = { + .bLength = sizeof(USBInterfaceDescriptor), + .bDescriptorType = USBGenericDescriptor_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = USB_CLASS_PROPRIETARY, + .bInterfaceSubClass = 0xff, + .bInterfaceProtocol = 0, + .iInterface = VERSION_STR, + }, +}; + const USBConfigurationDescriptor *configurationDescriptorsArr[] = { #ifdef HAVE_SNIFFER &configurationDescriptorSniffer.configuration, @@ -536,6 +646,7 @@ const USBConfigurationDescriptor *configurationDescriptorsArr[] = { #ifdef HAVE_MITM &configurationDescriptorMITM.configuration, #endif + &configurationDescriptorVersion.configuration, }; /** Standard USB device descriptor for the CDC serial driver */ @@ -552,7 +663,7 @@ const USBDeviceDescriptor deviceDescriptor = { .bcdDevice = 2, /* Release number */ .iManufacturer = MANUF_STR, .iProduct = PRODUCT_STRING, - .iSerialNumber = 0, + .iSerialNumber = SERIAL_STR, .bNumConfigurations = ARRAY_SIZE(configurationDescriptorsArr), }; @@ -566,8 +677,8 @@ static const USBDDriverDescriptors driverDescriptors = { 0, /* No high-speed configuration descriptor */ 0, /* No high-speed device qualifier descriptor */ 0, /* No high-speed other speed configuration descriptor */ - usb_strings, - ARRAY_SIZE(usb_strings),/* cnt string descriptors in list */ + usb_strings_extended, + ARRAY_SIZE(usb_strings_extended),/* cnt string descriptors in list */ }; /*---------------------------------------------------------------------------- @@ -576,23 +687,42 @@ static const USBDDriverDescriptors driverDescriptors = { void SIMtrace_USB_Initialize(void) { - + unsigned int i; /* Signal USB reset by disabling the pull-up on USB D+ for at least 10 ms */ -#ifdef PIN_USB_PULLUP - const Pin usb_dp_pullup = PIN_USB_PULLUP; - PIO_Configure(&usb_dp_pullup, 1); - PIO_Set(&usb_dp_pullup); -#endif + USBD_HAL_Disconnect(); USBD_HAL_Suspend(); - mdelay(20); -#ifdef PIN_USB_PULLUP - PIO_Clear(&usb_dp_pullup); -#endif + mdelay(500); USBD_HAL_Activate(); // Get std USB driver USBDDriver *pUsbd = USBD_GetDriver(); + // put device ID into USB serial number description + unsigned int device_id[4]; + EEFC_ReadUniqueID(device_id); + char device_id_string[32 + 1]; + snprintf(device_id_string, ARRAY_SIZE(device_id_string), "%08x%08x%08x%08x", + device_id[0], device_id[1], device_id[2], device_id[3]); + for (i = 0; i < ARRAY_SIZE(device_id_string) - 1; i++) { + usb_string_serial[2 + 2 * i] = device_id_string[i]; + } + + // put version into USB string + usb_string_version[0] = USBStringDescriptor_LENGTH(ARRAY_SIZE(git_version) - 1); + usb_string_version[1] = USBGenericDescriptor_STRING; + for (i = 0; i < ARRAY_SIZE(git_version) - 1; i++) { + usb_string_version[2 + i * 2 + 0] = git_version[i]; + usb_string_version[2 + i * 2 + 1] = 0; + } + + // fill extended USB strings + for (i = 0; i < ARRAY_SIZE(usb_strings) && i < ARRAY_SIZE(usb_strings_extended); i++) { + usb_strings_extended[i] = usb_strings[i]; + } + usb_strings_extended[SERIAL_STR] = usb_string_serial; + usb_strings_extended[VERSION_CONF_STR] = usb_string_version_conf; + usb_strings_extended[VERSION_STR] = usb_string_version; + // Initialize standard USB driver USBDDriver_Initialize(pUsbd, &driverDescriptors, 0); // Multiple interface settings not supported USBD_Init(); diff --git a/firmware/libcommon/source/usb_buf.c b/firmware/libcommon/source/usb_buf.c index 418569e..72eae54 100644 --- a/firmware/libcommon/source/usb_buf.c +++ b/firmware/libcommon/source/usb_buf.c @@ -9,10 +9,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA */ #include "board.h" #include "trace.h" @@ -24,6 +20,7 @@ #include <errno.h> #define USB_ALLOC_SIZE 280 +#define USB_MAX_QLEN 3 static struct usb_buffered_ep usb_buffered_ep[BOARD_USB_NUMENDPOINTS]; @@ -78,7 +75,18 @@ int usb_buf_submit(struct msgb *msg) /* no need for irqsafe operation, as the usb_tx_queue is * processed only by the main loop context */ - msgb_enqueue(&ep->queue, msg); + + if (ep->queue_len >= USB_MAX_QLEN) { + struct msgb *evict; + /* free the first pending buffer in the queue */ + TRACE_INFO("EP%02x: dropping first queue element (qlen=%u)\r\n", + ep->ep, ep->queue_len); + evict = msgb_dequeue_count(&ep->queue, &ep->queue_len); + OSMO_ASSERT(evict); + usb_buf_free(evict); + } + + msgb_enqueue_count(&ep->queue, msg, &ep->queue_len); return 0; } @@ -89,5 +97,6 @@ void usb_buf_init(void) for (i = 0; i < ARRAY_SIZE(usb_buffered_ep); i++) { struct usb_buffered_ep *ep = &usb_buffered_ep[i]; INIT_LLIST_HEAD(&ep->queue); + ep->ep = i; } } diff --git a/firmware/libosmocore/include/osmocom/core/bit16gen.h b/firmware/libosmocore/include/osmocom/core/bit16gen.h index 5c6162c..ed47285 100644 --- a/firmware/libosmocore/include/osmocom/core/bit16gen.h +++ b/firmware/libosmocore/include/osmocom/core/bit16gen.h @@ -14,10 +14,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once diff --git a/firmware/libosmocore/include/osmocom/core/bit32gen.h b/firmware/libosmocore/include/osmocom/core/bit32gen.h index 6640e76..12abb72 100644 --- a/firmware/libosmocore/include/osmocom/core/bit32gen.h +++ b/firmware/libosmocore/include/osmocom/core/bit32gen.h @@ -14,10 +14,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once diff --git a/firmware/libosmocore/include/osmocom/core/bit64gen.h b/firmware/libosmocore/include/osmocom/core/bit64gen.h index 8c7b709..2aa2a2e 100644 --- a/firmware/libosmocore/include/osmocom/core/bit64gen.h +++ b/firmware/libosmocore/include/osmocom/core/bit64gen.h @@ -14,10 +14,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once diff --git a/firmware/libosmocore/include/osmocom/core/linuxrbtree.h b/firmware/libosmocore/include/osmocom/core/linuxrbtree.h index d3f9fd1..4212109 100644 --- a/firmware/libosmocore/include/osmocom/core/linuxrbtree.h +++ b/firmware/libosmocore/include/osmocom/core/linuxrbtree.h @@ -11,10 +11,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. linux/include/linux/rbtree.h diff --git a/firmware/libosmocore/include/osmocom/core/msgb.h b/firmware/libosmocore/include/osmocom/core/msgb.h index afb887c..dadf487 100644 --- a/firmware/libosmocore/include/osmocom/core/msgb.h +++ b/firmware/libosmocore/include/osmocom/core/msgb.h @@ -13,10 +13,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * */ #include <stdint.h> @@ -80,6 +76,49 @@ extern int msgb_resize_area(struct msgb *msg, uint8_t *area, extern struct msgb *msgb_copy(const struct msgb *msg, const char *name); static int msgb_test_invariant(const struct msgb *msg) __attribute__((pure)); +/*! Free all msgbs from a queue built with msgb_enqueue(). + * \param[in] queue list head of a msgb queue. + */ +static inline void msgb_queue_free(struct llist_head *queue) +{ + struct msgb *msg; + while ((msg = msgb_dequeue(queue))) msgb_free(msg); +} + +/*! Enqueue message buffer to tail of a queue and increment queue size counter + * \param[in] queue linked list header of queue + * \param[in] msg message buffer to be added to the queue + * \param[in] count pointer to variable holding size of the queue + * + * The function will append the specified message buffer \a msg to the queue + * implemented by \ref llist_head \a queue using function \ref msgb_enqueue_count, + * then increment \a count + */ +static inline void msgb_enqueue_count(struct llist_head *queue, struct msgb *msg, + unsigned int *count) +{ + msgb_enqueue(queue, msg); + (*count)++; +} + +/*! Dequeue message buffer from head of queue and decrement queue size counter + * \param[in] queue linked list header of queue + * \param[in] count pointer to variable holding size of the queue + * \returns message buffer (if any) or NULL if queue empty + * + * The function will remove the first message buffer from the queue + * implemented by \ref llist_head \a queue using function \ref msgb_enqueue_count, + * and decrement \a count, all if queue is not empty. + */ +static inline struct msgb *msgb_dequeue_count(struct llist_head *queue, + unsigned int *count) +{ + struct msgb *msg = msgb_dequeue(queue); + if (msg) + (*count)--; + return msg; +} + #ifdef MSGB_DEBUG #include <osmocom/core/panic.h> #define MSGB_ABORT(msg, fmt, args ...) do { \ diff --git a/firmware/libosmocore/include/osmocom/core/timer.h b/firmware/libosmocore/include/osmocom/core/timer.h index 6d70fff..6bd95a7 100644 --- a/firmware/libosmocore/include/osmocom/core/timer.h +++ b/firmware/libosmocore/include/osmocom/core/timer.h @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * */ /*! \defgroup timer Osmocom timers diff --git a/firmware/libosmocore/source/backtrace.c b/firmware/libosmocore/source/backtrace.c index 5d6dc4a..3938d7a 100644 --- a/firmware/libosmocore/source/backtrace.c +++ b/firmware/libosmocore/source/backtrace.c @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * */ /*! \file backtrace.c diff --git a/firmware/libosmocore/source/bits.c b/firmware/libosmocore/source/bits.c index 0c77b27..5fa9488 100644 --- a/firmware/libosmocore/source/bits.c +++ b/firmware/libosmocore/source/bits.c @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * */ #include <stdint.h> diff --git a/firmware/libosmocore/source/msgb.c b/firmware/libosmocore/source/msgb.c index a27100c..fcdda87 100644 --- a/firmware/libosmocore/source/msgb.c +++ b/firmware/libosmocore/source/msgb.c @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * */ /*! \addtogroup msgb diff --git a/firmware/libosmocore/source/panic.c b/firmware/libosmocore/source/panic.c index 74243b0..589464a 100644 --- a/firmware/libosmocore/source/panic.c +++ b/firmware/libosmocore/source/panic.c @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * */ /*! \addtogroup utils @@ -46,7 +42,7 @@ static osmo_panic_handler_t osmo_panic_handler = (void*)0; __attribute__ ((format (printf, 1, 0))) static void osmo_panic_default(const char *fmt, va_list args) { - vfprintf(stderr, fmt, args); + vfprintf_sync(stderr, fmt, args); osmo_generate_backtrace(); assert(0); } diff --git a/firmware/libosmocore/source/rbtree.c b/firmware/libosmocore/source/rbtree.c index f0ebb8c..a8969f4 100644 --- a/firmware/libosmocore/source/rbtree.c +++ b/firmware/libosmocore/source/rbtree.c @@ -12,10 +12,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA linux/lib/rbtree.c diff --git a/firmware/libosmocore/source/timer.c b/firmware/libosmocore/source/timer.c index 75c7d45..eb43884 100644 --- a/firmware/libosmocore/source/timer.c +++ b/firmware/libosmocore/source/timer.c @@ -17,10 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * */ diff --git a/firmware/libosmocore/source/utils.c b/firmware/libosmocore/source/utils.c index 3096572..f519df7 100644 --- a/firmware/libosmocore/source/utils.c +++ b/firmware/libosmocore/source/utils.c @@ -17,10 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * */ diff --git a/firmware/misc/crctool.c b/firmware/misc/crctool.c new file mode 100644 index 0000000..2602753 --- /dev/null +++ b/firmware/misc/crctool.c @@ -0,0 +1,91 @@ +/* SIMtrace 2 firmware crc tool + * + * (C) 2021 by sysmocom -s.f.m.c. GmbH, Author: Eric Wild <ewild@sysmocom.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +static void do_crc32(int8_t c, uint32_t *crc_reg) +{ + int32_t i, mask; + *crc_reg ^= c; + + for (unsigned int j = 0; j < 8; j++) + if (*crc_reg & 1) + *crc_reg = (*crc_reg >> 1) ^ 0xEDB88320; + else + *crc_reg = *crc_reg >> 1; +} + +int main(int argc, char *argv[]) +{ + uint32_t crc_reg = 0xffffffff; + long fsize; + uint8_t *buffer; + uint32_t crc_start_offset; + + if (argc < 3) { + perror("usage: crctool startoffset blupdate.bin"); + return -1; + } + + crc_start_offset = strtoull(argv[1], 0, 10); + + FILE *blfile = fopen(argv[2], "rb+"); + if (blfile == NULL) { + perror("error opening file!"); + return -1; + } + + fseek(blfile, 0, SEEK_END); + fsize = ftell(blfile); + + if (fsize <= crc_start_offset) { + perror("file size?!"); + return -1; + } + + fseek(blfile, 0, SEEK_SET); + + buffer = malloc(fsize); + fread(buffer, 1, fsize, blfile); + + if (*(uint32_t *)buffer != 0xdeadc0de) { + perror("weird magic, not a valid blupdate file?"); + free(buffer); + return -1; + } + + uint8_t *startaddr = buffer + crc_start_offset; + uint8_t *endaddr = buffer + fsize; + for (uint8_t *i = startaddr; i < endaddr; i++) { + do_crc32(*i, &crc_reg); + } + crc_reg = ~crc_reg; + + fprintf(stderr, "len: %ld crc: %.8x\n", fsize - crc_start_offset, crc_reg); + + ((uint32_t *)buffer)[0] = 0x2000baa0; /* fix magic to valid stack address, checked by BL */ + ((uint32_t *)buffer)[2] = crc_reg; + ((uint32_t *)buffer)[3] = 0x00400000 + 0x4000 + crc_start_offset; + ((uint32_t *)buffer)[4] = fsize - crc_start_offset; + + fseek(blfile, 0, SEEK_SET); + fwrite(buffer, 4, 5, blfile); + + fclose(blfile); + free(buffer); + return 0; +} diff --git a/firmware/test/Makefile b/firmware/test/Makefile index d4c543a..4341c92 100644 --- a/firmware/test/Makefile +++ b/firmware/test/Makefile @@ -11,12 +11,12 @@ CFLAGS=-g -Wall $(LIBOSMOCORE_CFLAGS) \ -I../libboard/common/include \ -I../libboard/simtrace/include \ -I. -LDFLAGS=$(LIBOSMOCORE_LIBS) +LIBS=$(LIBOSMOCORE_LIBS) VPATH=../src_simtrace ../libcommon/source card_emu_test: card_emu_tests.hobj card_emu.hobj usb_buf.hobj iso7816_fidi.hobj - $(CC) $(LDFLAGS) -o $@ $^ + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) %.hobj: %.c $(CC) $(CFLAGS) -o $@ -c $^ diff --git a/firmware/test/card_emu_tests.c b/firmware/test/card_emu_tests.c index 09b2e0d..5d5bd3e 100644 --- a/firmware/test/card_emu_tests.c +++ b/firmware/test/card_emu_tests.c @@ -13,7 +13,23 @@ #define PHONE_INT 2 #define PHONE_DATAOUT 3 -/* stub functions required by card_emu.c */ +/* stub for stdio */ +signed int printf_sync(const char *pFormat, ...) +{ + va_list ap; + signed int result; + + va_start(ap, pFormat); + result = vprintf(pFormat, ap); + va_end(ap); + + return result; +} + + +/*********************************************************************** + * stub functions required by card_emu.c + ***********************************************************************/ void card_emu_uart_wait_tx_idle(uint8_t uart_chan) { @@ -30,6 +46,7 @@ int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi) static uint8_t tx_debug_buf[1024]; static unsigned int tx_debug_buf_idx; +/* the card emulator wants to send some data to the host [reader] */ int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte) { printf("UART_TX(%02x)\n", byte); @@ -37,13 +54,6 @@ int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte) return 1; } -static void reader_check_and_clear(const uint8_t *data, unsigned int len) -{ - assert(len == tx_debug_buf_idx); - assert(!memcmp(tx_debug_buf, data, len)); - tx_debug_buf_idx = 0; -} - void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx) { char *rts; @@ -54,6 +64,9 @@ void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx) case ENABLE_TX: rts = "TX"; break; + case ENABLE_TX_TIMER_ONLY: + rts = "TX-TIMER-ONLY"; + break; case ENABLE_RX: rts = "RX"; break; @@ -70,32 +83,31 @@ void card_emu_uart_interrupt(uint8_t uart_chan) printf("uart_interrupt(uart_chan=%u)\n", uart_chan); } -void tc_etu_set_wtime(uint8_t tc_chan, uint16_t wtime) +void card_emu_uart_update_wt(uint8_t uart_chan, uint32_t wt) { - printf("tc_etu_set_wtime(tc_chan=%u, wtime=%u)\n", tc_chan, wtime); + printf("%s(uart_chan=%u, wtime=%u)\n", __func__, uart_chan, wt); } -void tc_etu_set_etu(uint8_t tc_chan, uint16_t etu) +void card_emu_uart_reset_wt(uint8_t uart_chan) { - printf("tc_etu_set_etu(tc_chan=%u, etu=%u)\n", tc_chan, etu); + printf("%s(uart_chan=%u\n", __func__, uart_chan); } -void tc_etu_init(uint8_t chan_nr, void *handle) -{ - printf("tc_etu_init(tc_chan=%u)\n", chan_nr); -} -void tc_etu_enable(uint8_t chan_nr) -{ - printf("tc_etu_enable(tc_chan=%u)\n", chan_nr); -} -void tc_etu_disable(uint8_t chan_nr) +/*********************************************************************** + * test helper functions + ***********************************************************************/ + + +static void reader_check_and_clear(const uint8_t *data, unsigned int len) { - printf("tc_etu_disable(tc_chan=%u)\n", chan_nr); + assert(len == tx_debug_buf_idx); + assert(!memcmp(tx_debug_buf, data, len)); + tx_debug_buf_idx = 0; } -const uint8_t atr[] = { 0x3b, 0x02, 0x14, 0x50 }; +static const uint8_t atr[] = { 0x3b, 0x02, 0x14, 0x50 }; static int verify_atr(struct card_handle *ch) { @@ -126,10 +138,11 @@ static void io_start_card(struct card_handle *ch) /* release from reset and verify th ATR */ card_emu_io_statechg(ch, CARD_IO_RST, 0); /* simulate waiting time before ATR expired */ - tc_etu_wtime_expired(ch); + card_emu_wtime_expired(ch); verify_atr(ch); } +/* emulate the host/reader sending some bytes to the [emulated] card */ static void reader_send_bytes(struct card_handle *ch, const uint8_t *bytes, unsigned int len) { unsigned int i; @@ -166,14 +179,14 @@ static void dump_rctx(struct msgb *msg) static void get_and_verify_rctx(uint8_t ep, const uint8_t *data, unsigned int len) { - struct llist_head *queue = usb_get_queue(ep); + struct usb_buffered_ep *bep = usb_get_buf_ep(ep); struct msgb *msg; struct cardemu_usb_msg_tx_data *td; struct cardemu_usb_msg_rx_data *rd; struct simtrace_msg_hdr *mh; - assert(queue); - msg = msgb_dequeue(queue); + assert(bep); + msg = msgb_dequeue_count(&bep->queue, &bep->queue_len); assert(msg); dump_rctx(msg); assert(msg->l1h); @@ -203,13 +216,13 @@ static void get_and_verify_rctx(uint8_t ep, const uint8_t *data, unsigned int le static void get_and_verify_rctx_pps(const uint8_t *data, unsigned int len) { - struct llist_head *queue = usb_get_queue(PHONE_DATAIN); + struct usb_buffered_ep *bep = usb_get_buf_ep(PHONE_DATAIN); struct msgb *msg; struct simtrace_msg_hdr *mh; struct cardemu_usb_msg_pts_info *ptsi; - assert(queue); - msg = msgb_dequeue(queue); + assert(bep); + msg = msgb_dequeue_count(&bep->queue, &bep->queue_len); assert(msg); dump_rctx(msg); assert(msg->l1h); @@ -397,7 +410,7 @@ int main(int argc, char **argv) struct card_handle *ch; unsigned int i; - ch = card_emu_init(0, 23, 42, PHONE_DATAIN, PHONE_INT); + ch = card_emu_init(0, 42, PHONE_DATAIN, PHONE_INT, false, true, false); assert(ch); usb_buf_init(); diff --git a/firmware/usbstring/usbstring.c b/firmware/usbstring/usbstring.c index ed07568..e7c6c8c 100644 --- a/firmware/usbstring/usbstring.c +++ b/firmware/usbstring/usbstring.c @@ -10,10 +10,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Based on existing utf8_to_utf16le() function, diff --git a/hardware/board_gpio.gnumeric b/hardware/board_gpio.gnumeric index 1ec9ff6..17cc60f 100644 --- a/hardware/board_gpio.gnumeric +++ b/hardware/board_gpio.gnumeric @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <gnm:Workbook xmlns:gnm="http://www.gnumeric.org/v10.dtd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.gnumeric.org/v9.xsd"> - <gnm:Version Epoch="1" Major="12" Minor="44" Full="1.12.44"/> + <gnm:Version Epoch="1" Major="12" Minor="48" Full="1.12.48"/> <gnm:Attributes> <gnm:Attribute> <gnm:name>WorkbookView::show_horizontal_scrollbar</gnm:name> @@ -25,7 +25,7 @@ </gnm:Attributes> <office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:ooo="http://openoffice.org/2004/office" office:version="1.2"> <office:meta> - <dc:date>2019-02-28T17:12:35Z</dc:date> + <dc:date>2021-07-01T21:26:44Z</dc:date> <meta:creation-date>2017-03-05T18:42:38Z</meta:creation-date> </office:meta> </office:document-meta> @@ -39,7 +39,7 @@ <gnm:Sheets> <gnm:Sheet DisplayFormulas="0" HideZero="0" HideGrid="0" HideColHeader="0" HideRowHeader="0" DisplayOutlines="1" OutlineSymbolsBelow="1" OutlineSymbolsRight="1" Visibility="GNM_SHEET_VISIBILITY_VISIBLE" GridColor="0:0:0"> <gnm:Name>Sheet1</gnm:Name> - <gnm:MaxCol>9</gnm:MaxCol> + <gnm:MaxCol>13</gnm:MaxCol> <gnm:MaxRow>67</gnm:MaxRow> <gnm:Zoom>1</gnm:Zoom> <gnm:Names> @@ -82,132 +82,132 @@ <gnm:errors PrintErrorsAs="GNM_PRINT_ERRORS_AS_DISPLAYED"/> </gnm:PrintInformation> <gnm:Styles> - <gnm:StyleRegion startCol="0" startRow="0" endCol="1" endRow="5"> + <gnm:StyleRegion startCol="0" startRow="0" endCol="2" endRow="5"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="0" startRow="6" endCol="1" endRow="9"> + <gnm:StyleRegion startCol="0" startRow="6" endCol="2" endRow="9"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="0" startRow="10" endCol="1" endRow="11"> + <gnm:StyleRegion startCol="0" startRow="10" endCol="2" endRow="11"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="0" startRow="12" endCol="1" endRow="14"> + <gnm:StyleRegion startCol="0" startRow="12" endCol="2" endRow="14"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="0" startRow="15" endCol="1" endRow="15"> + <gnm:StyleRegion startCol="0" startRow="15" endCol="2" endRow="15"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="0" startRow="16" endCol="1" endRow="19"> + <gnm:StyleRegion startCol="0" startRow="16" endCol="2" endRow="19"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="0" startRow="20" endCol="1" endRow="21"> + <gnm:StyleRegion startCol="0" startRow="20" endCol="2" endRow="21"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="0" startRow="22" endCol="1" endRow="26"> + <gnm:StyleRegion startCol="0" startRow="22" endCol="2" endRow="26"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="0" startRow="27" endCol="1" endRow="27"> + <gnm:StyleRegion startCol="0" startRow="27" endCol="2" endRow="27"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="0" startRow="28" endCol="1" endRow="35"> + <gnm:StyleRegion startCol="0" startRow="28" endCol="2" endRow="35"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="0" startRow="36" endCol="1" endRow="36"> + <gnm:StyleRegion startCol="0" startRow="36" endCol="2" endRow="36"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="0" startRow="37" endCol="1" endRow="41"> + <gnm:StyleRegion startCol="0" startRow="37" endCol="2" endRow="41"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="0" startRow="42" endCol="1" endRow="43"> + <gnm:StyleRegion startCol="0" startRow="42" endCol="2" endRow="43"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="0" startRow="44" endCol="1" endRow="47"> + <gnm:StyleRegion startCol="0" startRow="44" endCol="2" endRow="47"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="0" startRow="48" endCol="1" endRow="49"> + <gnm:StyleRegion startCol="0" startRow="48" endCol="2" endRow="49"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="0" startRow="50" endCol="1" endRow="51"> + <gnm:StyleRegion startCol="0" startRow="50" endCol="2" endRow="51"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="0" startRow="52" endCol="1" endRow="54"> + <gnm:StyleRegion startCol="0" startRow="52" endCol="2" endRow="54"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="0" startRow="55" endCol="1" endRow="55"> + <gnm:StyleRegion startCol="0" startRow="55" endCol="2" endRow="55"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="0" startRow="56" endCol="1" endRow="57"> + <gnm:StyleRegion startCol="0" startRow="56" endCol="2" endRow="57"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="0" startRow="58" endCol="1" endRow="58"> + <gnm:StyleRegion startCol="0" startRow="58" endCol="2" endRow="58"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="0" startRow="59" endCol="1" endRow="61"> + <gnm:StyleRegion startCol="0" startRow="59" endCol="2" endRow="61"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="0" startRow="62" endCol="1" endRow="62"> + <gnm:StyleRegion startCol="0" startRow="62" endCol="2" endRow="62"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="0" startRow="63" endCol="1" endRow="63"> + <gnm:StyleRegion startCol="0" startRow="63" endCol="2" endRow="63"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="0" startRow="64" endCol="1" endRow="66"> + <gnm:StyleRegion startCol="0" startRow="64" endCol="2" endRow="66"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="0" startRow="67" endCol="1" endRow="65535"> + <gnm:StyleRegion startCol="0" startRow="67" endCol="2" endRow="65535"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="0" endCol="2" endRow="5"> + <gnm:StyleRegion startCol="3" startRow="0" endCol="3" endRow="5"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -215,7 +215,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="6" endCol="2" endRow="9"> + <gnm:StyleRegion startCol="3" startRow="6" endCol="3" endRow="9"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -223,7 +223,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="10" endCol="2" endRow="11"> + <gnm:StyleRegion startCol="3" startRow="10" endCol="3" endRow="11"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -231,7 +231,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="12" endCol="2" endRow="14"> + <gnm:StyleRegion startCol="3" startRow="12" endCol="3" endRow="14"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -239,7 +239,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="15" endCol="2" endRow="15"> + <gnm:StyleRegion startCol="3" startRow="15" endCol="3" endRow="15"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -247,7 +247,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="16" endCol="2" endRow="19"> + <gnm:StyleRegion startCol="3" startRow="16" endCol="3" endRow="19"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -255,7 +255,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="20" endCol="2" endRow="21"> + <gnm:StyleRegion startCol="3" startRow="20" endCol="3" endRow="21"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -263,7 +263,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="22" endCol="2" endRow="26"> + <gnm:StyleRegion startCol="3" startRow="22" endCol="3" endRow="26"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -271,7 +271,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="27" endCol="2" endRow="27"> + <gnm:StyleRegion startCol="3" startRow="27" endCol="3" endRow="27"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -279,7 +279,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="28" endCol="2" endRow="35"> + <gnm:StyleRegion startCol="3" startRow="28" endCol="3" endRow="35"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -287,7 +287,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="36" endCol="2" endRow="36"> + <gnm:StyleRegion startCol="3" startRow="36" endCol="3" endRow="36"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -295,7 +295,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="37" endCol="2" endRow="41"> + <gnm:StyleRegion startCol="3" startRow="37" endCol="3" endRow="41"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -303,7 +303,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="42" endCol="2" endRow="43"> + <gnm:StyleRegion startCol="3" startRow="42" endCol="3" endRow="43"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -311,7 +311,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="44" endCol="2" endRow="47"> + <gnm:StyleRegion startCol="3" startRow="44" endCol="3" endRow="47"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -319,7 +319,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="48" endCol="2" endRow="49"> + <gnm:StyleRegion startCol="3" startRow="48" endCol="3" endRow="49"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -327,7 +327,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="50" endCol="2" endRow="51"> + <gnm:StyleRegion startCol="3" startRow="50" endCol="3" endRow="51"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -335,7 +335,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="52" endCol="2" endRow="54"> + <gnm:StyleRegion startCol="3" startRow="52" endCol="3" endRow="54"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -343,7 +343,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="55" endCol="2" endRow="55"> + <gnm:StyleRegion startCol="3" startRow="55" endCol="3" endRow="55"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -351,7 +351,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="56" endCol="2" endRow="57"> + <gnm:StyleRegion startCol="3" startRow="56" endCol="3" endRow="57"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -359,7 +359,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="58" endCol="2" endRow="58"> + <gnm:StyleRegion startCol="3" startRow="58" endCol="3" endRow="58"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -367,7 +367,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="59" endCol="2" endRow="61"> + <gnm:StyleRegion startCol="3" startRow="59" endCol="3" endRow="61"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -375,7 +375,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="62" endCol="2" endRow="62"> + <gnm:StyleRegion startCol="3" startRow="62" endCol="3" endRow="62"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -383,7 +383,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="63" endCol="2" endRow="63"> + <gnm:StyleRegion startCol="3" startRow="63" endCol="3" endRow="63"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -391,7 +391,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="64" endCol="2" endRow="66"> + <gnm:StyleRegion startCol="3" startRow="64" endCol="3" endRow="66"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -399,7 +399,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="2" startRow="67" endCol="2" endRow="65535"> + <gnm:StyleRegion startCol="3" startRow="67" endCol="3" endRow="65535"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -407,132 +407,132 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="0" endCol="3" endRow="5"> + <gnm:StyleRegion startCol="4" startRow="0" endCol="4" endRow="5"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="6" endCol="3" endRow="9"> + <gnm:StyleRegion startCol="4" startRow="6" endCol="4" endRow="9"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="10" endCol="3" endRow="11"> + <gnm:StyleRegion startCol="4" startRow="10" endCol="4" endRow="11"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="12" endCol="3" endRow="14"> + <gnm:StyleRegion startCol="4" startRow="12" endCol="4" endRow="14"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="15" endCol="3" endRow="15"> + <gnm:StyleRegion startCol="4" startRow="15" endCol="4" endRow="15"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="16" endCol="3" endRow="19"> + <gnm:StyleRegion startCol="4" startRow="16" endCol="4" endRow="19"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="20" endCol="3" endRow="21"> + <gnm:StyleRegion startCol="4" startRow="20" endCol="4" endRow="21"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="22" endCol="3" endRow="26"> + <gnm:StyleRegion startCol="4" startRow="22" endCol="4" endRow="26"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="27" endCol="3" endRow="27"> + <gnm:StyleRegion startCol="4" startRow="27" endCol="4" endRow="27"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="28" endCol="3" endRow="35"> + <gnm:StyleRegion startCol="4" startRow="28" endCol="4" endRow="35"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="36" endCol="3" endRow="36"> + <gnm:StyleRegion startCol="4" startRow="36" endCol="4" endRow="36"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="37" endCol="3" endRow="41"> + <gnm:StyleRegion startCol="4" startRow="37" endCol="4" endRow="41"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="42" endCol="3" endRow="43"> + <gnm:StyleRegion startCol="4" startRow="42" endCol="4" endRow="43"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="44" endCol="3" endRow="47"> + <gnm:StyleRegion startCol="4" startRow="44" endCol="4" endRow="47"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="48" endCol="3" endRow="49"> + <gnm:StyleRegion startCol="4" startRow="48" endCol="4" endRow="49"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="50" endCol="3" endRow="51"> + <gnm:StyleRegion startCol="4" startRow="50" endCol="4" endRow="51"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="52" endCol="3" endRow="54"> + <gnm:StyleRegion startCol="4" startRow="52" endCol="4" endRow="54"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="55" endCol="3" endRow="55"> + <gnm:StyleRegion startCol="4" startRow="55" endCol="4" endRow="55"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="56" endCol="3" endRow="57"> + <gnm:StyleRegion startCol="4" startRow="56" endCol="4" endRow="57"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="58" endCol="3" endRow="58"> + <gnm:StyleRegion startCol="4" startRow="58" endCol="4" endRow="58"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="59" endCol="3" endRow="61"> + <gnm:StyleRegion startCol="4" startRow="59" endCol="4" endRow="61"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="62" endCol="3" endRow="62"> + <gnm:StyleRegion startCol="4" startRow="62" endCol="4" endRow="62"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="63" endCol="3" endRow="63"> + <gnm:StyleRegion startCol="4" startRow="63" endCol="4" endRow="63"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="64" endCol="3" endRow="66"> + <gnm:StyleRegion startCol="4" startRow="64" endCol="4" endRow="66"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="3" startRow="67" endCol="3" endRow="65535"> + <gnm:StyleRegion startCol="4" startRow="67" endCol="4" endRow="65535"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="0" endCol="4" endRow="5"> + <gnm:StyleRegion startCol="5" startRow="0" endCol="5" endRow="5"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -540,7 +540,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="6" endCol="4" endRow="9"> + <gnm:StyleRegion startCol="5" startRow="6" endCol="5" endRow="9"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -548,7 +548,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="10" endCol="4" endRow="11"> + <gnm:StyleRegion startCol="5" startRow="10" endCol="5" endRow="11"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -556,7 +556,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="12" endCol="4" endRow="14"> + <gnm:StyleRegion startCol="5" startRow="12" endCol="5" endRow="14"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -564,7 +564,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="15" endCol="4" endRow="15"> + <gnm:StyleRegion startCol="5" startRow="15" endCol="5" endRow="15"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -572,7 +572,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="16" endCol="4" endRow="19"> + <gnm:StyleRegion startCol="5" startRow="16" endCol="5" endRow="19"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -580,7 +580,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="20" endCol="4" endRow="21"> + <gnm:StyleRegion startCol="5" startRow="20" endCol="5" endRow="21"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -588,7 +588,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="22" endCol="4" endRow="26"> + <gnm:StyleRegion startCol="5" startRow="22" endCol="5" endRow="26"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -596,7 +596,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="27" endCol="4" endRow="27"> + <gnm:StyleRegion startCol="5" startRow="27" endCol="5" endRow="27"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -604,7 +604,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="28" endCol="4" endRow="35"> + <gnm:StyleRegion startCol="5" startRow="28" endCol="5" endRow="35"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -612,7 +612,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="36" endCol="4" endRow="36"> + <gnm:StyleRegion startCol="5" startRow="36" endCol="5" endRow="36"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -620,7 +620,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="37" endCol="4" endRow="41"> + <gnm:StyleRegion startCol="5" startRow="37" endCol="5" endRow="41"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -628,7 +628,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="42" endCol="4" endRow="43"> + <gnm:StyleRegion startCol="5" startRow="42" endCol="5" endRow="43"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -636,7 +636,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="44" endCol="4" endRow="47"> + <gnm:StyleRegion startCol="5" startRow="44" endCol="5" endRow="47"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -644,7 +644,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="48" endCol="4" endRow="49"> + <gnm:StyleRegion startCol="5" startRow="48" endCol="5" endRow="49"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -652,7 +652,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="50" endCol="4" endRow="51"> + <gnm:StyleRegion startCol="5" startRow="50" endCol="5" endRow="51"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -660,7 +660,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="52" endCol="4" endRow="54"> + <gnm:StyleRegion startCol="5" startRow="52" endCol="5" endRow="54"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -668,7 +668,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="55" endCol="4" endRow="55"> + <gnm:StyleRegion startCol="5" startRow="55" endCol="5" endRow="55"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -676,7 +676,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="56" endCol="4" endRow="57"> + <gnm:StyleRegion startCol="5" startRow="56" endCol="5" endRow="57"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -684,7 +684,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="58" endCol="4" endRow="58"> + <gnm:StyleRegion startCol="5" startRow="58" endCol="5" endRow="58"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -692,7 +692,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="59" endCol="4" endRow="61"> + <gnm:StyleRegion startCol="5" startRow="59" endCol="5" endRow="61"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -700,7 +700,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="62" endCol="4" endRow="62"> + <gnm:StyleRegion startCol="5" startRow="62" endCol="5" endRow="62"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -708,7 +708,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="63" endCol="4" endRow="63"> + <gnm:StyleRegion startCol="5" startRow="63" endCol="5" endRow="63"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -716,7 +716,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="64" endCol="4" endRow="66"> + <gnm:StyleRegion startCol="5" startRow="64" endCol="5" endRow="66"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -724,7 +724,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="4" startRow="67" endCol="4" endRow="65535"> + <gnm:StyleRegion startCol="5" startRow="67" endCol="5" endRow="65535"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -732,132 +732,132 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="0" endCol="5" endRow="5"> + <gnm:StyleRegion startCol="6" startRow="0" endCol="6" endRow="5"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="6" endCol="5" endRow="9"> + <gnm:StyleRegion startCol="6" startRow="6" endCol="6" endRow="9"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="10" endCol="5" endRow="11"> + <gnm:StyleRegion startCol="6" startRow="10" endCol="6" endRow="11"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="12" endCol="5" endRow="14"> + <gnm:StyleRegion startCol="6" startRow="12" endCol="6" endRow="14"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="15" endCol="5" endRow="15"> + <gnm:StyleRegion startCol="6" startRow="15" endCol="6" endRow="15"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="16" endCol="5" endRow="19"> + <gnm:StyleRegion startCol="6" startRow="16" endCol="6" endRow="19"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="20" endCol="5" endRow="21"> + <gnm:StyleRegion startCol="6" startRow="20" endCol="6" endRow="21"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="22" endCol="5" endRow="26"> + <gnm:StyleRegion startCol="6" startRow="22" endCol="6" endRow="26"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="27" endCol="5" endRow="27"> + <gnm:StyleRegion startCol="6" startRow="27" endCol="6" endRow="27"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="28" endCol="5" endRow="35"> + <gnm:StyleRegion startCol="6" startRow="28" endCol="6" endRow="35"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="36" endCol="5" endRow="36"> + <gnm:StyleRegion startCol="6" startRow="36" endCol="6" endRow="36"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="37" endCol="5" endRow="41"> + <gnm:StyleRegion startCol="6" startRow="37" endCol="6" endRow="41"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="42" endCol="5" endRow="43"> + <gnm:StyleRegion startCol="6" startRow="42" endCol="6" endRow="43"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="44" endCol="5" endRow="47"> + <gnm:StyleRegion startCol="6" startRow="44" endCol="6" endRow="47"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="48" endCol="5" endRow="49"> + <gnm:StyleRegion startCol="6" startRow="48" endCol="6" endRow="49"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="50" endCol="5" endRow="51"> + <gnm:StyleRegion startCol="6" startRow="50" endCol="6" endRow="51"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="52" endCol="5" endRow="54"> + <gnm:StyleRegion startCol="6" startRow="52" endCol="6" endRow="54"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="55" endCol="5" endRow="55"> + <gnm:StyleRegion startCol="6" startRow="55" endCol="6" endRow="55"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="56" endCol="5" endRow="57"> + <gnm:StyleRegion startCol="6" startRow="56" endCol="6" endRow="57"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="58" endCol="5" endRow="58"> + <gnm:StyleRegion startCol="6" startRow="58" endCol="6" endRow="58"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="59" endCol="5" endRow="61"> + <gnm:StyleRegion startCol="6" startRow="59" endCol="6" endRow="61"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="62" endCol="5" endRow="62"> + <gnm:StyleRegion startCol="6" startRow="62" endCol="6" endRow="62"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="63" endCol="5" endRow="63"> + <gnm:StyleRegion startCol="6" startRow="63" endCol="6" endRow="63"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="64" endCol="5" endRow="66"> + <gnm:StyleRegion startCol="6" startRow="64" endCol="6" endRow="66"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="5" startRow="67" endCol="5" endRow="65535"> + <gnm:StyleRegion startCol="6" startRow="67" endCol="6" endRow="65535"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="0" endCol="6" endRow="5"> + <gnm:StyleRegion startCol="7" startRow="0" endCol="7" endRow="5"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -865,7 +865,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="6" endCol="6" endRow="9"> + <gnm:StyleRegion startCol="7" startRow="6" endCol="7" endRow="9"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -873,7 +873,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="10" endCol="6" endRow="11"> + <gnm:StyleRegion startCol="7" startRow="10" endCol="7" endRow="11"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -881,7 +881,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="12" endCol="6" endRow="14"> + <gnm:StyleRegion startCol="7" startRow="12" endCol="7" endRow="14"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -889,7 +889,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="15" endCol="6" endRow="15"> + <gnm:StyleRegion startCol="7" startRow="15" endCol="7" endRow="15"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -897,7 +897,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="16" endCol="6" endRow="19"> + <gnm:StyleRegion startCol="7" startRow="16" endCol="7" endRow="19"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -905,7 +905,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="20" endCol="6" endRow="21"> + <gnm:StyleRegion startCol="7" startRow="20" endCol="7" endRow="21"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -913,7 +913,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="22" endCol="6" endRow="26"> + <gnm:StyleRegion startCol="7" startRow="22" endCol="7" endRow="26"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -921,7 +921,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="27" endCol="6" endRow="27"> + <gnm:StyleRegion startCol="7" startRow="27" endCol="7" endRow="27"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -929,7 +929,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="28" endCol="6" endRow="35"> + <gnm:StyleRegion startCol="7" startRow="28" endCol="7" endRow="35"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -937,7 +937,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="36" endCol="6" endRow="36"> + <gnm:StyleRegion startCol="7" startRow="36" endCol="7" endRow="36"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -945,7 +945,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="37" endCol="6" endRow="41"> + <gnm:StyleRegion startCol="7" startRow="37" endCol="7" endRow="41"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -953,7 +953,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="42" endCol="6" endRow="43"> + <gnm:StyleRegion startCol="7" startRow="42" endCol="7" endRow="43"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -961,7 +961,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="44" endCol="6" endRow="47"> + <gnm:StyleRegion startCol="7" startRow="44" endCol="7" endRow="47"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -969,7 +969,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="48" endCol="6" endRow="49"> + <gnm:StyleRegion startCol="7" startRow="48" endCol="7" endRow="49"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -977,7 +977,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="50" endCol="6" endRow="51"> + <gnm:StyleRegion startCol="7" startRow="50" endCol="7" endRow="51"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -985,7 +985,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="52" endCol="6" endRow="54"> + <gnm:StyleRegion startCol="7" startRow="52" endCol="7" endRow="54"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -993,7 +993,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="55" endCol="6" endRow="55"> + <gnm:StyleRegion startCol="7" startRow="55" endCol="7" endRow="55"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1001,7 +1001,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="56" endCol="6" endRow="57"> + <gnm:StyleRegion startCol="7" startRow="56" endCol="7" endRow="57"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1009,7 +1009,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="58" endCol="6" endRow="58"> + <gnm:StyleRegion startCol="7" startRow="58" endCol="7" endRow="58"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1017,7 +1017,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="59" endCol="6" endRow="61"> + <gnm:StyleRegion startCol="7" startRow="59" endCol="7" endRow="61"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1025,7 +1025,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="62" endCol="6" endRow="62"> + <gnm:StyleRegion startCol="7" startRow="62" endCol="7" endRow="62"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1033,7 +1033,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="63" endCol="6" endRow="63"> + <gnm:StyleRegion startCol="7" startRow="63" endCol="7" endRow="63"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1041,7 +1041,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="64" endCol="6" endRow="66"> + <gnm:StyleRegion startCol="7" startRow="64" endCol="7" endRow="66"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1049,7 +1049,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="6" startRow="67" endCol="6" endRow="65535"> + <gnm:StyleRegion startCol="7" startRow="67" endCol="7" endRow="65535"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1057,132 +1057,132 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="0" endCol="7" endRow="5"> + <gnm:StyleRegion startCol="8" startRow="0" endCol="8" endRow="5"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="6" endCol="7" endRow="9"> + <gnm:StyleRegion startCol="8" startRow="6" endCol="8" endRow="9"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="10" endCol="7" endRow="11"> + <gnm:StyleRegion startCol="8" startRow="10" endCol="8" endRow="11"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="12" endCol="7" endRow="14"> + <gnm:StyleRegion startCol="8" startRow="12" endCol="8" endRow="14"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="15" endCol="7" endRow="15"> + <gnm:StyleRegion startCol="8" startRow="15" endCol="8" endRow="15"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="16" endCol="7" endRow="19"> + <gnm:StyleRegion startCol="8" startRow="16" endCol="8" endRow="19"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="20" endCol="7" endRow="21"> + <gnm:StyleRegion startCol="8" startRow="20" endCol="8" endRow="21"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="22" endCol="7" endRow="26"> + <gnm:StyleRegion startCol="8" startRow="22" endCol="8" endRow="26"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="27" endCol="7" endRow="27"> + <gnm:StyleRegion startCol="8" startRow="27" endCol="8" endRow="27"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="28" endCol="7" endRow="35"> + <gnm:StyleRegion startCol="8" startRow="28" endCol="8" endRow="35"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="36" endCol="7" endRow="36"> + <gnm:StyleRegion startCol="8" startRow="36" endCol="8" endRow="36"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="37" endCol="7" endRow="41"> + <gnm:StyleRegion startCol="8" startRow="37" endCol="8" endRow="41"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="42" endCol="7" endRow="43"> + <gnm:StyleRegion startCol="8" startRow="42" endCol="8" endRow="43"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="44" endCol="7" endRow="47"> + <gnm:StyleRegion startCol="8" startRow="44" endCol="8" endRow="47"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="48" endCol="7" endRow="49"> + <gnm:StyleRegion startCol="8" startRow="48" endCol="8" endRow="49"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="50" endCol="7" endRow="51"> + <gnm:StyleRegion startCol="8" startRow="50" endCol="8" endRow="51"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="52" endCol="7" endRow="54"> + <gnm:StyleRegion startCol="8" startRow="52" endCol="8" endRow="54"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="55" endCol="7" endRow="55"> + <gnm:StyleRegion startCol="8" startRow="55" endCol="8" endRow="55"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="56" endCol="7" endRow="57"> + <gnm:StyleRegion startCol="8" startRow="56" endCol="8" endRow="57"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="58" endCol="7" endRow="58"> + <gnm:StyleRegion startCol="8" startRow="58" endCol="8" endRow="58"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="59" endCol="7" endRow="61"> + <gnm:StyleRegion startCol="8" startRow="59" endCol="8" endRow="61"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="62" endCol="7" endRow="62"> + <gnm:StyleRegion startCol="8" startRow="62" endCol="8" endRow="62"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="63" endCol="7" endRow="63"> + <gnm:StyleRegion startCol="8" startRow="63" endCol="8" endRow="63"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="64" endCol="7" endRow="66"> + <gnm:StyleRegion startCol="8" startRow="64" endCol="8" endRow="66"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="7" startRow="67" endCol="7" endRow="65535"> + <gnm:StyleRegion startCol="8" startRow="67" endCol="8" endRow="65535"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="0" endCol="8" endRow="5"> + <gnm:StyleRegion startCol="9" startRow="0" endCol="9" endRow="5"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1190,7 +1190,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="6" endCol="8" endRow="9"> + <gnm:StyleRegion startCol="9" startRow="6" endCol="9" endRow="9"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1198,7 +1198,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="10" endCol="8" endRow="11"> + <gnm:StyleRegion startCol="9" startRow="10" endCol="9" endRow="11"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1206,7 +1206,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="12" endCol="8" endRow="14"> + <gnm:StyleRegion startCol="9" startRow="12" endCol="9" endRow="14"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1214,7 +1214,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="15" endCol="8" endRow="15"> + <gnm:StyleRegion startCol="9" startRow="15" endCol="9" endRow="15"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1222,7 +1222,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="16" endCol="8" endRow="19"> + <gnm:StyleRegion startCol="9" startRow="16" endCol="9" endRow="19"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1230,7 +1230,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="20" endCol="8" endRow="21"> + <gnm:StyleRegion startCol="9" startRow="20" endCol="9" endRow="21"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1238,7 +1238,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="22" endCol="8" endRow="26"> + <gnm:StyleRegion startCol="9" startRow="22" endCol="9" endRow="26"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1246,7 +1246,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="27" endCol="8" endRow="27"> + <gnm:StyleRegion startCol="9" startRow="27" endCol="9" endRow="27"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1254,7 +1254,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="28" endCol="8" endRow="35"> + <gnm:StyleRegion startCol="9" startRow="28" endCol="9" endRow="35"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1262,7 +1262,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="36" endCol="8" endRow="36"> + <gnm:StyleRegion startCol="9" startRow="36" endCol="9" endRow="36"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1270,7 +1270,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="37" endCol="8" endRow="41"> + <gnm:StyleRegion startCol="9" startRow="37" endCol="9" endRow="41"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1278,7 +1278,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="42" endCol="8" endRow="43"> + <gnm:StyleRegion startCol="9" startRow="42" endCol="9" endRow="43"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1286,7 +1286,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="44" endCol="8" endRow="47"> + <gnm:StyleRegion startCol="9" startRow="44" endCol="9" endRow="47"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1294,7 +1294,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="48" endCol="8" endRow="49"> + <gnm:StyleRegion startCol="9" startRow="48" endCol="9" endRow="49"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1302,7 +1302,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="50" endCol="8" endRow="51"> + <gnm:StyleRegion startCol="9" startRow="50" endCol="9" endRow="51"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1310,7 +1310,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="52" endCol="8" endRow="54"> + <gnm:StyleRegion startCol="9" startRow="52" endCol="9" endRow="54"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1318,7 +1318,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="55" endCol="8" endRow="55"> + <gnm:StyleRegion startCol="9" startRow="55" endCol="9" endRow="55"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1326,7 +1326,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="56" endCol="8" endRow="57"> + <gnm:StyleRegion startCol="9" startRow="56" endCol="9" endRow="57"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1334,7 +1334,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="58" endCol="8" endRow="58"> + <gnm:StyleRegion startCol="9" startRow="58" endCol="9" endRow="58"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1342,7 +1342,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="59" endCol="8" endRow="61"> + <gnm:StyleRegion startCol="9" startRow="59" endCol="9" endRow="61"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1350,7 +1350,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="62" endCol="8" endRow="62"> + <gnm:StyleRegion startCol="9" startRow="62" endCol="9" endRow="62"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1358,7 +1358,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="63" endCol="8" endRow="63"> + <gnm:StyleRegion startCol="9" startRow="63" endCol="9" endRow="63"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1366,7 +1366,7 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="64" endCol="8" endRow="66"> + <gnm:StyleRegion startCol="9" startRow="64" endCol="9" endRow="66"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1374,7 +1374,332 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="8" startRow="67" endCol="8" endRow="65535"> + <gnm:StyleRegion startCol="9" startRow="67" endCol="9" endRow="65535"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="0" endCol="10" endRow="5"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="6" endCol="10" endRow="9"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="10" endCol="10" endRow="11"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="12" endCol="10" endRow="14"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="15" endCol="10" endRow="15"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="16" endCol="10" endRow="19"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="20" endCol="10" endRow="21"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="22" endCol="10" endRow="26"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="27" endCol="10" endRow="27"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="28" endCol="10" endRow="35"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="36" endCol="10" endRow="36"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="37" endCol="10" endRow="41"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="42" endCol="10" endRow="43"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="44" endCol="10" endRow="47"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="48" endCol="10" endRow="49"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="50" endCol="10" endRow="51"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="52" endCol="10" endRow="54"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="55" endCol="10" endRow="55"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="56" endCol="10" endRow="57"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="58" endCol="10" endRow="58"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="59" endCol="10" endRow="61"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="62" endCol="10" endRow="62"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="63" endCol="10" endRow="63"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="64" endCol="10" endRow="66"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="10" startRow="67" endCol="10" endRow="65535"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="0" endCol="11" endRow="5"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="6" endCol="11" endRow="9"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="10" endCol="11" endRow="11"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="12" endCol="11" endRow="14"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="15" endCol="11" endRow="15"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="16" endCol="11" endRow="19"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="20" endCol="11" endRow="21"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="22" endCol="11" endRow="26"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="27" endCol="11" endRow="27"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="28" endCol="11" endRow="35"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="36" endCol="11" endRow="36"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="37" endCol="11" endRow="41"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="42" endCol="11" endRow="43"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="44" endCol="11" endRow="47"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="48" endCol="11" endRow="49"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="50" endCol="11" endRow="51"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="52" endCol="11" endRow="54"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="55" endCol="11" endRow="55"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="56" endCol="11" endRow="57"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="58" endCol="11" endRow="58"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="59" endCol="11" endRow="61"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="62" endCol="11" endRow="62"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="63" endCol="11" endRow="63"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="64" endCol="11" endRow="66"> + <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> + <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> + <gnm:StyleBorder> + <gnm:Left Style="1" Color="0:0:0"/> + </gnm:StyleBorder> + </gnm:Style> + </gnm:StyleRegion> + <gnm:StyleRegion startCol="11" startRow="67" endCol="11" endRow="65535"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> <gnm:StyleBorder> @@ -1382,545 +1707,668 @@ </gnm:StyleBorder> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="0" endCol="255" endRow="5"> + <gnm:StyleRegion startCol="12" startRow="0" endCol="255" endRow="5"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="6" endCol="255" endRow="9"> + <gnm:StyleRegion startCol="12" startRow="6" endCol="255" endRow="9"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="10" endCol="255" endRow="11"> + <gnm:StyleRegion startCol="12" startRow="10" endCol="255" endRow="11"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="12" endCol="255" endRow="14"> + <gnm:StyleRegion startCol="12" startRow="12" endCol="255" endRow="14"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="15" endCol="255" endRow="15"> + <gnm:StyleRegion startCol="12" startRow="15" endCol="255" endRow="15"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="16" endCol="255" endRow="19"> + <gnm:StyleRegion startCol="12" startRow="16" endCol="255" endRow="19"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="20" endCol="255" endRow="21"> + <gnm:StyleRegion startCol="12" startRow="20" endCol="255" endRow="21"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="22" endCol="255" endRow="26"> + <gnm:StyleRegion startCol="12" startRow="22" endCol="255" endRow="26"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="27" endCol="255" endRow="27"> + <gnm:StyleRegion startCol="12" startRow="27" endCol="255" endRow="27"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="28" endCol="255" endRow="35"> + <gnm:StyleRegion startCol="12" startRow="28" endCol="255" endRow="35"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="36" endCol="255" endRow="36"> + <gnm:StyleRegion startCol="12" startRow="36" endCol="255" endRow="36"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="37" endCol="255" endRow="41"> + <gnm:StyleRegion startCol="12" startRow="37" endCol="255" endRow="41"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="42" endCol="255" endRow="43"> + <gnm:StyleRegion startCol="12" startRow="42" endCol="255" endRow="43"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="44" endCol="255" endRow="47"> + <gnm:StyleRegion startCol="12" startRow="44" endCol="255" endRow="47"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="48" endCol="255" endRow="49"> + <gnm:StyleRegion startCol="12" startRow="48" endCol="255" endRow="49"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="50" endCol="255" endRow="51"> + <gnm:StyleRegion startCol="12" startRow="50" endCol="255" endRow="51"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="52" endCol="255" endRow="54"> + <gnm:StyleRegion startCol="12" startRow="52" endCol="255" endRow="54"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="55" endCol="255" endRow="55"> + <gnm:StyleRegion startCol="12" startRow="55" endCol="255" endRow="55"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="56" endCol="255" endRow="57"> + <gnm:StyleRegion startCol="12" startRow="56" endCol="255" endRow="57"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="58" endCol="255" endRow="58"> + <gnm:StyleRegion startCol="12" startRow="58" endCol="255" endRow="58"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="59" endCol="255" endRow="61"> + <gnm:StyleRegion startCol="12" startRow="59" endCol="255" endRow="61"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="62" endCol="255" endRow="62"> + <gnm:StyleRegion startCol="12" startRow="62" endCol="255" endRow="62"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="63" endCol="255" endRow="63"> + <gnm:StyleRegion startCol="12" startRow="63" endCol="255" endRow="63"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="64" endCol="255" endRow="66"> + <gnm:StyleRegion startCol="12" startRow="64" endCol="255" endRow="66"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="1" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:BABA" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> - <gnm:StyleRegion startCol="9" startRow="67" endCol="255" endRow="65535"> + <gnm:StyleRegion startCol="12" startRow="67" endCol="255" endRow="65535"> <gnm:Style HAlign="GNM_HALIGN_GENERAL" VAlign="GNM_VALIGN_BOTTOM" WrapText="0" ShrinkToFit="0" Rotation="0" Shade="0" Indent="0" Locked="1" Hidden="0" Fore="0:0:0" Back="FFFF:FFFF:FFFF" PatternColor="0:0:0" Format="General"> <gnm:Font Unit="10" Bold="0" Italic="0" Underline="0" StrikeThrough="0" Script="0">Sans</gnm:Font> </gnm:Style> </gnm:StyleRegion> </gnm:Styles> <gnm:Cols DefaultSizePts="48"> - <gnm:ColInfo No="1" Unit="118.5" HardSize="1"/> - <gnm:ColInfo No="2" Unit="78.75" HardSize="1"/> - <gnm:ColInfo No="3" Unit="102.8" HardSize="1"/> - <gnm:ColInfo No="5" Unit="120" HardSize="1"/> - <gnm:ColInfo No="7" Unit="161.2" HardSize="1"/> + <gnm:ColInfo No="2" Unit="118.5" HardSize="1"/> + <gnm:ColInfo No="3" Unit="78.75" HardSize="1"/> + <gnm:ColInfo No="4" Unit="102.8" HardSize="1"/> + <gnm:ColInfo No="6" Unit="120" HardSize="1"/> + <gnm:ColInfo No="8" Unit="161.2" HardSize="1"/> + <gnm:ColInfo No="9" Unit="48" HardSize="1"/> + <gnm:ColInfo No="10" Unit="141" HardSize="1"/> + <gnm:ColInfo No="12" Unit="144.8" HardSize="1"/> </gnm:Cols> <gnm:Rows DefaultSizePts="12.75"> - <gnm:RowInfo No="2" Unit="13.5" Count="2"/> - <gnm:RowInfo No="12" Unit="13.5" Count="3"/> - <gnm:RowInfo No="16" Unit="13.5" Count="2"/> - <gnm:RowInfo No="19" Unit="13.5"/> - <gnm:RowInfo No="22" Unit="13.5"/> - <gnm:RowInfo No="24" Unit="13.5" Count="2"/> - <gnm:RowInfo No="30" Unit="13.5" Count="5"/> - <gnm:RowInfo No="39" Unit="13.5"/> - <gnm:RowInfo No="46" Unit="13.5"/> - <gnm:RowInfo No="55" Unit="13.5"/> + <gnm:RowInfo No="2" Unit="13.5" Count="13"/> + <gnm:RowInfo No="16" Unit="13.5" Count="4"/> + <gnm:RowInfo No="21" Unit="13.5" Count="42"/> + <gnm:RowInfo No="64" Unit="13.5" Count="4"/> </gnm:Rows> - <gnm:Selections CursorCol="3" CursorRow="0"> - <gnm:Selection startCol="3" startRow="0" endCol="3" endRow="0"/> + <gnm:Selections CursorCol="11" CursorRow="2"> + <gnm:Selection startCol="11" startRow="2" endCol="12" endRow="2"/> </gnm:Selections> <gnm:Cells> - <gnm:Cell Row="0" Col="0" ValueType="60">Pins / Ios of SAM3 based devices</gnm:Cell> - <gnm:Cell Row="2" Col="2" ValueType="60">SIMtrace v1.x</gnm:Cell> - <gnm:Cell Row="2" Col="4" ValueType="60">Quad Modem</gnm:Cell> - <gnm:Cell Row="2" Col="6" ValueType="60">OWHW</gnm:Cell> - <gnm:Cell Row="2" Col="8" ValueType="60">SAM3-P256</gnm:Cell> - <gnm:Cell Row="3" Col="0" ValueType="60">Pin Number</gnm:Cell> - <gnm:Cell Row="3" Col="1" ValueType="60">Pin Name</gnm:Cell> - <gnm:Cell Row="3" Col="2" ValueType="60">Used Function</gnm:Cell> - <gnm:Cell Row="3" Col="3" ValueType="60">Signal Name</gnm:Cell> - <gnm:Cell Row="3" Col="4" ValueType="60">Used Function</gnm:Cell> - <gnm:Cell Row="3" Col="5" ValueType="60">Signal Name</gnm:Cell> - <gnm:Cell Row="3" Col="6" ValueType="60">Used Function</gnm:Cell> - <gnm:Cell Row="3" Col="7" ValueType="60">Signal Name</gnm:Cell> - <gnm:Cell Row="3" Col="8" ValueType="60">Used Function</gnm:Cell> - <gnm:Cell Row="3" Col="9" ValueType="60">Signal Name</gnm:Cell> + <gnm:Cell Row="0" Col="1" ValueType="60">Pins / Ios of SAM3 based devices</gnm:Cell> + <gnm:Cell Row="2" Col="3" ValueType="60">SIMtrace v1.x</gnm:Cell> + <gnm:Cell Row="2" Col="5" ValueType="60">Quad Modem</gnm:Cell> + <gnm:Cell Row="2" Col="7" ValueType="60">OWHW</gnm:Cell> + <gnm:Cell Row="2" Col="9" ValueType="60">SAM3-P256</gnm:Cell> + <gnm:Cell Row="2" Col="11" ValueType="60">mPCIe / m.2 CCID</gnm:Cell> + <gnm:Cell Row="3" Col="0" ValueType="60">Pin48</gnm:Cell> + <gnm:Cell Row="3" Col="1" ValueType="60">Pin Number</gnm:Cell> + <gnm:Cell Row="3" Col="2" ValueType="60">Pin Name</gnm:Cell> + <gnm:Cell Row="3" Col="3" ValueType="60">Used Function</gnm:Cell> + <gnm:Cell Row="3" Col="4" ValueType="60">Signal Name</gnm:Cell> + <gnm:Cell Row="3" Col="5" ValueType="60">Used Function</gnm:Cell> + <gnm:Cell Row="3" Col="6" ValueType="60">Signal Name</gnm:Cell> + <gnm:Cell Row="3" Col="7" ValueType="60">Used Function</gnm:Cell> + <gnm:Cell Row="3" Col="8" ValueType="60">Signal Name</gnm:Cell> + <gnm:Cell Row="3" Col="9" ValueType="60">Used Function</gnm:Cell> + <gnm:Cell Row="3" Col="10" ValueType="60">Signal Name</gnm:Cell> + <gnm:Cell Row="3" Col="11" ValueType="60">Used Fun</gnm:Cell> + <gnm:Cell Row="3" Col="12" ValueType="60">Signal Name</gnm:Cell> <gnm:Cell Row="4" Col="0" ValueType="40">1</gnm:Cell> - <gnm:Cell Row="4" Col="1" ValueType="60">ADVREF</gnm:Cell> - <gnm:Cell Row="4" Col="4" ValueType="60">ADVREF</gnm:Cell> + <gnm:Cell Row="4" Col="1" ValueType="40">1</gnm:Cell> + <gnm:Cell Row="4" Col="2" ValueType="60">ADVREF</gnm:Cell> <gnm:Cell Row="4" Col="5" ValueType="60">ADVREF</gnm:Cell> + <gnm:Cell Row="4" Col="6" ValueType="60">ADVREF</gnm:Cell> <gnm:Cell Row="5" Col="0" ValueType="40">2</gnm:Cell> - <gnm:Cell Row="5" Col="1" ValueType="60">GND</gnm:Cell> + <gnm:Cell Row="5" Col="1" ValueType="40">2</gnm:Cell> + <gnm:Cell Row="5" Col="2" ValueType="60">GND</gnm:Cell> <gnm:Cell Row="6" Col="0" ValueType="40">3</gnm:Cell> - <gnm:Cell Row="6" Col="1" ValueType="60">AD4</gnm:Cell> - <gnm:Cell Row="6" Col="5" ValueType="60">GND</gnm:Cell> - <gnm:Cell Row="6" Col="7" ValueType="60">GND</gnm:Cell> + <gnm:Cell Row="6" Col="1" ValueType="40">3</gnm:Cell> + <gnm:Cell Row="6" Col="2" ValueType="60">AD4</gnm:Cell> + <gnm:Cell Row="6" Col="6" ValueType="60">GND</gnm:Cell> + <gnm:Cell Row="6" Col="8" ValueType="60">GND</gnm:Cell> <gnm:Cell Row="7" Col="0" ValueType="40">4</gnm:Cell> - <gnm:Cell Row="7" Col="1" ValueType="60">AD5</gnm:Cell> - <gnm:Cell Row="7" Col="5" ValueType="60">GND</gnm:Cell> - <gnm:Cell Row="7" Col="7" ValueType="60">GND</gnm:Cell> + <gnm:Cell Row="7" Col="1" ValueType="40">4</gnm:Cell> + <gnm:Cell Row="7" Col="2" ValueType="60">AD5</gnm:Cell> + <gnm:Cell Row="7" Col="6" ValueType="60">GND</gnm:Cell> + <gnm:Cell Row="7" Col="8" ValueType="60">GND</gnm:Cell> <gnm:Cell Row="8" Col="0" ValueType="40">5</gnm:Cell> - <gnm:Cell Row="8" Col="1" ValueType="60">AD6</gnm:Cell> - <gnm:Cell Row="8" Col="4" ValueType="60">AD6</gnm:Cell> - <gnm:Cell Row="8" Col="5" ValueType="60">MDM2_USIM_VDD</gnm:Cell> - <gnm:Cell Row="8" Col="6" ValueType="60">AD6</gnm:Cell> - <gnm:Cell Row="8" Col="7" ValueType="60">MDM2_USIM_VDD</gnm:Cell> + <gnm:Cell Row="8" Col="1" ValueType="40">5</gnm:Cell> + <gnm:Cell Row="8" Col="2" ValueType="60">AD6</gnm:Cell> + <gnm:Cell Row="8" Col="5" ValueType="60">AD6</gnm:Cell> + <gnm:Cell Row="8" Col="6" ValueType="60">MDM2_USIM_VDD</gnm:Cell> + <gnm:Cell Row="8" Col="7" ValueType="60">AD6</gnm:Cell> + <gnm:Cell Row="8" Col="8" ValueType="60">MDM2_USIM_VDD</gnm:Cell> + <gnm:Cell Row="8" Col="11" ValueType="60">PB2</gnm:Cell> + <gnm:Cell Row="8" Col="12" ValueType="60">EN_ST_SIM_VDD</gnm:Cell> <gnm:Cell Row="9" Col="0" ValueType="40">6</gnm:Cell> - <gnm:Cell Row="9" Col="1" ValueType="60">AD7</gnm:Cell> - <gnm:Cell Row="9" Col="4" ValueType="60">AD7</gnm:Cell> - <gnm:Cell Row="9" Col="5" ValueType="60">MDM1_USIM_VDD</gnm:Cell> - <gnm:Cell Row="9" Col="6" ValueType="60">AD7</gnm:Cell> - <gnm:Cell Row="9" Col="7" ValueType="60">MDM1_USIM_VDD</gnm:Cell> + <gnm:Cell Row="9" Col="1" ValueType="40">6</gnm:Cell> + <gnm:Cell Row="9" Col="2" ValueType="60">AD7</gnm:Cell> + <gnm:Cell Row="9" Col="5" ValueType="60">AD7</gnm:Cell> + <gnm:Cell Row="9" Col="6" ValueType="60">MDM1_USIM_VDD</gnm:Cell> + <gnm:Cell Row="9" Col="7" ValueType="60">AD7</gnm:Cell> + <gnm:Cell Row="9" Col="8" ValueType="60">MDM1_USIM_VDD</gnm:Cell> + <gnm:Cell Row="9" Col="11" ValueType="60">AD7</gnm:Cell> + <gnm:Cell Row="9" Col="12" ValueType="60">MDM_UIM_VDD</gnm:Cell> <gnm:Cell Row="10" Col="0" ValueType="40">7</gnm:Cell> - <gnm:Cell Row="10" Col="1" ValueType="60">VDDIN</gnm:Cell> + <gnm:Cell Row="10" Col="1" ValueType="40">7</gnm:Cell> + <gnm:Cell Row="10" Col="2" ValueType="60">VDDIN</gnm:Cell> <gnm:Cell Row="11" Col="0" ValueType="40">8</gnm:Cell> - <gnm:Cell Row="11" Col="1" ValueType="60">VDDOUT</gnm:Cell> + <gnm:Cell Row="11" Col="1" ValueType="40">8</gnm:Cell> + <gnm:Cell Row="11" Col="2" ValueType="60">VDDOUT</gnm:Cell> <gnm:Cell Row="12" Col="0" ValueType="40">9</gnm:Cell> - <gnm:Cell Row="12" Col="1" ValueType="60">PA17</gnm:Cell> + <gnm:Cell Row="12" Col="1" ValueType="40">9</gnm:Cell> <gnm:Cell Row="12" Col="2" ValueType="60">PA17</gnm:Cell> - <gnm:Cell Row="12" Col="3" ValueType="60">LED_R</gnm:Cell> - <gnm:Cell Row="12" Col="4" ValueType="60">PA17</gnm:Cell> - <gnm:Cell Row="12" Col="5" ValueType="60">LED_RED</gnm:Cell> - <gnm:Cell Row="12" Col="6" ValueType="60">PA17</gnm:Cell> - <gnm:Cell Row="12" Col="7" ValueType="60">LED_RED</gnm:Cell> - <gnm:Cell Row="12" Col="8" ValueType="60">LED2</gnm:Cell> + <gnm:Cell Row="12" Col="3" ValueType="60">PA17</gnm:Cell> + <gnm:Cell Row="12" Col="4" ValueType="60">LED_R</gnm:Cell> + <gnm:Cell Row="12" Col="5" ValueType="60">PA17</gnm:Cell> + <gnm:Cell Row="12" Col="6" ValueType="60">LED_RED</gnm:Cell> + <gnm:Cell Row="12" Col="7" ValueType="60">PA17</gnm:Cell> + <gnm:Cell Row="12" Col="8" ValueType="60">LED_RED</gnm:Cell> + <gnm:Cell Row="12" Col="9" ValueType="60">LED2</gnm:Cell> + <gnm:Cell Row="12" Col="11" ValueType="60">PA17</gnm:Cell> + <gnm:Cell Row="12" Col="12" ValueType="60">LED_RED</gnm:Cell> <gnm:Cell Row="13" Col="0" ValueType="40">10</gnm:Cell> - <gnm:Cell Row="13" Col="1" ValueType="60">PA18</gnm:Cell> + <gnm:Cell Row="13" Col="1" ValueType="40">10</gnm:Cell> <gnm:Cell Row="13" Col="2" ValueType="60">PA18</gnm:Cell> - <gnm:Cell Row="13" Col="3" ValueType="60">LED_G</gnm:Cell> - <gnm:Cell Row="13" Col="4" ValueType="60">PA18</gnm:Cell> - <gnm:Cell Row="13" Col="5" ValueType="60">LED_GREEN</gnm:Cell> - <gnm:Cell Row="13" Col="6" ValueType="60">PA18</gnm:Cell> - <gnm:Cell Row="13" Col="7" ValueType="60">LED_GREEN</gnm:Cell> - <gnm:Cell Row="13" Col="8" ValueType="60">LED1</gnm:Cell> + <gnm:Cell Row="13" Col="3" ValueType="60">PA18</gnm:Cell> + <gnm:Cell Row="13" Col="4" ValueType="60">LED_G</gnm:Cell> + <gnm:Cell Row="13" Col="5" ValueType="60">PA18</gnm:Cell> + <gnm:Cell Row="13" Col="6" ValueType="60">LED_GREEN</gnm:Cell> + <gnm:Cell Row="13" Col="7" ValueType="60">PA18</gnm:Cell> + <gnm:Cell Row="13" Col="8" ValueType="60">LED_GREEN</gnm:Cell> + <gnm:Cell Row="13" Col="9" ValueType="60">LED1</gnm:Cell> + <gnm:Cell Row="13" Col="11" ValueType="60">PA18</gnm:Cell> + <gnm:Cell Row="13" Col="12" ValueType="60">LED_GREEN</gnm:Cell> <gnm:Cell Row="14" Col="0" ValueType="40">11</gnm:Cell> - <gnm:Cell Row="14" Col="1" ValueType="60">PA21/RXD1/PCK1</gnm:Cell> - <gnm:Cell Row="14" Col="2" ValueType="60">RXD1</gnm:Cell> - <gnm:Cell Row="14" Col="3" ValueType="60">I/O_PHONE</gnm:Cell> - <gnm:Cell Row="14" Col="4" ValueType="60">RXD1</gnm:Cell> - <gnm:Cell Row="14" Col="5" ValueType="60">ST_USIM1_IO</gnm:Cell> - <gnm:Cell Row="14" Col="6" ValueType="60">RXD1</gnm:Cell> - <gnm:Cell Row="14" Col="7" ValueType="60">ST_USIM1_IO</gnm:Cell> - <gnm:Cell Row="14" Col="8" ValueType="60">RXD1</gnm:Cell> - <gnm:Cell Row="15" Col="0" ValueType="40">12</gnm:Cell> - <gnm:Cell Row="15" Col="1" ValueType="60">VDDCORE</gnm:Cell> - <gnm:Cell Row="16" Col="0" ValueType="40">13</gnm:Cell> - <gnm:Cell Row="16" Col="1" ValueType="60">PA19/RK/FIQ</gnm:Cell> - <gnm:Cell Row="16" Col="2" ValueType="60">PA19</gnm:Cell> - <gnm:Cell Row="16" Col="3" ValueType="60">I/O_SW</gnm:Cell> - <gnm:Cell Row="16" Col="4" ValueType="60">AD2</gnm:Cell> - <gnm:Cell Row="16" Col="5" ValueType="60">VERSION_DETECT12</gnm:Cell> - <gnm:Cell Row="16" Col="7" ValueType="60">NC</gnm:Cell> - <gnm:Cell Row="16" Col="8" ValueType="60">B1</gnm:Cell> - <gnm:Cell Row="17" Col="0" ValueType="40">14</gnm:Cell> - <gnm:Cell Row="17" Col="1" ValueType="60">PA22/TXD1/NPCS3</gnm:Cell> - <gnm:Cell Row="17" Col="2" ValueType="60">TXD1</gnm:Cell> - <gnm:Cell Row="17" Col="3" ValueType="60">I/O_PHONE</gnm:Cell> - <gnm:Cell Row="17" Col="4" ValueType="60">TXD1</gnm:Cell> - <gnm:Cell Row="17" Col="5" ValueType="60">ST_USIM1_IO</gnm:Cell> - <gnm:Cell Row="17" Col="6" ValueType="60">TXD1</gnm:Cell> - <gnm:Cell Row="17" Col="7" ValueType="60">ST_USIM1_IO</gnm:Cell> - <gnm:Cell Row="17" Col="8" ValueType="60">TXD1</gnm:Cell> - <gnm:Cell Row="18" Col="0" ValueType="40">15</gnm:Cell> - <gnm:Cell Row="18" Col="1" ValueType="60">PA23/SCK1/PWM0</gnm:Cell> - <gnm:Cell Row="18" Col="2" ValueType="60">SCK1</gnm:Cell> - <gnm:Cell Row="18" Col="3" ValueType="60">CLK_PHONE</gnm:Cell> - <gnm:Cell Row="18" Col="4" ValueType="60">SCK1</gnm:Cell> - <gnm:Cell Row="18" Col="5" ValueType="60">ST_USIM1_CLK</gnm:Cell> - <gnm:Cell Row="18" Col="6" ValueType="60">SCK1</gnm:Cell> - <gnm:Cell Row="18" Col="7" ValueType="60">ST_USIM1_CLK</gnm:Cell> - <gnm:Cell Row="19" Col="0" ValueType="40">16</gnm:Cell> - <gnm:Cell Row="19" Col="1" ValueType="60">PA20/RF/IRQ0/AD3</gnm:Cell> - <gnm:Cell Row="19" Col="2" ValueType="60">PA20</gnm:Cell> - <gnm:Cell Row="19" Col="3" ValueType="60">SC_SW</gnm:Cell> - <gnm:Cell Row="19" Col="4" ValueType="60">PA20</gnm:Cell> - <gnm:Cell Row="19" Col="5" ValueType="60">!CONNECT_ST_USIM1</gnm:Cell> - <gnm:Cell Row="19" Col="7" ValueType="60">NC</gnm:Cell> - <gnm:Cell Row="19" Col="8" ValueType="60">B2</gnm:Cell> - <gnm:Cell Row="20" Col="0" ValueType="40">17</gnm:Cell> - <gnm:Cell Row="20" Col="1" ValueType="60">GND</gnm:Cell> - <gnm:Cell Row="21" Col="0" ValueType="40">18</gnm:Cell> - <gnm:Cell Row="21" Col="1" ValueType="60">VDDIO</gnm:Cell> - <gnm:Cell Row="22" Col="0" ValueType="40">19</gnm:Cell> - <gnm:Cell Row="22" Col="1" ValueType="60">PA16/TK/TIOB1</gnm:Cell> - <gnm:Cell Row="22" Col="2" ValueType="60">PA16</gnm:Cell> - <gnm:Cell Row="22" Col="3" ValueType="60">!UDP_PUP</gnm:Cell> - <gnm:Cell Row="22" Col="4" ValueType="60">PA16</gnm:Cell> - <gnm:Cell Row="22" Col="5" ValueType="60">WWAN2</gnm:Cell> - <gnm:Cell Row="22" Col="6" ValueType="60">PA16</gnm:Cell> - <gnm:Cell Row="22" Col="7" ValueType="60">UDP_PUP_CTL</gnm:Cell> - <gnm:Cell Row="22" Col="8" ValueType="60">DP_PUP</gnm:Cell> - <gnm:Cell Row="23" Col="0" ValueType="40">20</gnm:Cell> - <gnm:Cell Row="23" Col="1" ValueType="60">PA15/TF/TIOA1</gnm:Cell> - <gnm:Cell Row="23" Col="2" ValueType="60">PA15</gnm:Cell> - <gnm:Cell Row="23" Col="3" ValueType="60">WP</gnm:Cell> - <gnm:Cell Row="23" Col="4" ValueType="60">PA15</gnm:Cell> - <gnm:Cell Row="23" Col="5" ValueType="60">WWAN1</gnm:Cell> - <gnm:Cell Row="23" Col="7" ValueType="60">NC</gnm:Cell> - <gnm:Cell Row="24" Col="0" ValueType="40">21</gnm:Cell> - <gnm:Cell Row="24" Col="1" ValueType="60">PA14/SPCK/PWM3</gnm:Cell> - <gnm:Cell Row="24" Col="2" ValueType="60">SPCK</gnm:Cell> - <gnm:Cell Row="24" Col="3" ValueType="60">SCK</gnm:Cell> - <gnm:Cell Row="24" Col="4" ValueType="60">PA14</gnm:Cell> - <gnm:Cell Row="24" Col="5" ValueType="60">ST12_ST34_SELECT</gnm:Cell> - <gnm:Cell Row="24" Col="6" ValueType="60">PA14</gnm:Cell> - <gnm:Cell Row="24" Col="7" ValueType="60">SET_USIM2_PRES</gnm:Cell> - <gnm:Cell Row="24" Col="8" ValueType="60">SPCK</gnm:Cell> - <gnm:Cell Row="25" Col="0" ValueType="40">22</gnm:Cell> - <gnm:Cell Row="25" Col="1" ValueType="60">PA13/MOSI/PWM2</gnm:Cell> - <gnm:Cell Row="25" Col="2" ValueType="60">MOSI</gnm:Cell> + <gnm:Cell Row="14" Col="1" ValueType="40">11</gnm:Cell> + <gnm:Cell Row="14" Col="2" ValueType="60">PA21/RXD1/PCK1</gnm:Cell> + <gnm:Cell Row="14" Col="3" ValueType="60">RXD1</gnm:Cell> + <gnm:Cell Row="14" Col="4" ValueType="60">I/O_PHONE</gnm:Cell> + <gnm:Cell Row="14" Col="5" ValueType="60">RXD1</gnm:Cell> + <gnm:Cell Row="14" Col="6" ValueType="60">ST_USIM1_IO</gnm:Cell> + <gnm:Cell Row="14" Col="7" ValueType="60">RXD1</gnm:Cell> + <gnm:Cell Row="14" Col="8" ValueType="60">ST_USIM1_IO</gnm:Cell> + <gnm:Cell Row="14" Col="9" ValueType="60">RXD1</gnm:Cell> + <gnm:Cell Row="14" Col="12" ValueType="60">ST_UART1_IO</gnm:Cell> + <gnm:Cell Row="15" Col="1" ValueType="40">12</gnm:Cell> + <gnm:Cell Row="15" Col="2" ValueType="60">VDDCORE</gnm:Cell> + <gnm:Cell Row="16" Col="1" ValueType="40">13</gnm:Cell> + <gnm:Cell Row="16" Col="2" ValueType="60">PA19/RK/FIQ</gnm:Cell> + <gnm:Cell Row="16" Col="3" ValueType="60">PA19</gnm:Cell> + <gnm:Cell Row="16" Col="4" ValueType="60">I/O_SW</gnm:Cell> + <gnm:Cell Row="16" Col="5" ValueType="60">AD2</gnm:Cell> + <gnm:Cell Row="16" Col="6" ValueType="60">VERSION_DETECT12</gnm:Cell> + <gnm:Cell Row="16" Col="8" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="16" Col="9" ValueType="60">B1</gnm:Cell> + <gnm:Cell Row="16" Col="11" ValueType="60">AD2</gnm:Cell> + <gnm:Cell Row="16" Col="12" ValueType="60">VERSION_DETECT</gnm:Cell> + <gnm:Cell Row="17" Col="1" ValueType="40">14</gnm:Cell> + <gnm:Cell Row="17" Col="2" ValueType="60">PA22/TXD1/NPCS3</gnm:Cell> + <gnm:Cell Row="17" Col="3" ValueType="60">TXD1</gnm:Cell> + <gnm:Cell Row="17" Col="4" ValueType="60">I/O_PHONE</gnm:Cell> + <gnm:Cell Row="17" Col="5" ValueType="60">TXD1</gnm:Cell> + <gnm:Cell Row="17" Col="6" ValueType="60">ST_USIM1_IO</gnm:Cell> + <gnm:Cell Row="17" Col="7" ValueType="60">TXD1</gnm:Cell> + <gnm:Cell Row="17" Col="8" ValueType="60">ST_USIM1_IO</gnm:Cell> + <gnm:Cell Row="17" Col="9" ValueType="60">TXD1</gnm:Cell> + <gnm:Cell Row="17" Col="11" ValueType="60">TXD1</gnm:Cell> + <gnm:Cell Row="17" Col="12" ValueType="60">ST_UART1_IO</gnm:Cell> + <gnm:Cell Row="18" Col="1" ValueType="40">15</gnm:Cell> + <gnm:Cell Row="18" Col="2" ValueType="60">PA23/SCK1/PWM0</gnm:Cell> + <gnm:Cell Row="18" Col="3" ValueType="60">SCK1</gnm:Cell> + <gnm:Cell Row="18" Col="4" ValueType="60">CLK_PHONE</gnm:Cell> + <gnm:Cell Row="18" Col="5" ValueType="60">SCK1</gnm:Cell> + <gnm:Cell Row="18" Col="6" ValueType="60">ST_USIM1_CLK</gnm:Cell> + <gnm:Cell Row="18" Col="7" ValueType="60">SCK1</gnm:Cell> + <gnm:Cell Row="18" Col="8" ValueType="60">ST_USIM1_CLK</gnm:Cell> + <gnm:Cell Row="18" Col="11" ValueType="60">SCK1</gnm:Cell> + <gnm:Cell Row="18" Col="12" ValueType="60">ST_UART1_CLK</gnm:Cell> + <gnm:Cell Row="19" Col="0" ValueType="40">12</gnm:Cell> + <gnm:Cell Row="19" Col="1" ValueType="40">16</gnm:Cell> + <gnm:Cell Row="19" Col="2" ValueType="60">PA20/RF/IRQ0/AD3</gnm:Cell> + <gnm:Cell Row="19" Col="3" ValueType="60">PA20</gnm:Cell> + <gnm:Cell Row="19" Col="4" ValueType="60">SC_SW</gnm:Cell> + <gnm:Cell Row="19" Col="5" ValueType="60">PA20</gnm:Cell> + <gnm:Cell Row="19" Col="6" ValueType="60">!CONNECT_ST_USIM1</gnm:Cell> + <gnm:Cell Row="19" Col="8" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="19" Col="9" ValueType="60">B2</gnm:Cell> + <gnm:Cell Row="19" Col="11" ValueType="60">PA20</gnm:Cell> + <gnm:Cell Row="19" Col="12" ValueType="60">!CONNECT_UART1</gnm:Cell> + <gnm:Cell Row="20" Col="1" ValueType="40">17</gnm:Cell> + <gnm:Cell Row="20" Col="2" ValueType="60">GND</gnm:Cell> + <gnm:Cell Row="21" Col="0" ValueType="40">13</gnm:Cell> + <gnm:Cell Row="21" Col="1" ValueType="40">18</gnm:Cell> + <gnm:Cell Row="21" Col="2" ValueType="60">VDDIO</gnm:Cell> + <gnm:Cell Row="22" Col="0" ValueType="40">14</gnm:Cell> + <gnm:Cell Row="22" Col="1" ValueType="40">19</gnm:Cell> + <gnm:Cell Row="22" Col="2" ValueType="60">PA16/TK/TIOB1</gnm:Cell> + <gnm:Cell Row="22" Col="3" ValueType="60">PA16</gnm:Cell> + <gnm:Cell Row="22" Col="4" ValueType="60">!UDP_PUP</gnm:Cell> + <gnm:Cell Row="22" Col="5" ValueType="60">PA16</gnm:Cell> + <gnm:Cell Row="22" Col="6" ValueType="60">WWAN2</gnm:Cell> + <gnm:Cell Row="22" Col="7" ValueType="60">PA16</gnm:Cell> + <gnm:Cell Row="22" Col="8" ValueType="60">UDP_PUP_CTL</gnm:Cell> + <gnm:Cell Row="22" Col="9" ValueType="60">DP_PUP</gnm:Cell> + <gnm:Cell Row="22" Col="11" ValueType="60">PA16</gnm:Cell> + <gnm:Cell Row="22" Col="12" ValueType="60">EN_MDM_SIM_VDD</gnm:Cell> + <gnm:Cell Row="23" Col="0" ValueType="40">15</gnm:Cell> + <gnm:Cell Row="23" Col="1" ValueType="40">20</gnm:Cell> + <gnm:Cell Row="23" Col="2" ValueType="60">PA15/TF/TIOA1</gnm:Cell> + <gnm:Cell Row="23" Col="3" ValueType="60">PA15</gnm:Cell> + <gnm:Cell Row="23" Col="4" ValueType="60">WP</gnm:Cell> + <gnm:Cell Row="23" Col="5" ValueType="60">PA15</gnm:Cell> + <gnm:Cell Row="23" Col="6" ValueType="60">WWAN1</gnm:Cell> + <gnm:Cell Row="23" Col="8" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="23" Col="11" ValueType="60">PA15</gnm:Cell> + <gnm:Cell Row="23" Col="12" ValueType="60">WWAN1</gnm:Cell> + <gnm:Cell Row="24" Col="0" ValueType="40">16</gnm:Cell> + <gnm:Cell Row="24" Col="1" ValueType="40">21</gnm:Cell> + <gnm:Cell Row="24" Col="2" ValueType="60">PA14/SPCK/PWM3</gnm:Cell> + <gnm:Cell Row="24" Col="3" ValueType="60">SPCK</gnm:Cell> + <gnm:Cell Row="24" Col="4" ValueType="60">SCK</gnm:Cell> + <gnm:Cell Row="24" Col="5" ValueType="60">PA14</gnm:Cell> + <gnm:Cell Row="24" Col="6" ValueType="60">ST12_ST34_SELECT</gnm:Cell> + <gnm:Cell Row="24" Col="7" ValueType="60">PA14</gnm:Cell> + <gnm:Cell Row="24" Col="8" ValueType="60">SET_USIM2_PRES</gnm:Cell> + <gnm:Cell Row="24" Col="9" ValueType="60">SPCK</gnm:Cell> + <gnm:Cell Row="24" Col="11" ValueType="60">PA14</gnm:Cell> + <gnm:Cell Row="24" Col="12" ValueType="60">!ALARM_ST_SIM_VDD</gnm:Cell> + <gnm:Cell Row="25" Col="0" ValueType="40">17</gnm:Cell> + <gnm:Cell Row="25" Col="1" ValueType="40">22</gnm:Cell> + <gnm:Cell Row="25" Col="2" ValueType="60">PA13/MOSI/PWM2</gnm:Cell> <gnm:Cell Row="25" Col="3" ValueType="60">MOSI</gnm:Cell> - <gnm:Cell Row="25" Col="4" ValueType="60">PA13</gnm:Cell> - <gnm:Cell Row="25" Col="5" ValueType="60">HUB_RESET</gnm:Cell> - <gnm:Cell Row="25" Col="7" ValueType="60">NC</gnm:Cell> - <gnm:Cell Row="25" Col="8" ValueType="60">MOSI</gnm:Cell> - <gnm:Cell Row="26" Col="0" ValueType="40">23</gnm:Cell> - <gnm:Cell Row="26" Col="1" ValueType="60">PA24/RTS1/PWM1</gnm:Cell> - <gnm:Cell Row="26" Col="2" ValueType="60">PA24</gnm:Cell> - <gnm:Cell Row="26" Col="3" ValueType="60">RST_PHONE</gnm:Cell> - <gnm:Cell Row="26" Col="4" ValueType="60">PA24</gnm:Cell> - <gnm:Cell Row="26" Col="5" ValueType="60">!ST_USIM1_RST</gnm:Cell> - <gnm:Cell Row="26" Col="6" ValueType="60">PA24</gnm:Cell> - <gnm:Cell Row="26" Col="7" ValueType="60">!ST_USIM1_RST</gnm:Cell> - <gnm:Cell Row="27" Col="0" ValueType="40">24</gnm:Cell> - <gnm:Cell Row="27" Col="1" ValueType="60">VDDCORE</gnm:Cell> - <gnm:Cell Row="28" Col="0" ValueType="40">25</gnm:Cell> - <gnm:Cell Row="28" Col="1" ValueType="60">PA25/CTS1/PWM2</gnm:Cell> - <gnm:Cell Row="28" Col="2" ValueType="60">PA25</gnm:Cell> - <gnm:Cell Row="28" Col="3" ValueType="60">VCC_PHONE</gnm:Cell> - <gnm:Cell Row="28" Col="4" ValueType="60">PA25</gnm:Cell> - <gnm:Cell Row="28" Col="5" ValueType="60">PERST1</gnm:Cell> - <gnm:Cell Row="28" Col="7" ValueType="60">NC</gnm:Cell> - <gnm:Cell Row="29" Col="0" ValueType="40">26</gnm:Cell> - <gnm:Cell Row="29" Col="1" ValueType="60">PA26/DCD1/TIOA2</gnm:Cell> - <gnm:Cell Row="29" Col="2" ValueType="60">PA26</gnm:Cell> - <gnm:Cell Row="29" Col="3" ValueType="60">VCC_FWD</gnm:Cell> - <gnm:Cell Row="29" Col="4" ValueType="60">PA26</gnm:Cell> - <gnm:Cell Row="29" Col="5" ValueType="60">PERST2</gnm:Cell> - <gnm:Cell Row="29" Col="7" ValueType="60">NC</gnm:Cell> - <gnm:Cell Row="30" Col="0" ValueType="40">27</gnm:Cell> - <gnm:Cell Row="30" Col="1" ValueType="60">PA12/MISO/PWM1</gnm:Cell> - <gnm:Cell Row="30" Col="2" ValueType="60">MISO</gnm:Cell> + <gnm:Cell Row="25" Col="4" ValueType="60">MOSI</gnm:Cell> + <gnm:Cell Row="25" Col="5" ValueType="60">PA13</gnm:Cell> + <gnm:Cell Row="25" Col="6" ValueType="60">HUB_RESET</gnm:Cell> + <gnm:Cell Row="25" Col="8" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="25" Col="9" ValueType="60">MOSI</gnm:Cell> + <gnm:Cell Row="25" Col="11" ValueType="60">PA13</gnm:Cell> + <gnm:Cell Row="25" Col="12" ValueType="60">!SET_SIM_DET</gnm:Cell> + <gnm:Cell Row="26" Col="1" ValueType="40">23</gnm:Cell> + <gnm:Cell Row="26" Col="2" ValueType="60">PA24/RTS1/PWM1</gnm:Cell> + <gnm:Cell Row="26" Col="3" ValueType="60">PA24</gnm:Cell> + <gnm:Cell Row="26" Col="4" ValueType="60">RST_PHONE</gnm:Cell> + <gnm:Cell Row="26" Col="5" ValueType="60">PA24</gnm:Cell> + <gnm:Cell Row="26" Col="6" ValueType="60">!ST_USIM1_RST</gnm:Cell> + <gnm:Cell Row="26" Col="7" ValueType="60">PA24</gnm:Cell> + <gnm:Cell Row="26" Col="8" ValueType="60">!ST_USIM1_RST</gnm:Cell> + <gnm:Cell Row="26" Col="11" ValueType="60">PA24</gnm:Cell> + <gnm:Cell Row="26" Col="12" ValueType="60">!ST_UART1_RST</gnm:Cell> + <gnm:Cell Row="27" Col="0" ValueType="40">18</gnm:Cell> + <gnm:Cell Row="27" Col="1" ValueType="40">24</gnm:Cell> + <gnm:Cell Row="27" Col="2" ValueType="60">VDDCORE</gnm:Cell> + <gnm:Cell Row="28" Col="1" ValueType="40">25</gnm:Cell> + <gnm:Cell Row="28" Col="2" ValueType="60">PA25/CTS1/PWM2</gnm:Cell> + <gnm:Cell Row="28" Col="3" ValueType="60">PA25</gnm:Cell> + <gnm:Cell Row="28" Col="4" ValueType="60">VCC_PHONE</gnm:Cell> + <gnm:Cell Row="28" Col="5" ValueType="60">PA25</gnm:Cell> + <gnm:Cell Row="28" Col="6" ValueType="60">PERST1</gnm:Cell> + <gnm:Cell Row="28" Col="8" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="28" Col="11" ValueType="60">PA25</gnm:Cell> + <gnm:Cell Row="28" Col="12" ValueType="60">PERST</gnm:Cell> + <gnm:Cell Row="29" Col="1" ValueType="40">26</gnm:Cell> + <gnm:Cell Row="29" Col="2" ValueType="60">PA26/DCD1/TIOA2</gnm:Cell> + <gnm:Cell Row="29" Col="3" ValueType="60">PA26</gnm:Cell> + <gnm:Cell Row="29" Col="4" ValueType="60">VCC_FWD</gnm:Cell> + <gnm:Cell Row="29" Col="5" ValueType="60">PA26</gnm:Cell> + <gnm:Cell Row="29" Col="6" ValueType="60">PERST2</gnm:Cell> + <gnm:Cell Row="29" Col="8" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="29" Col="11" ValueType="60">PA26</gnm:Cell> + <gnm:Cell Row="29" Col="12" ValueType="60">!PWR_ON</gnm:Cell> + <gnm:Cell Row="30" Col="0" ValueType="40">19</gnm:Cell> + <gnm:Cell Row="30" Col="1" ValueType="40">27</gnm:Cell> + <gnm:Cell Row="30" Col="2" ValueType="60">PA12/MISO/PWM1</gnm:Cell> <gnm:Cell Row="30" Col="3" ValueType="60">MISO</gnm:Cell> - <gnm:Cell Row="30" Col="4" ValueType="60">NC</gnm:Cell> - <gnm:Cell Row="30" Col="5" ValueType="60">SIMPRES1</gnm:Cell> - <gnm:Cell Row="30" Col="6" ValueType="60">PA12</gnm:Cell> - <gnm:Cell Row="30" Col="7" ValueType="60">SET_USIM1_PRES</gnm:Cell> - <gnm:Cell Row="30" Col="8" ValueType="60">MISO</gnm:Cell> - <gnm:Cell Row="31" Col="0" ValueType="40">28</gnm:Cell> - <gnm:Cell Row="31" Col="1" ValueType="60">PA11/NPCS0/PWM0</gnm:Cell> - <gnm:Cell Row="31" Col="2" ValueType="60">NPCS0</gnm:Cell> - <gnm:Cell Row="31" Col="3" ValueType="60">CS</gnm:Cell> - <gnm:Cell Row="31" Col="4" ValueType="60">PA11</gnm:Cell> - <gnm:Cell Row="31" Col="5" ValueType="60">_SIMTRACE34_ERASE</gnm:Cell> - <gnm:Cell Row="31" Col="7" ValueType="60">NC</gnm:Cell> - <gnm:Cell Row="31" Col="8" ValueType="60">NPCS0</gnm:Cell> - <gnm:Cell Row="32" Col="0" ValueType="40">29</gnm:Cell> - <gnm:Cell Row="32" Col="1" ValueType="60">PA10/DTXD/NCPS2</gnm:Cell> - <gnm:Cell Row="32" Col="2" ValueType="60">DTXD</gnm:Cell> + <gnm:Cell Row="30" Col="4" ValueType="60">MISO</gnm:Cell> + <gnm:Cell Row="30" Col="5" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="30" Col="6" ValueType="60">SIMPRES1</gnm:Cell> + <gnm:Cell Row="30" Col="7" ValueType="60">PA12</gnm:Cell> + <gnm:Cell Row="30" Col="8" ValueType="60">SET_USIM1_PRES</gnm:Cell> + <gnm:Cell Row="30" Col="9" ValueType="60">MISO</gnm:Cell> + <gnm:Cell Row="30" Col="12" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="31" Col="0" ValueType="40">20</gnm:Cell> + <gnm:Cell Row="31" Col="1" ValueType="40">28</gnm:Cell> + <gnm:Cell Row="31" Col="2" ValueType="60">PA11/NPCS0/PWM0</gnm:Cell> + <gnm:Cell Row="31" Col="3" ValueType="60">NPCS0</gnm:Cell> + <gnm:Cell Row="31" Col="4" ValueType="60">CS</gnm:Cell> + <gnm:Cell Row="31" Col="5" ValueType="60">PA11</gnm:Cell> + <gnm:Cell Row="31" Col="6" ValueType="60">_SIMTRACE34_ERASE</gnm:Cell> + <gnm:Cell Row="31" Col="8" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="31" Col="9" ValueType="60">NPCS0</gnm:Cell> + <gnm:Cell Row="31" Col="11" ValueType="60">PA11</gnm:Cell> + <gnm:Cell Row="31" Col="12" ValueType="60">MODEM_EN</gnm:Cell> + <gnm:Cell Row="32" Col="0" ValueType="40">21</gnm:Cell> + <gnm:Cell Row="32" Col="1" ValueType="40">29</gnm:Cell> + <gnm:Cell Row="32" Col="2" ValueType="60">PA10/DTXD/NCPS2</gnm:Cell> <gnm:Cell Row="32" Col="3" ValueType="60">DTXD</gnm:Cell> <gnm:Cell Row="32" Col="4" ValueType="60">DTXD</gnm:Cell> - <gnm:Cell Row="32" Col="5" ValueType="60">SIMTRACE1_DTXD</gnm:Cell> - <gnm:Cell Row="32" Col="6" ValueType="60">DTXD</gnm:Cell> - <gnm:Cell Row="32" Col="7" ValueType="60">SIMTRACE_DTXD</gnm:Cell> - <gnm:Cell Row="32" Col="8" ValueType="60">DTXD</gnm:Cell> - <gnm:Cell Row="33" Col="0" ValueType="40">30</gnm:Cell> - <gnm:Cell Row="33" Col="1" ValueType="60">PA9/DRXDNPCS1</gnm:Cell> - <gnm:Cell Row="33" Col="2" ValueType="60">DRXD</gnm:Cell> + <gnm:Cell Row="32" Col="5" ValueType="60">DTXD</gnm:Cell> + <gnm:Cell Row="32" Col="6" ValueType="60">SIMTRACE1_DTXD</gnm:Cell> + <gnm:Cell Row="32" Col="7" ValueType="60">DTXD</gnm:Cell> + <gnm:Cell Row="32" Col="8" ValueType="60">SIMTRACE_DTXD</gnm:Cell> + <gnm:Cell Row="32" Col="9" ValueType="60">DTXD</gnm:Cell> + <gnm:Cell Row="32" Col="11" ValueType="60">DTXD</gnm:Cell> + <gnm:Cell Row="33" Col="0" ValueType="40">22</gnm:Cell> + <gnm:Cell Row="33" Col="1" ValueType="40">30</gnm:Cell> + <gnm:Cell Row="33" Col="2" ValueType="60">PA9/DRXDNPCS1</gnm:Cell> <gnm:Cell Row="33" Col="3" ValueType="60">DRXD</gnm:Cell> <gnm:Cell Row="33" Col="4" ValueType="60">DRXD</gnm:Cell> - <gnm:Cell Row="33" Col="5" ValueType="60">SIMTRACE1_DRXD</gnm:Cell> - <gnm:Cell Row="33" Col="6" ValueType="60">DRXD</gnm:Cell> - <gnm:Cell Row="33" Col="7" ValueType="60">SIMTRACE_DRXD</gnm:Cell> - <gnm:Cell Row="33" Col="8" ValueType="60">DRXD</gnm:Cell> - <gnm:Cell Row="34" Col="0" ValueType="40">31</gnm:Cell> - <gnm:Cell Row="34" Col="1" ValueType="60">PA8/CTS0/ADTRG</gnm:Cell> - <gnm:Cell Row="34" Col="2" ValueType="60">PA8</gnm:Cell> - <gnm:Cell Row="34" Col="3" ValueType="60">SW_SIM</gnm:Cell> - <gnm:Cell Row="34" Col="4" ValueType="60">PA8</gnm:Cell> - <gnm:Cell Row="34" Col="5" ValueType="60">SIMPRES2 / ST12_PRTPWR-OVERRIDE</gnm:Cell> - <gnm:Cell Row="34" Col="7" ValueType="60">NC</gnm:Cell> - <gnm:Cell Row="34" Col="8" ValueType="60">DM_PUP</gnm:Cell> - <gnm:Cell Row="35" Col="0" ValueType="40">32</gnm:Cell> - <gnm:Cell Row="35" Col="1" ValueType="60">PA7/RTS0/PWM3</gnm:Cell> - <gnm:Cell Row="35" Col="2" ValueType="60">PA7</gnm:Cell> - <gnm:Cell Row="35" Col="3" ValueType="60">RST_SIM</gnm:Cell> - <gnm:Cell Row="35" Col="4" ValueType="60">PA7</gnm:Cell> - <gnm:Cell Row="35" Col="5" ValueType="60">!ST_USIM2_RST</gnm:Cell> - <gnm:Cell Row="35" Col="6" ValueType="60">PA7</gnm:Cell> - <gnm:Cell Row="35" Col="7" ValueType="60">!ST_USIM2_RST</gnm:Cell> - <gnm:Cell Row="36" Col="0" ValueType="40">33</gnm:Cell> - <gnm:Cell Row="36" Col="1" ValueType="60">TDI</gnm:Cell> - <gnm:Cell Row="36" Col="4" ValueType="60">TDI</gnm:Cell> - <gnm:Cell Row="36" Col="5" ValueType="60">SIMTRACE12_TDI</gnm:Cell> - <gnm:Cell Row="37" Col="0" ValueType="40">34</gnm:Cell> - <gnm:Cell Row="37" Col="1" ValueType="60">PA6/TXD0/PCK0</gnm:Cell> - <gnm:Cell Row="37" Col="3" ValueType="60">I/O_SIM</gnm:Cell> - <gnm:Cell Row="37" Col="4" ValueType="60">TXD0</gnm:Cell> - <gnm:Cell Row="37" Col="5" ValueType="60">ST_USIM2_IO</gnm:Cell> - <gnm:Cell Row="37" Col="6" ValueType="60">TXD0</gnm:Cell> - <gnm:Cell Row="37" Col="7" ValueType="60">ST_USIM2_IO</gnm:Cell> - <gnm:Cell Row="38" Col="0" ValueType="40">35</gnm:Cell> - <gnm:Cell Row="38" Col="1" ValueType="60">PA5/RXD0/NPCS3</gnm:Cell> - <gnm:Cell Row="38" Col="2" ValueType="60">PA5</gnm:Cell> - <gnm:Cell Row="38" Col="3" ValueType="60">SIM_PWEN</gnm:Cell> - <gnm:Cell Row="38" Col="4" ValueType="60">RXD0</gnm:Cell> - <gnm:Cell Row="38" Col="5" ValueType="60">ST_USIM2_IO</gnm:Cell> - <gnm:Cell Row="38" Col="6" ValueType="60">RXD0</gnm:Cell> - <gnm:Cell Row="38" Col="7" ValueType="60">ST_USIM2_IO</gnm:Cell> - <gnm:Cell Row="39" Col="0" ValueType="40">36</gnm:Cell> - <gnm:Cell Row="39" Col="1" ValueType="60">PA4/TWCK/TCLK0</gnm:Cell> - <gnm:Cell Row="39" Col="2" ValueType="60">TCLK0</gnm:Cell> - <gnm:Cell Row="39" Col="3" ValueType="60">CLK_SIM</gnm:Cell> - <gnm:Cell Row="39" Col="4" ValueType="60">TCLK0</gnm:Cell> - <gnm:Cell Row="39" Col="5" ValueType="60">ST_USIM2_CLK</gnm:Cell> - <gnm:Cell Row="39" Col="6" ValueType="60">TCLK0</gnm:Cell> - <gnm:Cell Row="39" Col="7" ValueType="60">ST_USIM2_CLK</gnm:Cell> - <gnm:Cell Row="39" Col="8" ValueType="60">TWCK</gnm:Cell> - <gnm:Cell Row="40" Col="0" ValueType="40">37</gnm:Cell> - <gnm:Cell Row="40" Col="1" ValueType="60">PA27/DTR1/TIOB2</gnm:Cell> - <gnm:Cell Row="40" Col="2" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="33" Col="5" ValueType="60">DRXD</gnm:Cell> + <gnm:Cell Row="33" Col="6" ValueType="60">SIMTRACE1_DRXD</gnm:Cell> + <gnm:Cell Row="33" Col="7" ValueType="60">DRXD</gnm:Cell> + <gnm:Cell Row="33" Col="8" ValueType="60">SIMTRACE_DRXD</gnm:Cell> + <gnm:Cell Row="33" Col="9" ValueType="60">DRXD</gnm:Cell> + <gnm:Cell Row="33" Col="11" ValueType="60">DRXD</gnm:Cell> + <gnm:Cell Row="34" Col="0" ValueType="40">23</gnm:Cell> + <gnm:Cell Row="34" Col="1" ValueType="40">31</gnm:Cell> + <gnm:Cell Row="34" Col="2" ValueType="60">PA8/CTS0/ADTRG</gnm:Cell> + <gnm:Cell Row="34" Col="3" ValueType="60">PA8</gnm:Cell> + <gnm:Cell Row="34" Col="4" ValueType="60">SW_SIM</gnm:Cell> + <gnm:Cell Row="34" Col="5" ValueType="60">PA8</gnm:Cell> + <gnm:Cell Row="34" Col="6" ValueType="60">SIMPRES2 / ST12_PRTPWR-OVERRIDE</gnm:Cell> + <gnm:Cell Row="34" Col="8" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="34" Col="9" ValueType="60">DM_PUP</gnm:Cell> + <gnm:Cell Row="34" Col="11" ValueType="60">PA8</gnm:Cell> + <gnm:Cell Row="34" Col="12" ValueType="60">SLOT_DET</gnm:Cell> + <gnm:Cell Row="35" Col="0" ValueType="40">24</gnm:Cell> + <gnm:Cell Row="35" Col="1" ValueType="40">32</gnm:Cell> + <gnm:Cell Row="35" Col="2" ValueType="60">PA7/RTS0/PWM3</gnm:Cell> + <gnm:Cell Row="35" Col="3" ValueType="60">PA7</gnm:Cell> + <gnm:Cell Row="35" Col="4" ValueType="60">RST_SIM</gnm:Cell> + <gnm:Cell Row="35" Col="5" ValueType="60">PA7</gnm:Cell> + <gnm:Cell Row="35" Col="6" ValueType="60">!ST_USIM2_RST</gnm:Cell> + <gnm:Cell Row="35" Col="7" ValueType="60">PA7</gnm:Cell> + <gnm:Cell Row="35" Col="8" ValueType="60">!ST_USIM2_RST</gnm:Cell> + <gnm:Cell Row="35" Col="11" ValueType="60">PA7</gnm:Cell> + <gnm:Cell Row="35" Col="12" ValueType="60">!ST_UART2_RST</gnm:Cell> + <gnm:Cell Row="36" Col="0" ValueType="40">25</gnm:Cell> + <gnm:Cell Row="36" Col="1" ValueType="40">33</gnm:Cell> + <gnm:Cell Row="36" Col="2" ValueType="60">TDI</gnm:Cell> + <gnm:Cell Row="36" Col="5" ValueType="60">TDI</gnm:Cell> + <gnm:Cell Row="36" Col="6" ValueType="60">SIMTRACE12_TDI</gnm:Cell> + <gnm:Cell Row="36" Col="11" ValueType="60">TDI</gnm:Cell> + <gnm:Cell Row="37" Col="0" ValueType="40">26</gnm:Cell> + <gnm:Cell Row="37" Col="1" ValueType="40">34</gnm:Cell> + <gnm:Cell Row="37" Col="2" ValueType="60">PA6/TXD0/PCK0</gnm:Cell> + <gnm:Cell Row="37" Col="4" ValueType="60">I/O_SIM</gnm:Cell> + <gnm:Cell Row="37" Col="5" ValueType="60">TXD0</gnm:Cell> + <gnm:Cell Row="37" Col="6" ValueType="60">ST_USIM2_IO</gnm:Cell> + <gnm:Cell Row="37" Col="7" ValueType="60">TXD0</gnm:Cell> + <gnm:Cell Row="37" Col="8" ValueType="60">ST_USIM2_IO</gnm:Cell> + <gnm:Cell Row="37" Col="11" ValueType="60">TXD0</gnm:Cell> + <gnm:Cell Row="37" Col="12" ValueType="60">ST_UART2_IO</gnm:Cell> + <gnm:Cell Row="38" Col="0" ValueType="40">27</gnm:Cell> + <gnm:Cell Row="38" Col="1" ValueType="40">35</gnm:Cell> + <gnm:Cell Row="38" Col="2" ValueType="60">PA5/RXD0/NPCS3</gnm:Cell> + <gnm:Cell Row="38" Col="3" ValueType="60">PA5</gnm:Cell> + <gnm:Cell Row="38" Col="4" ValueType="60">SIM_PWEN</gnm:Cell> + <gnm:Cell Row="38" Col="5" ValueType="60">RXD0</gnm:Cell> + <gnm:Cell Row="38" Col="6" ValueType="60">ST_USIM2_IO</gnm:Cell> + <gnm:Cell Row="38" Col="7" ValueType="60">RXD0</gnm:Cell> + <gnm:Cell Row="38" Col="8" ValueType="60">ST_USIM2_IO</gnm:Cell> + <gnm:Cell Row="38" Col="11" ValueType="60">RXD0</gnm:Cell> + <gnm:Cell Row="38" Col="12" ValueType="60">ST_UART2_IO</gnm:Cell> + <gnm:Cell Row="39" Col="0" ValueType="40">28</gnm:Cell> + <gnm:Cell Row="39" Col="1" ValueType="40">36</gnm:Cell> + <gnm:Cell Row="39" Col="2" ValueType="60">PA4/TWCK/TCLK0</gnm:Cell> + <gnm:Cell Row="39" Col="3" ValueType="60">TCLK0</gnm:Cell> + <gnm:Cell Row="39" Col="4" ValueType="60">CLK_SIM</gnm:Cell> + <gnm:Cell Row="39" Col="5" ValueType="60">TCLK0</gnm:Cell> + <gnm:Cell Row="39" Col="6" ValueType="60">ST_USIM2_CLK</gnm:Cell> + <gnm:Cell Row="39" Col="7" ValueType="60">TCLK0</gnm:Cell> + <gnm:Cell Row="39" Col="8" ValueType="60">ST_USIM2_CLK</gnm:Cell> + <gnm:Cell Row="39" Col="9" ValueType="60">TWCK</gnm:Cell> + <gnm:Cell Row="39" Col="11" ValueType="60">TCLK0</gnm:Cell> + <gnm:Cell Row="39" Col="12" ValueType="60">ST_UART2_CLK</gnm:Cell> + <gnm:Cell Row="40" Col="1" ValueType="40">37</gnm:Cell> + <gnm:Cell Row="40" Col="2" ValueType="60">PA27/DTR1/TIOB2</gnm:Cell> <gnm:Cell Row="40" Col="3" ValueType="60">NC</gnm:Cell> - <gnm:Cell Row="40" Col="4" ValueType="60">TIOB2</gnm:Cell> - <gnm:Cell Row="40" Col="5" ValueType="60">ST_USIM1_IO</gnm:Cell> - <gnm:Cell Row="40" Col="6" ValueType="60">TIOB2</gnm:Cell> - <gnm:Cell Row="40" Col="7" ValueType="60">ST_USIM1_IO</gnm:Cell> - <gnm:Cell Row="41" Col="0" ValueType="40">38</gnm:Cell> - <gnm:Cell Row="41" Col="1" ValueType="60">PA28/DSR1/TCLK1</gnm:Cell> - <gnm:Cell Row="41" Col="2" ValueType="60">TCLK1</gnm:Cell> - <gnm:Cell Row="41" Col="3" ValueType="60">CLK_PHONE</gnm:Cell> - <gnm:Cell Row="41" Col="4" ValueType="60">PA28</gnm:Cell> - <gnm:Cell Row="41" Col="5" ValueType="60">!CONNET_ST_USIM2</gnm:Cell> - <gnm:Cell Row="41" Col="7" ValueType="60">NC</gnm:Cell> - <gnm:Cell Row="42" Col="0" ValueType="40">39</gnm:Cell> - <gnm:Cell Row="42" Col="1" ValueType="60">!RST</gnm:Cell> + <gnm:Cell Row="40" Col="4" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="40" Col="5" ValueType="60">TIOB2</gnm:Cell> + <gnm:Cell Row="40" Col="6" ValueType="60">ST_USIM1_IO</gnm:Cell> + <gnm:Cell Row="40" Col="7" ValueType="60">TIOB2</gnm:Cell> + <gnm:Cell Row="40" Col="8" ValueType="60">ST_USIM1_IO</gnm:Cell> + <gnm:Cell Row="40" Col="11" ValueType="60">TIOB2</gnm:Cell> + <gnm:Cell Row="40" Col="12" ValueType="60">ST_UART1_IO</gnm:Cell> + <gnm:Cell Row="41" Col="1" ValueType="40">38</gnm:Cell> + <gnm:Cell Row="41" Col="2" ValueType="60">PA28/DSR1/TCLK1</gnm:Cell> + <gnm:Cell Row="41" Col="3" ValueType="60">TCLK1</gnm:Cell> + <gnm:Cell Row="41" Col="4" ValueType="60">CLK_PHONE</gnm:Cell> + <gnm:Cell Row="41" Col="5" ValueType="60">PA28</gnm:Cell> + <gnm:Cell Row="41" Col="6" ValueType="60">!CONNET_ST_USIM2</gnm:Cell> + <gnm:Cell Row="41" Col="8" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="41" Col="11" ValueType="60">PA28</gnm:Cell> + <gnm:Cell Row="41" Col="12" ValueType="60">!CONNECT_UART2</gnm:Cell> + <gnm:Cell Row="42" Col="0" ValueType="40">29</gnm:Cell> + <gnm:Cell Row="42" Col="1" ValueType="40">39</gnm:Cell> <gnm:Cell Row="42" Col="2" ValueType="60">!RST</gnm:Cell> <gnm:Cell Row="42" Col="3" ValueType="60">!RST</gnm:Cell> <gnm:Cell Row="42" Col="4" ValueType="60">!RST</gnm:Cell> - <gnm:Cell Row="42" Col="5" ValueType="60">!SIMTRACE12_RESET</gnm:Cell> - <gnm:Cell Row="43" Col="0" ValueType="40">40</gnm:Cell> - <gnm:Cell Row="43" Col="1" ValueType="60">TST</gnm:Cell> - <gnm:Cell Row="43" Col="4" ValueType="60">TST</gnm:Cell> - <gnm:Cell Row="44" Col="0" ValueType="40">41</gnm:Cell> - <gnm:Cell Row="44" Col="1" ValueType="60">PA29/RI1/TCLK2</gnm:Cell> - <gnm:Cell Row="44" Col="2" ValueType="60">PA29</gnm:Cell> - <gnm:Cell Row="44" Col="3" ValueType="60">A-B-DETECT</gnm:Cell> - <gnm:Cell Row="44" Col="4" ValueType="60">TCLK2</gnm:Cell> - <gnm:Cell Row="44" Col="5" ValueType="60">ST_USIM1_CLK</gnm:Cell> - <gnm:Cell Row="44" Col="6" ValueType="60">TCLK2</gnm:Cell> - <gnm:Cell Row="44" Col="7" ValueType="60">ST_USIM1_CLK</gnm:Cell> - <gnm:Cell Row="45" Col="0" ValueType="40">42</gnm:Cell> - <gnm:Cell Row="45" Col="1" ValueType="60">PA30/IRQ1/NPCS2</gnm:Cell> - <gnm:Cell Row="45" Col="2" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="42" Col="5" ValueType="60">!RST</gnm:Cell> + <gnm:Cell Row="42" Col="6" ValueType="60">!SIMTRACE12_RESET</gnm:Cell> + <gnm:Cell Row="43" Col="0" ValueType="40">30</gnm:Cell> + <gnm:Cell Row="43" Col="1" ValueType="40">40</gnm:Cell> + <gnm:Cell Row="43" Col="2" ValueType="60">TST</gnm:Cell> + <gnm:Cell Row="43" Col="5" ValueType="60">TST</gnm:Cell> + <gnm:Cell Row="44" Col="1" ValueType="40">41</gnm:Cell> + <gnm:Cell Row="44" Col="2" ValueType="60">PA29/RI1/TCLK2</gnm:Cell> + <gnm:Cell Row="44" Col="3" ValueType="60">PA29</gnm:Cell> + <gnm:Cell Row="44" Col="4" ValueType="60">A-B-DETECT</gnm:Cell> + <gnm:Cell Row="44" Col="5" ValueType="60">TCLK2</gnm:Cell> + <gnm:Cell Row="44" Col="6" ValueType="60">ST_USIM1_CLK</gnm:Cell> + <gnm:Cell Row="44" Col="7" ValueType="60">TCLK2</gnm:Cell> + <gnm:Cell Row="44" Col="8" ValueType="60">ST_USIM1_CLK</gnm:Cell> + <gnm:Cell Row="44" Col="11" ValueType="60">TCLK2</gnm:Cell> + <gnm:Cell Row="44" Col="12" ValueType="60">ST_UART1_CLK</gnm:Cell> + <gnm:Cell Row="45" Col="1" ValueType="40">42</gnm:Cell> + <gnm:Cell Row="45" Col="2" ValueType="60">PA30/IRQ1/NPCS2</gnm:Cell> <gnm:Cell Row="45" Col="3" ValueType="60">NC</gnm:Cell> - <gnm:Cell Row="45" Col="4" ValueType="60">PA30</gnm:Cell> - <gnm:Cell Row="45" Col="5" ValueType="60">SDA</gnm:Cell> - <gnm:Cell Row="45" Col="7" ValueType="60">NC</gnm:Cell> - <gnm:Cell Row="46" Col="0" ValueType="40">43</gnm:Cell> - <gnm:Cell Row="46" Col="1" ValueType="60">PA3/TWD/NPCS3</gnm:Cell> - <gnm:Cell Row="46" Col="2" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="45" Col="4" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="45" Col="5" ValueType="60">PA30</gnm:Cell> + <gnm:Cell Row="45" Col="6" ValueType="60">SDA</gnm:Cell> + <gnm:Cell Row="45" Col="8" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="45" Col="11" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="46" Col="0" ValueType="40">31</gnm:Cell> + <gnm:Cell Row="46" Col="1" ValueType="40">43</gnm:Cell> + <gnm:Cell Row="46" Col="2" ValueType="60">PA3/TWD/NPCS3</gnm:Cell> <gnm:Cell Row="46" Col="3" ValueType="60">NC</gnm:Cell> <gnm:Cell Row="46" Col="4" ValueType="60">NC</gnm:Cell> <gnm:Cell Row="46" Col="5" ValueType="60">NC</gnm:Cell> - <gnm:Cell Row="46" Col="7" ValueType="60">NC</gnm:Cell> - <gnm:Cell Row="46" Col="8" ValueType="60">TWD</gnm:Cell> - <gnm:Cell Row="47" Col="0" ValueType="40">44</gnm:Cell> - <gnm:Cell Row="47" Col="1" ValueType="60">PA2/PWM2/SCK0</gnm:Cell> - <gnm:Cell Row="47" Col="2" ValueType="60">SCK0</gnm:Cell> - <gnm:Cell Row="47" Col="3" ValueType="60">CLK_SIM</gnm:Cell> - <gnm:Cell Row="47" Col="4" ValueType="60">SCK0</gnm:Cell> - <gnm:Cell Row="47" Col="5" ValueType="60">ST_USIM2_CLK</gnm:Cell> - <gnm:Cell Row="47" Col="6" ValueType="60">SCK0</gnm:Cell> - <gnm:Cell Row="47" Col="7" ValueType="60">ST_USIM2_CLK</gnm:Cell> - <gnm:Cell Row="48" Col="0" ValueType="40">45</gnm:Cell> - <gnm:Cell Row="48" Col="1" ValueType="60">VDDIO</gnm:Cell> - <gnm:Cell Row="49" Col="0" ValueType="40">46</gnm:Cell> - <gnm:Cell Row="49" Col="1" ValueType="60">GND</gnm:Cell> - <gnm:Cell Row="50" Col="0" ValueType="40">47</gnm:Cell> - <gnm:Cell Row="50" Col="1" ValueType="60">PA1/PWM1/TIOB0</gnm:Cell> - <gnm:Cell Row="50" Col="2" ValueType="60">TIOB0</gnm:Cell> - <gnm:Cell Row="50" Col="3" ValueType="60">I/O_SIM</gnm:Cell> - <gnm:Cell Row="50" Col="4" ValueType="60">TIOB0</gnm:Cell> - <gnm:Cell Row="50" Col="5" ValueType="60">ST_USIM2_IO</gnm:Cell> - <gnm:Cell Row="50" Col="6" ValueType="60">TIOB0</gnm:Cell> - <gnm:Cell Row="50" Col="7" ValueType="60">ST_USIM2_IO</gnm:Cell> - <gnm:Cell Row="51" Col="0" ValueType="40">48</gnm:Cell> - <gnm:Cell Row="51" Col="1" ValueType="60">PA0/PWM0/TIOA0</gnm:Cell> - <gnm:Cell Row="51" Col="2" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="46" Col="6" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="46" Col="8" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="46" Col="9" ValueType="60">TWD</gnm:Cell> + <gnm:Cell Row="46" Col="11" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="47" Col="0" ValueType="40">32</gnm:Cell> + <gnm:Cell Row="47" Col="1" ValueType="40">44</gnm:Cell> + <gnm:Cell Row="47" Col="2" ValueType="60">PA2/PWM2/SCK0</gnm:Cell> + <gnm:Cell Row="47" Col="3" ValueType="60">SCK0</gnm:Cell> + <gnm:Cell Row="47" Col="4" ValueType="60">CLK_SIM</gnm:Cell> + <gnm:Cell Row="47" Col="5" ValueType="60">SCK0</gnm:Cell> + <gnm:Cell Row="47" Col="6" ValueType="60">ST_USIM2_CLK</gnm:Cell> + <gnm:Cell Row="47" Col="7" ValueType="60">SCK0</gnm:Cell> + <gnm:Cell Row="47" Col="8" ValueType="60">ST_USIM2_CLK</gnm:Cell> + <gnm:Cell Row="47" Col="11" ValueType="60">SCK0</gnm:Cell> + <gnm:Cell Row="47" Col="12" ValueType="60">ST_UART2_CLK</gnm:Cell> + <gnm:Cell Row="48" Col="0" ValueType="40">33</gnm:Cell> + <gnm:Cell Row="48" Col="1" ValueType="40">45</gnm:Cell> + <gnm:Cell Row="48" Col="2" ValueType="60">VDDIO</gnm:Cell> + <gnm:Cell Row="49" Col="0" ValueType="40">34</gnm:Cell> + <gnm:Cell Row="49" Col="1" ValueType="40">46</gnm:Cell> + <gnm:Cell Row="49" Col="2" ValueType="60">GND</gnm:Cell> + <gnm:Cell Row="50" Col="0" ValueType="40">35</gnm:Cell> + <gnm:Cell Row="50" Col="1" ValueType="40">47</gnm:Cell> + <gnm:Cell Row="50" Col="2" ValueType="60">PA1/PWM1/TIOB0</gnm:Cell> + <gnm:Cell Row="50" Col="3" ValueType="60">TIOB0</gnm:Cell> + <gnm:Cell Row="50" Col="4" ValueType="60">I/O_SIM</gnm:Cell> + <gnm:Cell Row="50" Col="5" ValueType="60">TIOB0</gnm:Cell> + <gnm:Cell Row="50" Col="6" ValueType="60">ST_USIM2_IO</gnm:Cell> + <gnm:Cell Row="50" Col="7" ValueType="60">TIOB0</gnm:Cell> + <gnm:Cell Row="50" Col="8" ValueType="60">ST_USIM2_IO</gnm:Cell> + <gnm:Cell Row="50" Col="11" ValueType="60">TIOB0</gnm:Cell> + <gnm:Cell Row="50" Col="12" ValueType="60">ST_UART2_IO</gnm:Cell> + <gnm:Cell Row="51" Col="0" ValueType="40">36</gnm:Cell> + <gnm:Cell Row="51" Col="1" ValueType="40">48</gnm:Cell> + <gnm:Cell Row="51" Col="2" ValueType="60">PA0/PWM0/TIOA0</gnm:Cell> <gnm:Cell Row="51" Col="3" ValueType="60">NC</gnm:Cell> - <gnm:Cell Row="51" Col="4" ValueType="60">PA0</gnm:Cell> - <gnm:Cell Row="51" Col="5" ValueType="60">_SIMTRACE34_RESET</gnm:Cell> - <gnm:Cell Row="51" Col="7" ValueType="60">NC</gnm:Cell> - <gnm:Cell Row="52" Col="0" ValueType="40">49</gnm:Cell> - <gnm:Cell Row="52" Col="1" ValueType="60">TDO</gnm:Cell> + <gnm:Cell Row="51" Col="4" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="51" Col="5" ValueType="60">PA0</gnm:Cell> + <gnm:Cell Row="51" Col="6" ValueType="60">_SIMTRACE34_RESET</gnm:Cell> + <gnm:Cell Row="51" Col="8" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="51" Col="11" ValueType="60">PA0</gnm:Cell> + <gnm:Cell Row="51" Col="12" ValueType="60">!CONNECT_MDM_SIM</gnm:Cell> + <gnm:Cell Row="52" Col="0" ValueType="40">37</gnm:Cell> + <gnm:Cell Row="52" Col="1" ValueType="40">49</gnm:Cell> <gnm:Cell Row="52" Col="2" ValueType="60">TDO</gnm:Cell> - <gnm:Cell Row="52" Col="4" ValueType="60">TDO</gnm:Cell> - <gnm:Cell Row="52" Col="5" ValueType="60">SIMTRACE12_TDO</gnm:Cell> - <gnm:Cell Row="52" Col="6" ValueType="60">TDO</gnm:Cell> - <gnm:Cell Row="52" Col="7" ValueType="60">SIMTRACE_TDO</gnm:Cell> - <gnm:Cell Row="53" Col="0" ValueType="40">50</gnm:Cell> - <gnm:Cell Row="53" Col="1" ValueType="60">JTAGSEL</gnm:Cell> + <gnm:Cell Row="52" Col="3" ValueType="60">TDO</gnm:Cell> + <gnm:Cell Row="52" Col="5" ValueType="60">TDO</gnm:Cell> + <gnm:Cell Row="52" Col="6" ValueType="60">SIMTRACE12_TDO</gnm:Cell> + <gnm:Cell Row="52" Col="7" ValueType="60">TDO</gnm:Cell> + <gnm:Cell Row="52" Col="8" ValueType="60">SIMTRACE_TDO</gnm:Cell> + <gnm:Cell Row="52" Col="11" ValueType="60">TDO</gnm:Cell> + <gnm:Cell Row="53" Col="0" ValueType="40">38</gnm:Cell> + <gnm:Cell Row="53" Col="1" ValueType="40">50</gnm:Cell> <gnm:Cell Row="53" Col="2" ValueType="60">JTAGSEL</gnm:Cell> - <gnm:Cell Row="53" Col="4" ValueType="60">JTAGSEL</gnm:Cell> - <gnm:Cell Row="53" Col="5" ValueType="60">GND</gnm:Cell> - <gnm:Cell Row="54" Col="0" ValueType="40">51</gnm:Cell> - <gnm:Cell Row="54" Col="1" ValueType="60">TMS</gnm:Cell> + <gnm:Cell Row="53" Col="3" ValueType="60">JTAGSEL</gnm:Cell> + <gnm:Cell Row="53" Col="5" ValueType="60">JTAGSEL</gnm:Cell> + <gnm:Cell Row="53" Col="6" ValueType="60">GND</gnm:Cell> + <gnm:Cell Row="53" Col="11" ValueType="60">JTAGSEL</gnm:Cell> + <gnm:Cell Row="54" Col="0" ValueType="40">39</gnm:Cell> + <gnm:Cell Row="54" Col="1" ValueType="40">51</gnm:Cell> <gnm:Cell Row="54" Col="2" ValueType="60">TMS</gnm:Cell> - <gnm:Cell Row="54" Col="4" ValueType="60">TMS</gnm:Cell> - <gnm:Cell Row="54" Col="5" ValueType="60">SIMTRACE12_TMS</gnm:Cell> - <gnm:Cell Row="54" Col="6" ValueType="60">TMS</gnm:Cell> - <gnm:Cell Row="54" Col="7" ValueType="60">SIMTRACE_TMS</gnm:Cell> - <gnm:Cell Row="55" Col="0" ValueType="40">52</gnm:Cell> - <gnm:Cell Row="55" Col="1" ValueType="60">PA31/NPCS1/PCK2</gnm:Cell> - <gnm:Cell Row="55" Col="2" ValueType="60">PA31</gnm:Cell> - <gnm:Cell Row="55" Col="3" ValueType="60">BOTLOADER_SW</gnm:Cell> - <gnm:Cell Row="55" Col="4" ValueType="60">PA31</gnm:Cell> - <gnm:Cell Row="55" Col="5" ValueType="60">SCL</gnm:Cell> - <gnm:Cell Row="55" Col="8" ValueType="60">NPCS1</gnm:Cell> - <gnm:Cell Row="56" Col="0" ValueType="40">53</gnm:Cell> - <gnm:Cell Row="56" Col="1" ValueType="60">TCK</gnm:Cell> + <gnm:Cell Row="54" Col="3" ValueType="60">TMS</gnm:Cell> + <gnm:Cell Row="54" Col="5" ValueType="60">TMS</gnm:Cell> + <gnm:Cell Row="54" Col="6" ValueType="60">SIMTRACE12_TMS</gnm:Cell> + <gnm:Cell Row="54" Col="7" ValueType="60">TMS</gnm:Cell> + <gnm:Cell Row="54" Col="8" ValueType="60">SIMTRACE_TMS</gnm:Cell> + <gnm:Cell Row="54" Col="11" ValueType="60">TMS</gnm:Cell> + <gnm:Cell Row="55" Col="1" ValueType="40">52</gnm:Cell> + <gnm:Cell Row="55" Col="2" ValueType="60">PA31/NPCS1/PCK2</gnm:Cell> + <gnm:Cell Row="55" Col="3" ValueType="60">PA31</gnm:Cell> + <gnm:Cell Row="55" Col="4" ValueType="60">BOTLOADER_SW</gnm:Cell> + <gnm:Cell Row="55" Col="5" ValueType="60">PA31</gnm:Cell> + <gnm:Cell Row="55" Col="6" ValueType="60">SCL</gnm:Cell> + <gnm:Cell Row="55" Col="9" ValueType="60">NPCS1</gnm:Cell> + <gnm:Cell Row="55" Col="11" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="56" Col="0" ValueType="40">40</gnm:Cell> + <gnm:Cell Row="56" Col="1" ValueType="40">53</gnm:Cell> <gnm:Cell Row="56" Col="2" ValueType="60">TCK</gnm:Cell> - <gnm:Cell Row="56" Col="4" ValueType="60">TCK</gnm:Cell> - <gnm:Cell Row="56" Col="5" ValueType="60">SIMTRACE_TCK</gnm:Cell> - <gnm:Cell Row="57" Col="0" ValueType="40">54</gnm:Cell> - <gnm:Cell Row="57" Col="1" ValueType="60">VDDCORE</gnm:Cell> - <gnm:Cell Row="58" Col="0" ValueType="40">55</gnm:Cell> - <gnm:Cell Row="58" Col="1" ValueType="60">PB12/ERASE</gnm:Cell> - <gnm:Cell Row="58" Col="2" ValueType="60">ERASE</gnm:Cell> - <gnm:Cell Row="58" Col="4" ValueType="60">ERASE</gnm:Cell> - <gnm:Cell Row="58" Col="5" ValueType="60">SIMTRACE12_ERASE</gnm:Cell> - <gnm:Cell Row="59" Col="0" ValueType="40">56</gnm:Cell> - <gnm:Cell Row="59" Col="1" ValueType="60">DDM</gnm:Cell> - <gnm:Cell Row="59" Col="4" ValueType="60">DDM</gnm:Cell> - <gnm:Cell Row="60" Col="0" ValueType="40">57</gnm:Cell> - <gnm:Cell Row="60" Col="1" ValueType="60">DDP</gnm:Cell> - <gnm:Cell Row="60" Col="4" ValueType="60">DDN</gnm:Cell> - <gnm:Cell Row="61" Col="0" ValueType="40">58</gnm:Cell> - <gnm:Cell Row="61" Col="1" ValueType="60">VDDIO</gnm:Cell> - <gnm:Cell Row="62" Col="0" ValueType="40">59</gnm:Cell> - <gnm:Cell Row="62" Col="1" ValueType="60">PB13/VDDFLASH</gnm:Cell> - <gnm:Cell Row="62" Col="4" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="56" Col="3" ValueType="60">TCK</gnm:Cell> + <gnm:Cell Row="56" Col="5" ValueType="60">TCK</gnm:Cell> + <gnm:Cell Row="56" Col="6" ValueType="60">SIMTRACE_TCK</gnm:Cell> + <gnm:Cell Row="56" Col="11" ValueType="60">TCK</gnm:Cell> + <gnm:Cell Row="57" Col="0" ValueType="40">41</gnm:Cell> + <gnm:Cell Row="57" Col="1" ValueType="40">54</gnm:Cell> + <gnm:Cell Row="57" Col="2" ValueType="60">VDDCORE</gnm:Cell> + <gnm:Cell Row="58" Col="0" ValueType="40">42</gnm:Cell> + <gnm:Cell Row="58" Col="1" ValueType="40">55</gnm:Cell> + <gnm:Cell Row="58" Col="2" ValueType="60">PB12/ERASE</gnm:Cell> + <gnm:Cell Row="58" Col="3" ValueType="60">ERASE</gnm:Cell> + <gnm:Cell Row="58" Col="5" ValueType="60">ERASE</gnm:Cell> + <gnm:Cell Row="58" Col="6" ValueType="60">SIMTRACE12_ERASE</gnm:Cell> + <gnm:Cell Row="58" Col="11" ValueType="60">ERASE</gnm:Cell> + <gnm:Cell Row="59" Col="0" ValueType="40">43</gnm:Cell> + <gnm:Cell Row="59" Col="1" ValueType="40">56</gnm:Cell> + <gnm:Cell Row="59" Col="2" ValueType="60">DDM</gnm:Cell> + <gnm:Cell Row="59" Col="5" ValueType="60">DDM</gnm:Cell> + <gnm:Cell Row="60" Col="0" ValueType="40">44</gnm:Cell> + <gnm:Cell Row="60" Col="1" ValueType="40">57</gnm:Cell> + <gnm:Cell Row="60" Col="2" ValueType="60">DDP</gnm:Cell> + <gnm:Cell Row="60" Col="5" ValueType="60">DDN</gnm:Cell> + <gnm:Cell Row="61" Col="0" ValueType="40">47</gnm:Cell> + <gnm:Cell Row="61" Col="1" ValueType="40">58</gnm:Cell> + <gnm:Cell Row="61" Col="2" ValueType="60">VDDIO</gnm:Cell> + <gnm:Cell Row="62" Col="1" ValueType="40">59</gnm:Cell> + <gnm:Cell Row="62" Col="2" ValueType="60">PB13/VDDFLASH</gnm:Cell> <gnm:Cell Row="62" Col="5" ValueType="60">NC</gnm:Cell> - <gnm:Cell Row="63" Col="0" ValueType="40">60</gnm:Cell> - <gnm:Cell Row="63" Col="1" ValueType="60">GND</gnm:Cell> - <gnm:Cell Row="64" Col="0" ValueType="40">61</gnm:Cell> - <gnm:Cell Row="64" Col="1" ValueType="60">XOUT</gnm:Cell> + <gnm:Cell Row="62" Col="6" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="62" Col="11" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="63" Col="1" ValueType="40">60</gnm:Cell> + <gnm:Cell Row="63" Col="2" ValueType="60">GND</gnm:Cell> + <gnm:Cell Row="64" Col="0" ValueType="40">45</gnm:Cell> + <gnm:Cell Row="64" Col="1" ValueType="40">61</gnm:Cell> <gnm:Cell Row="64" Col="2" ValueType="60">XOUT</gnm:Cell> - <gnm:Cell Row="64" Col="4" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="64" Col="3" ValueType="60">XOUT</gnm:Cell> <gnm:Cell Row="64" Col="5" ValueType="60">NC</gnm:Cell> - <gnm:Cell Row="65" Col="0" ValueType="40">62</gnm:Cell> - <gnm:Cell Row="65" Col="1" ValueType="60">XIN</gnm:Cell> + <gnm:Cell Row="64" Col="6" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="64" Col="11" ValueType="60">XOUT</gnm:Cell> + <gnm:Cell Row="65" Col="0" ValueType="40">46</gnm:Cell> + <gnm:Cell Row="65" Col="1" ValueType="40">62</gnm:Cell> <gnm:Cell Row="65" Col="2" ValueType="60">XIN</gnm:Cell> - <gnm:Cell Row="65" Col="4" ValueType="60">XIN</gnm:Cell> - <gnm:Cell Row="65" Col="5" ValueType="60">ST12_12MHZ</gnm:Cell> - <gnm:Cell Row="66" Col="0" ValueType="40">63</gnm:Cell> - <gnm:Cell Row="66" Col="1" ValueType="60">PB14/PLLRC</gnm:Cell> - <gnm:Cell Row="66" Col="4" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="65" Col="3" ValueType="60">XIN</gnm:Cell> + <gnm:Cell Row="65" Col="5" ValueType="60">XIN</gnm:Cell> + <gnm:Cell Row="65" Col="6" ValueType="60">ST12_12MHZ</gnm:Cell> + <gnm:Cell Row="65" Col="11" ValueType="60">XIN</gnm:Cell> + <gnm:Cell Row="66" Col="1" ValueType="40">63</gnm:Cell> + <gnm:Cell Row="66" Col="2" ValueType="60">PB14/PLLRC</gnm:Cell> <gnm:Cell Row="66" Col="5" ValueType="60">NC</gnm:Cell> - <gnm:Cell Row="67" Col="0" ValueType="40">64</gnm:Cell> - <gnm:Cell Row="67" Col="1" ValueType="60">VDDPLL</gnm:Cell> + <gnm:Cell Row="66" Col="6" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="66" Col="11" ValueType="60">NC</gnm:Cell> + <gnm:Cell Row="67" Col="0" ValueType="40">48</gnm:Cell> + <gnm:Cell Row="67" Col="1" ValueType="40">64</gnm:Cell> + <gnm:Cell Row="67" Col="2" ValueType="60">VDDPLL</gnm:Cell> </gnm:Cells> + <gnm:MergedRegions> + <gnm:Merge>L3:M3</gnm:Merge> + </gnm:MergedRegions> <gnm:SheetLayout TopLeft="A1"/> <gnm:Solver ModelType="0" ProblemType="0" MaxTime="60" MaxIter="1000" NonNeg="1" Discr="0" AutoScale="0" ProgramR="0" SensitivityR="0"/> </gnm:Sheet> diff --git a/host/.gitignore b/host/.gitignore new file mode 100644 index 0000000..f9841ab --- /dev/null +++ b/host/.gitignore @@ -0,0 +1,37 @@ +.o +*.a +*.lo +*.la +.deps +Makefile +Makefile.in + +#configure +aclocal.m4 +autom4te.cache/ +compile +config.guess +config.log +config.status +config.sub +configure +configure.lineno +depcomp +install-sh +missing +stamp-h1 +m4 + +#libtool +ltmain.sh +libtool +.libs + +.tarball-version +.version + +*.pc + +simtrace2-list +simtrace2-sniff +simtrace2-cardem-pcsc diff --git a/host/COPYING b/host/COPYING new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/host/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/host/Makefile b/host/Makefile deleted file mode 100644 index aee399c..0000000 --- a/host/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -LDFLAGS+=`pkg-config --libs libusb-1.0 libosmocore` -pthread -CFLAGS=-Wall -g - -APPS=simtrace2-remsim simtrace2-remsim-usb2udp simtrace2-list simtrace2-sniff - -all: $(APPS) - -simtrace2-remsim: simtrace2-remsim.o apdu_dispatch.o simtrace2-discovery.o libusb_util.o - $(CC) -o $@ $^ $(LDFLAGS) `pkg-config --libs libosmosim libpcsclite` - -simtrace2-remsim-usb2udp: usb2udp.o simtrace2-discovery.o - $(CC) -o $@ $^ $(LDFLAGS) - -simtrace2-list: simtrace2_usb.o libusb_util.o - $(CC) -o $@ $^ $(LDFLAGS) - -simtrace2-sniff: simtrace2-sniff.o simtrace2-discovery.o libusb_util.o - $(CC) -o $@ $^ $(LDFLAGS) - -%.o: %.c - $(CC) $(CFLAGS) `pkg-config --cflags libusb-1.0 libosmocore` -o $@ -c $^ - -clean: - @rm -f *.o $(APPS) - -install: $(APPS) - mkdir -p $(DESTDIR)/usr/bin - cp $(APPS) $(DESTDIR)/usr/bin/ diff --git a/host/Makefile.am b/host/Makefile.am new file mode 100644 index 0000000..338a46b --- /dev/null +++ b/host/Makefile.am @@ -0,0 +1,17 @@ +AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6 + +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +SUBDIRS = include lib src contrib #tests examples doc + +EXTRA_DIST = .version + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libosmo-simtrace2.pc + +@RELMAKE@ + +BUILT_SOURCES = $(top_srcdir)/.version +$(top_srcdir)/.version: + echo $(VERSION) > $@-t && mv $@-t $@ +dist-hook: + echo $(VERSION) > $(distdir)/.tarball-version diff --git a/host/configure.ac b/host/configure.ac new file mode 100644 index 0000000..8ba9930 --- /dev/null +++ b/host/configure.ac @@ -0,0 +1,104 @@ +AC_INIT([simtrace2], + m4_esyscmd([../git-version-gen ../.tarball-version]), + [simtrace@lists.osmocom.org]) + +dnl *This* is the root dir, even if an install-sh exists in ../ or ../../ +AC_CONFIG_AUX_DIR([.]) + +AM_INIT_AUTOMAKE([foreign dist-bzip2 no-dist-gzip 1.6 subdir-objects]) +AC_CONFIG_TESTDIR(tests) + +dnl kernel style compile messages +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +dnl include release helper +RELMAKE='-include osmo-release.mk' +AC_SUBST([RELMAKE]) + +dnl checks for programs +AC_PROG_MAKE_SET +AC_PROG_CC +AC_PROG_INSTALL +LT_INIT([pic-only]) + +dnl check for pkg-config (explained in detail in libosmocore/configure.ac) +AC_PATH_PROG(PKG_CONFIG_INSTALLED, pkg-config, no) +if test "x$PKG_CONFIG_INSTALLED" = "xno"; then + AC_MSG_WARN([You need to install pkg-config]) +fi +PKG_PROG_PKG_CONFIG([0.20]) + +AC_CONFIG_MACRO_DIR([m4]) + +CFLAGS="$CFLAGS -Wall" +CPPFLAGS="$CPPFLAGS -Wall" + +AC_ARG_ENABLE(sanitize, + [AS_HELP_STRING( + [--enable-sanitize], + [Compile with address sanitizer enabled], + )], + [sanitize=$enableval], [sanitize="no"]) +if test x"$sanitize" = x"yes" +then + CFLAGS="$CFLAGS -fsanitize=address -fsanitize=undefined" + CPPFLAGS="$CPPFLAGS -fsanitize=address -fsanitize=undefined" +fi + +# The following test is taken from WebKit's webkit.m4 +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -fvisibility=hidden " +AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([char foo;])], + [ AC_MSG_RESULT([yes]) + SYMBOL_VISIBILITY="-fvisibility=hidden"], + AC_MSG_RESULT([no])) +CFLAGS="$saved_CFLAGS" +AC_SUBST(SYMBOL_VISIBILITY) + +PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.4.0) +PKG_CHECK_MODULES(LIBOSMOSIM, libosmosim >= 1.4.0) +PKG_CHECK_MODULES(LIBOSMOUSB, libosmousb >= 1.4.0) +PKG_CHECK_MODULES(LIBUSB, libusb-1.0) + +AC_ARG_ENABLE(sanitize, + [AS_HELP_STRING( + [--enable-sanitize], + [Compile with address sanitizer enabled], + )], + [sanitize=$enableval], [sanitize="no"]) +if test x"$sanitize" = x"yes" +then + CFLAGS="$CFLAGS -fsanitize=address -fsanitize=undefined" + CPPFLAGS="$CPPFLAGS -fsanitize=address -fsanitize=undefined" +fi + +AC_ARG_ENABLE(werror, + [AS_HELP_STRING( + [--enable-werror], + [Turn all compiler warnings into errors, with exceptions: + a) deprecation (allow upstream to mark deprecation without breaking builds); + b) "#warning" pragmas (allow to remind ourselves of errors without breaking builds) + ] + )], + [werror=$enableval], [werror="no"]) +if test x"$werror" = x"yes" +then + WERROR_FLAGS="-Werror" + WERROR_FLAGS+=" -Wno-error=deprecated -Wno-error=deprecated-declarations" + WERROR_FLAGS+=" -Wno-error=cpp" # "#warning" + CFLAGS="$CFLAGS $WERROR_FLAGS" + CPPFLAGS="$CPPFLAGS $WERROR_FLAGS" +fi + +AC_MSG_RESULT([CFLAGS="$CFLAGS"]) +AC_MSG_RESULT([CPPFLAGS="$CPPFLAGS"]) + +AC_OUTPUT( + libosmo-simtrace2.pc + include/Makefile + src/Makefile + lib/Makefile + contrib/Makefile + contrib/simtrace2.spec + Makefile) diff --git a/host/99-simtrace2.rules b/host/contrib/99-simtrace2.rules index 4a8b2ea..5ae04e2 100644 --- a/host/99-simtrace2.rules +++ b/host/contrib/99-simtrace2.rules @@ -16,6 +16,10 @@ ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="4002", GROUP="plugdev" # sysmocom QMOD SAM3 (DFU and runtime) ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="4003", GROUP="plugdev" ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="4004", GROUP="plugdev" +# sysmocom OCTSIMTEST +ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="616d", GROUP="plugdev" +# ngff-cardem +ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="616e", GROUP="plugdev" # All done LABEL="simtrace2_rules_end" diff --git a/host/contrib/Makefile.am b/host/contrib/Makefile.am new file mode 100644 index 0000000..4f11962 --- /dev/null +++ b/host/contrib/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = 99-simtrace2.rules diff --git a/host/contrib/simtrace2.spec.in b/host/contrib/simtrace2.spec.in new file mode 100644 index 0000000..0bc5d2a --- /dev/null +++ b/host/contrib/simtrace2.spec.in @@ -0,0 +1,102 @@ +# +# spec file for package simtrace2 +# +# Copyright (c) 2021 SUSE LLC +# Copyright (c) 2018-2021, Martin Hauke <mardnh@gmx.de> +# +# All modifications and additions to the file contributed by third parties +# remain the property of their copyright owners, unless otherwise agreed +# upon. The license for this file, and modifications and additions to the +# file, is the same license as for the pristine package itself (unless the +# license for the pristine package is not an Open Source License, in which +# case the license is the MIT License). An "Open Source License" is a +# license that conforms to the Open Source Definition (Version 1.9) +# published by the Open Source Initiative. + +%define sover 1 +Name: simtrace2 +Version: @VERSION@ +Release: 0 +Summary: Osmocom SIMtrace host utility +License: GPL-2.0-or-later +Group: Productivity/Telephony/Utilities +URL: https://osmocom.org/projects/simtrace2/wiki +Source: %{name}-%{version}.tar.xz +BuildRequires: autoconf +BuildRequires: automake +BuildRequires: libtool +BuildRequires: pkgconfig +BuildRequires: pkgconfig(libosmocore) >= 1.4.0 +BuildRequires: pkgconfig(libosmosim) >= 1.4.0 +BuildRequires: pkgconfig(libosmousb) >= 1.4.0 +BuildRequires: pkgconfig(libpcsclite) +BuildRequires: pkgconfig(libusb-1.0) + +%description +Osmocom SIMtrace 2 is a software and hardware system for passively +tracing SIM-ME communication between the SIM card and the mobile phone, +and remote SIM operation. + +This package contains SIMtrace 2 host utility. + +%package -n libosmo-simtrace2-%{sover} +Summary: Driver functions for Osmocom SIMtrace2 and compatible firmware +Group: System/Libraries + +%description -n libosmo-simtrace2-%{sover} +This library contains core "driver" functionality to interface with the +Osmocom SIMtrace2 (and compatible) USB device firmware. It enables +applications to implement SIM card / smart card tracing as well as +SIM / smart card emulation functions. + +%package -n libosmo-simtrace2-devel +Summary: Development files for the Osmocom SIMtrace2 library +Group: Development/Libraries/C and C++ +Requires: libosmo-simtrace2-%{sover} = %{version} + +%description -n libosmo-simtrace2-devel +Osmocom SIMtrace2 (and compatible) USB device firmware. It enables +applications to implement SIM card / smart card tracing as well as +SIM / smart card emulation functions. + +This subpackage contains libraries and header files for developing +applications that want to make use of libosmo-simtrace2. + +%prep +%setup -q + +%build +cd host +echo "%{version}" >.tarball-version +autoreconf -fiv +%configure --disable-static +%make_build + +%install +%make_install -C host +install -Dm0644 host/contrib/99-simtrace2.rules %{buildroot}/%{_udevrulesdir}/99-simtrace2.rules +find %{buildroot} -type f -name "*.la" -delete -print + +%post -n libosmo-simtrace2-%{sover} -p /sbin/ldconfig +%postun -n libosmo-simtrace2-%{sover} -p /sbin/ldconfig + +%files +%license host/COPYING +%doc README.md +%{_bindir}/simtrace2-cardem-pcsc +%{_bindir}/simtrace2-list +%{_bindir}/simtrace2-sniff +%{_bindir}/simtrace2-tool +%{_udevrulesdir}/99-simtrace2.rules + +%files -n libosmo-simtrace2-%{sover} +%{_libdir}/libosmo-simtrace2.so.%{sover}* + +%files -n libosmo-simtrace2-devel +%dir %{_includedir}/osmocom/ +%dir %{_includedir}/osmocom/simtrace2/ +%{_includedir}/osmocom/simtrace2/*.h +%{_libdir}/libosmo-simtrace2.so +%{_libdir}/pkgconfig/libosmo-simtrace2.pc + +%changelog diff --git a/host/include/Makefile.am b/host/include/Makefile.am new file mode 100644 index 0000000..60134f3 --- /dev/null +++ b/host/include/Makefile.am @@ -0,0 +1,8 @@ +nobase_include_HEADERS = \ + osmocom/simtrace2/apdu_dispatch.h \ + osmocom/simtrace2/simtrace2_api.h \ + osmocom/simtrace2/simtrace_usb.h \ + osmocom/simtrace2/simtrace_prot.h \ + osmocom/simtrace2/usb_util.h \ + osmocom/simtrace2/gsmtap.h \ + $(NULL) diff --git a/host/apdu_dispatch.h b/host/include/osmocom/simtrace2/apdu_dispatch.h index 2c99858..62ff762 100644 --- a/host/apdu_dispatch.h +++ b/host/include/osmocom/simtrace2/apdu_dispatch.h @@ -1,6 +1,6 @@ /* apdu_dispatch - State machine to determine Rx/Tx phases of APDU * - * (C) 2016 by Harald Welte <hwelte@hmw-consulting.de> + * (C) 2016-2019 by Harald Welte <hwelte@hmw-consulting.de> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once @@ -23,7 +19,7 @@ #include <osmocom/sim/sim.h> -struct apdu_context { +struct osmo_apdu_context { struct osim_apdu_cmd_hdr hdr; uint8_t dc[256]; uint8_t de[256]; @@ -39,11 +35,13 @@ struct apdu_context { } le; }; -enum apdu_action { +enum osmo_apdu_action { APDU_ACT_TX_CAPDU_TO_CARD = 0x0001, APDU_ACT_RX_MORE_CAPDU_FROM_READER = 0x0002, }; +const char *osmo_apdu_dump_context_buf(char *buf, unsigned int buf_len, + const struct osmo_apdu_context *ac); -int apdu_segment_in(struct apdu_context *ac, const uint8_t *apdu_buf, - unsigned int apdu_len, bool new_apdu); +int osmo_apdu_segment_in(struct osmo_apdu_context *ac, const uint8_t *apdu_buf, + unsigned int apdu_len, bool new_apdu); diff --git a/host/include/osmocom/simtrace2/gsmtap.h b/host/include/osmocom/simtrace2/gsmtap.h new file mode 100644 index 0000000..d7184dc --- /dev/null +++ b/host/include/osmocom/simtrace2/gsmtap.h @@ -0,0 +1,6 @@ +#pragma once +#include <stdint.h> +#include <osmocom/core/gsmtap.h> + +int osmo_st2_gsmtap_init(const char *gsmtap_host); +int osmo_st2_gsmtap_send_apdu(uint8_t sub_type, const uint8_t *apdu, unsigned int len); diff --git a/host/include/osmocom/simtrace2/simtrace2_api.h b/host/include/osmocom/simtrace2/simtrace2_api.h new file mode 100644 index 0000000..d658d16 --- /dev/null +++ b/host/include/osmocom/simtrace2/simtrace2_api.h @@ -0,0 +1,63 @@ +#pragma once + +#include <stdint.h> +#include <osmocom/sim/sim.h> + +/* transport to a SIMtrace device */ +struct osmo_st2_transport { + /* USB */ + struct libusb_device_handle *usb_devh; + struct { + uint8_t in; + uint8_t out; + uint8_t irq_in; + } usb_ep; + /* use non-blocking / asynchronous libusb I/O */ + bool usb_async; + + /* UDP */ + int udp_fd; +}; + +/* a SIMtrace slot; communicates over a transport */ +struct osmo_st2_slot { + /* transport through which the slot can be reached */ + struct osmo_st2_transport *transp; + /* number of the slot within the transport */ + uint8_t slot_nr; +}; + +/* One istance of card emulation */ +struct osmo_st2_cardem_inst { + /* slot on which this card emulation instance runs */ + struct osmo_st2_slot *slot; + /* libosmosim SIM card profile */ + const struct osim_cla_ins_card_profile *card_prof; + /* libosmosim SIM card channel */ + struct osim_chan_hdl *chan; + /* path of the underlying USB device */ + char *usb_path; + /* opaque data TBD by user */ + void *priv; +}; + +int osmo_st2_slot_tx_msg(struct osmo_st2_slot *slot, struct msgb *msg, + uint8_t msg_class, uint8_t msg_type); + + +int osmo_st2_cardem_request_card_insert(struct osmo_st2_cardem_inst *ci, bool inserted); +int osmo_st2_cardem_request_pb_and_rx(struct osmo_st2_cardem_inst *ci, uint8_t pb, uint8_t le); +int osmo_st2_cardem_request_pb_and_tx(struct osmo_st2_cardem_inst *ci, uint8_t pb, + const uint8_t *data, uint16_t data_len_in); +int osmo_st2_cardem_request_sw_tx(struct osmo_st2_cardem_inst *ci, const uint8_t *sw); +int osmo_st2_cardem_request_set_atr(struct osmo_st2_cardem_inst *ci, const uint8_t *atr, + unsigned int atr_len); +int osmo_st2_cardem_request_config(struct osmo_st2_cardem_inst *ci, uint32_t features); + + +int osmo_st2_modem_reset_pulse(struct osmo_st2_slot *slot, uint16_t duration_ms); +int osmo_st2_modem_reset_active(struct osmo_st2_slot *slot); +int osmo_st2_modem_reset_inactive(struct osmo_st2_slot *slot); +int osmo_st2_modem_sim_select_local(struct osmo_st2_slot *slot); +int osmo_st2_modem_sim_select_remote(struct osmo_st2_slot *slot); +int osmo_st2_modem_get_status(struct osmo_st2_slot *slot); diff --git a/host/include/osmocom/simtrace2/simtrace_prot.h b/host/include/osmocom/simtrace2/simtrace_prot.h new file mode 120000 index 0000000..cf485f3 --- /dev/null +++ b/host/include/osmocom/simtrace2/simtrace_prot.h @@ -0,0 +1 @@ +../../../../firmware/libcommon/include/simtrace_prot.h
\ No newline at end of file diff --git a/host/include/osmocom/simtrace2/simtrace_usb.h b/host/include/osmocom/simtrace2/simtrace_usb.h new file mode 120000 index 0000000..ec0c021 --- /dev/null +++ b/host/include/osmocom/simtrace2/simtrace_usb.h @@ -0,0 +1 @@ +../../../../firmware/libcommon/include/simtrace_usb.h
\ No newline at end of file diff --git a/host/include/osmocom/simtrace2/usb_util.h b/host/include/osmocom/simtrace2/usb_util.h new file mode 100644 index 0000000..3bb2486 --- /dev/null +++ b/host/include/osmocom/simtrace2/usb_util.h @@ -0,0 +1,5 @@ +#pragma once + +#include <osmocom/usb/libusb.h> + +extern const struct dev_id osmo_st2_compatible_dev_ids[]; diff --git a/host/lib/Makefile.am b/host/lib/Makefile.am new file mode 100644 index 0000000..e134c75 --- /dev/null +++ b/host/lib/Makefile.am @@ -0,0 +1,20 @@ +# This is _NOT_ the library release version, it's an API version. +# Please read chapter "Library interface versions" of the libtool documentation +# before making any modifications: https://www.gnu.org/software/libtool/manual/html_node/Versioning.html +ST2_LIBVERSION=1:0:0 + +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) +AM_CFLAGS= -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOSIM_CFLAGS) $(LIBUSB_CFLAGS) $(COVERAGE_CFLAGS) +AM_LDFLAGS = $(COVERAGE_LDFLAGS) +COMMONLIBS = $(LIBOSMOCORE_LIBS) $(LIBOSMOSIM_LIBS) $(LIBUSB_LIBS) + +lib_LTLIBRARIES = libosmo-simtrace2.la + +libosmo_simtrace2_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(ST2_LIBVERSION) +libosmo_simtrace2_la_LIBADD = $(COMMONLIBS) +libosmo_simtrace2_la_SOURCES = \ + apdu_dispatch.c \ + gsmtap.c \ + simtrace2_api.c \ + usb_util.c \ + $(NULL) diff --git a/host/apdu_dispatch.c b/host/lib/apdu_dispatch.c index 7c7ed01..4c8f505 100644 --- a/host/apdu_dispatch.c +++ b/host/lib/apdu_dispatch.c @@ -1,6 +1,6 @@ /* apdu_dispatch - State machine to determine Rx/Tx phases of APDU * - * (C) 2016 by Harald Welte <hwelte@hmw-consulting.de> + * (C) 2016-2019 by Harald Welte <hwelte@hmw-consulting.de> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include <stdint.h> #include <stdlib.h> @@ -24,24 +20,25 @@ #include <errno.h> #include <osmocom/core/utils.h> +#include <osmocom/core/logging.h> #include <osmocom/sim/sim.h> #include <osmocom/sim/class_tables.h> -#include "apdu_dispatch.h" +#include <osmocom/simtrace2/apdu_dispatch.h> /*! \brief Has the command-data phase been completed yet? */ -static inline bool is_dc_complete(struct apdu_context *ac) +static inline bool is_dc_complete(struct osmo_apdu_context *ac) { return (ac->lc.tot == ac->lc.cur); } /*! \brief Has the expected-data phase been completed yet? */ -static inline bool is_de_complete(struct apdu_context *ac) +static inline bool is_de_complete(struct osmo_apdu_context *ac) { return (ac->le.tot == ac->le.cur); } -static const char *dump_apdu_hdr(const struct osim_apdu_cmd_hdr *h) +static const char *stringify_apdu_hdr(const struct osim_apdu_cmd_hdr *h) { static char buf[256]; sprintf(buf, "CLA=%02x INS=%02x P1=%02x P2=%02x P3=%02x", @@ -50,12 +47,19 @@ static const char *dump_apdu_hdr(const struct osim_apdu_cmd_hdr *h) return buf; } -static void dump_apdu_ctx(const struct apdu_context *ac) +/*! generate string representation of APDU context in specified output buffer. + * \param[in] buf output string buffer provided by caller + * \param[in] buf_len size of buf in bytes + * \param[in] ac APDU context to dump in buffer + * \returns pointer to buf on success */ +const char *osmo_apdu_dump_context_buf(char *buf, unsigned int buf_len, + const struct osmo_apdu_context *ac) { - printf("%s; case=%d, lc=%d(%d), le=%d(%d)\n", - dump_apdu_hdr(&ac->hdr), ac->apdu_case, - ac->lc.tot, ac->lc.cur, - ac->le.tot, ac->le.cur); + snprintf(buf, buf_len, "%s; case=%d, lc=%d(%d), le=%d(%d)\n", + stringify_apdu_hdr(&ac->hdr), ac->apdu_case, + ac->lc.tot, ac->lc.cur, + ac->le.tot, ac->le.cur); + return buf; } /*! \brief input function for APDU segmentation @@ -71,8 +75,8 @@ static void dump_apdu_ctx(const struct apdu_context *ac) * The function retunrs APDU_ACT_RX_MORE_CAPDU_FROM_READER when there * is more data to be received from the card reader (GSM Phone). */ -int apdu_segment_in(struct apdu_context *ac, const uint8_t *apdu_buf, - unsigned int apdu_len, bool new_apdu) +int osmo_apdu_segment_in(struct osmo_apdu_context *ac, const uint8_t *apdu_buf, + unsigned int apdu_len, bool new_apdu) { int rc = 0; @@ -105,7 +109,7 @@ int apdu_segment_in(struct apdu_context *ac, const uint8_t *apdu_buf, break; case 0: default: - fprintf(stderr, "Unknown APDU case %d\n", ac->apdu_case); + LOGP(DLGLOBAL, LOGL_ERROR, "Unknown APDU case %d\n", ac->apdu_case); return -1; } } else { @@ -124,8 +128,8 @@ int apdu_segment_in(struct apdu_context *ac, const uint8_t *apdu_buf, ac->lc.cur += cpy_len; break; default: - fprintf(stderr, "Unknown APDU case %d\n", ac->apdu_case); - break; + LOGP(DLGLOBAL, LOGL_ERROR, "Unknown APDU case %d\n", ac->apdu_case); + return -1; } } @@ -163,11 +167,9 @@ int apdu_segment_in(struct apdu_context *ac, const uint8_t *apdu_buf, break; case 0: default: - fprintf(stderr, "Unknown APDU case %d\n", ac->apdu_case); - break; + LOGP(DLGLOBAL, LOGL_ERROR, "Unknown APDU case %d\n", ac->apdu_case); + return -1; } - dump_apdu_ctx(ac); - return rc; } diff --git a/host/lib/gsmtap.c b/host/lib/gsmtap.c new file mode 100644 index 0000000..3fc3da6 --- /dev/null +++ b/host/lib/gsmtap.c @@ -0,0 +1,78 @@ +/* gsmtap - How to encapsulate SIM protocol traces in GSMTAP + * + * (C) 2016-2019 by Harald Welte <hwelte@hmw-consulting.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <osmocom/simtrace2/gsmtap.h> + +#include <osmocom/core/gsmtap.h> +#include <osmocom/core/gsmtap_util.h> + +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <stdio.h> + +/*! global GSMTAP instance */ +static struct gsmtap_inst *g_gti; + +/*! initialize the global GSMTAP instance for SIM traces */ +int osmo_st2_gsmtap_init(const char *gsmtap_host) +{ + if (g_gti) + return -EEXIST; + + g_gti = gsmtap_source_init(gsmtap_host, GSMTAP_UDP_PORT, 0); + if (!g_gti) { + perror("unable to open GSMTAP"); + return -EIO; + } + gsmtap_source_add_sink(g_gti); + + return 0; +} + +/*! log one APDU via the global GSMTAP instance. + * \param[in] sub_type GSMTAP sub-type (GSMTAP_SIM_* constant) + * \param[in] apdu User-provided buffer with APDU to log + * \param[in] len Length of apdu in bytes + */ +int osmo_st2_gsmtap_send_apdu(uint8_t sub_type, const uint8_t *apdu, unsigned int len) +{ + struct gsmtap_hdr *gh; + unsigned int gross_len = len + sizeof(*gh); + uint8_t *buf = malloc(gross_len); + int rc; + + if (!buf) + return -ENOMEM; + + memset(buf, 0, sizeof(*gh)); + gh = (struct gsmtap_hdr *) buf; + gh->version = GSMTAP_VERSION; + gh->hdr_len = sizeof(*gh)/4; + gh->type = GSMTAP_TYPE_SIM; + gh->sub_type = sub_type; + + memcpy(buf + sizeof(*gh), apdu, len); + + rc = write(gsmtap_inst_fd(g_gti), buf, gross_len); + if (rc < 0) { + perror("write gsmtap"); + free(buf); + return rc; + } + + free(buf); + return 0; +} diff --git a/host/lib/simtrace2_api.c b/host/lib/simtrace2_api.c new file mode 100644 index 0000000..4ad7eb7 --- /dev/null +++ b/host/lib/simtrace2_api.c @@ -0,0 +1,343 @@ + +/* simtrace2-protocol - USB protocol library code for SIMtrace2 + * + * (C) 2016-2019 by Harald Welte <hwelte@hmw-consulting.de> + * (C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <errno.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <signal.h> +#include <time.h> +#define _GNU_SOURCE +#include <getopt.h> + +#include <sys/time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <libusb.h> + +#include <osmocom/simtrace2/simtrace_prot.h> +#include <osmocom/simtrace2/simtrace2_api.h> + +#include <osmocom/core/utils.h> +#include <osmocom/core/socket.h> +#include <osmocom/core/msgb.h> +#include <osmocom/core/logging.h> +#include <osmocom/sim/class_tables.h> +#include <osmocom/sim/sim.h> + +#define LOGSLOT(slot, lvl, fmt, args...) \ + LOGP(DLINP, lvl, "[%u] " fmt, (slot)->slot_nr, ## args) + +/*********************************************************************** + * SIMTRACE core protocol + ***********************************************************************/ + +/*! \brief allocate a message buffer for simtrace use */ +static struct msgb *st_msgb_alloc(void) +{ + return msgb_alloc_headroom(1024+32, 32, "SIMtrace"); +} + + +static void usb_out_xfer_cb(struct libusb_transfer *xfer) +{ + struct msgb *msg = xfer->user_data; + + switch (xfer->status) { + case LIBUSB_TRANSFER_COMPLETED: + break; + case LIBUSB_TRANSFER_NO_DEVICE: + fprintf(stderr, "USB device disappeared\n"); + exit(1); + break; + default: + fprintf(stderr, "USB OUT transfer failed, status=%u\n", xfer->status); + exit(1); + break; + } + + msgb_free(msg); + libusb_free_transfer(xfer); +} + + +static int st2_transp_tx_msg_usb_async(struct osmo_st2_transport *transp, struct msgb *msg) +{ + struct libusb_transfer *xfer; + int rc; + + xfer = libusb_alloc_transfer(0); + OSMO_ASSERT(xfer); + xfer->dev_handle = transp->usb_devh; + xfer->flags = 0; + xfer->type = LIBUSB_TRANSFER_TYPE_BULK; + xfer->endpoint = transp->usb_ep.out; + xfer->timeout = 100000; + xfer->user_data = msg; + xfer->length = msgb_length(msg); + xfer->buffer = msgb_data(msg); + xfer->callback = usb_out_xfer_cb; + + rc = libusb_submit_transfer(xfer); + OSMO_ASSERT(rc == 0); + + return rc; +} + +/*! \brief Transmit a given command to the SIMtrace2 device */ +static int st2_transp_tx_msg_usb_sync(struct osmo_st2_transport *transp, struct msgb *msg) +{ + int rc; + int xfer_len; + rc = libusb_bulk_transfer(transp->usb_devh, transp->usb_ep.out, + msgb_data(msg), msgb_length(msg), + &xfer_len, 100000); + msgb_free(msg); + return rc; +} + +static struct simtrace_msg_hdr *st_push_hdr(struct msgb *msg, uint8_t msg_class, uint8_t msg_type, + uint8_t slot_nr) +{ + struct simtrace_msg_hdr *sh; + + sh = (struct simtrace_msg_hdr *) msgb_push(msg, sizeof(*sh)); + memset(sh, 0, sizeof(*sh)); + sh->msg_class = msg_class; + sh->msg_type = msg_type; + sh->slot_nr = slot_nr; + sh->msg_len = msgb_length(msg); + + return sh; +} + +/* transmit a given message to a specified slot. Expects all headers + * present before calling the function */ +int osmo_st2_slot_tx_msg(struct osmo_st2_slot *slot, struct msgb *msg, + uint8_t msg_class, uint8_t msg_type) +{ + struct osmo_st2_transport *transp = slot->transp; + int rc; + + OSMO_ASSERT(transp); + + st_push_hdr(msg, msg_class, msg_type, slot->slot_nr); + + if (transp->udp_fd < 0) { + if (transp->usb_async) + rc = st2_transp_tx_msg_usb_async(transp, msg); + else + rc = st2_transp_tx_msg_usb_sync(transp, msg); + } else { + rc = write(transp->udp_fd, msgb_data(msg), msgb_length(msg)); + msgb_free(msg); + } + return rc; +} + +/*********************************************************************** + * Card Emulation protocol + ***********************************************************************/ + + +/*! \brief Request the SIMtrace2 to generate a card-insert signal */ +int osmo_st2_cardem_request_card_insert(struct osmo_st2_cardem_inst *ci, bool inserted) +{ + struct msgb *msg = st_msgb_alloc(); + struct cardemu_usb_msg_cardinsert *cins; + + LOGSLOT(ci->slot, LOGL_NOTICE, "<= %s(inserted=%d)\n", __func__, inserted); + + cins = (struct cardemu_usb_msg_cardinsert *) msgb_put(msg, sizeof(*cins)); + memset(cins, 0, sizeof(*cins)); + if (inserted) + cins->card_insert = 1; + + return osmo_st2_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DT_CEMU_CARDINSERT); +} + +/*! \brief Request the SIMtrace2 to transmit a Procedure Byte, then Rx */ +int osmo_st2_cardem_request_pb_and_rx(struct osmo_st2_cardem_inst *ci, uint8_t pb, uint8_t le) +{ + struct msgb *msg = st_msgb_alloc(); + struct cardemu_usb_msg_tx_data *txd; + txd = (struct cardemu_usb_msg_tx_data *) msgb_put(msg, sizeof(*txd)); + + LOGSLOT(ci->slot, LOGL_DEBUG, "<= %s(pb=%02x, le=%u)\n", __func__, pb, le); + + memset(txd, 0, sizeof(*txd)); + txd->data_len = 1; + txd->flags = CEMU_DATA_F_PB_AND_RX; + /* one data byte */ + msgb_put_u8(msg, pb); + + return osmo_st2_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DT_CEMU_TX_DATA); +} + +/*! \brief Request the SIMtrace2 to transmit a Procedure Byte, then Tx */ +int osmo_st2_cardem_request_pb_and_tx(struct osmo_st2_cardem_inst *ci, uint8_t pb, + const uint8_t *data, uint16_t data_len_in) +{ + struct msgb *msg = st_msgb_alloc(); + struct cardemu_usb_msg_tx_data *txd; + uint8_t *cur; + + txd = (struct cardemu_usb_msg_tx_data *) msgb_put(msg, sizeof(*txd)); + + LOGSLOT(ci->slot, LOGL_DEBUG, "<= %s(pb=%02x, tx=%s, len=%d)\n", __func__, pb, + osmo_hexdump(data, data_len_in), data_len_in); + + memset(txd, 0, sizeof(*txd)); + txd->data_len = 1 + data_len_in; + txd->flags = CEMU_DATA_F_PB_AND_TX; + /* procedure byte */ + msgb_put_u8(msg, pb); + /* data */ + cur = msgb_put(msg, data_len_in); + memcpy(cur, data, data_len_in); + + return osmo_st2_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DT_CEMU_TX_DATA); +} + +/*! \brief Request the SIMtrace2 to send a Status Word */ +int osmo_st2_cardem_request_sw_tx(struct osmo_st2_cardem_inst *ci, const uint8_t *sw) +{ + struct msgb *msg = st_msgb_alloc(); + struct cardemu_usb_msg_tx_data *txd; + uint8_t *cur; + + txd = (struct cardemu_usb_msg_tx_data *) msgb_put(msg, sizeof(*txd)); + + LOGSLOT(ci->slot, LOGL_DEBUG, "<= %s(sw=%02x%02x)\n", __func__, sw[0], sw[1]); + + memset(txd, 0, sizeof(*txd)); + txd->data_len = 2; + txd->flags = CEMU_DATA_F_PB_AND_TX | CEMU_DATA_F_FINAL; + cur = msgb_put(msg, 2); + cur[0] = sw[0]; + cur[1] = sw[1]; + + return osmo_st2_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DT_CEMU_TX_DATA); +} + +int osmo_st2_cardem_request_set_atr(struct osmo_st2_cardem_inst *ci, const uint8_t *atr, unsigned int atr_len) +{ + struct msgb *msg = st_msgb_alloc(); + struct cardemu_usb_msg_set_atr *satr; + uint8_t *cur; + + satr = (struct cardemu_usb_msg_set_atr *) msgb_put(msg, sizeof(*satr)); + + LOGSLOT(ci->slot, LOGL_NOTICE, "<= %s(%s)\n", __func__, osmo_hexdump(atr, atr_len)); + + memset(satr, 0, sizeof(*satr)); + satr->atr_len = atr_len; + cur = msgb_put(msg, atr_len); + memcpy(cur, atr, atr_len); + + return osmo_st2_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DT_CEMU_SET_ATR); +} + +int osmo_st2_cardem_request_config(struct osmo_st2_cardem_inst *ci, uint32_t features) +{ + struct msgb *msg = st_msgb_alloc(); + struct cardemu_usb_msg_config *cfg; + + cfg = (struct cardemu_usb_msg_config *) msgb_put(msg, sizeof(*cfg)); + + LOGSLOT(ci->slot, LOGL_NOTICE, "<= %s(features=%08x)\n", __func__, features); + + memset(cfg, 0, sizeof(*cfg)); + cfg->features = features; + + return osmo_st2_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_BD_CEMU_CONFIG); +} + +/*********************************************************************** + * Modem Control protocol + ***********************************************************************/ + +static int _modem_reset(struct osmo_st2_slot *slot, uint8_t asserted, uint16_t pulse_ms) +{ + struct msgb *msg = st_msgb_alloc(); + struct st_modem_reset *sr ; + + LOGSLOT(slot, LOGL_NOTICE, "<= %s(asserted=%u, pulse_ms=%u)\n", __func__, + asserted, pulse_ms); + + sr = (struct st_modem_reset *) msgb_put(msg, sizeof(*sr)); + sr->asserted = asserted; + sr->pulse_duration_msec = pulse_ms; + + return osmo_st2_slot_tx_msg(slot, msg, SIMTRACE_MSGC_MODEM, SIMTRACE_MSGT_DT_MODEM_RESET); +} + +/*! \brief pulse the RESET line of the modem for \a duration_ms milli-seconds*/ +int osmo_st2_modem_reset_pulse(struct osmo_st2_slot *slot, uint16_t duration_ms) +{ + return _modem_reset(slot, 2, duration_ms); +} + +/*! \brief assert the RESET line of the modem */ +int osmo_st2_modem_reset_active(struct osmo_st2_slot *slot) +{ + return _modem_reset(slot, 1, 0); +} + +/*! \brief de-assert the RESET line of the modem */ +int osmo_st2_modem_reset_inactive(struct osmo_st2_slot *slot) +{ + return _modem_reset(slot, 0, 0); +} + +static int _modem_sim_select(struct osmo_st2_slot *slot, uint8_t remote_sim) +{ + struct msgb *msg = st_msgb_alloc(); + struct st_modem_sim_select *ss; + + LOGSLOT(slot, LOGL_NOTICE, "<= %s(remote_sim=%u)\n", __func__, remote_sim); + + ss = (struct st_modem_sim_select *) msgb_put(msg, sizeof(*ss)); + ss->remote_sim = remote_sim; + + return osmo_st2_slot_tx_msg(slot, msg, SIMTRACE_MSGC_MODEM, SIMTRACE_MSGT_DT_MODEM_SIM_SELECT); +} + +/*! \brief select local (physical) SIM for given slot */ +int osmo_st2_modem_sim_select_local(struct osmo_st2_slot *slot) +{ + return _modem_sim_select(slot, 0); +} + +/*! \brief select remote (emulated/forwarded) SIM for given slot */ +int osmo_st2_modem_sim_select_remote(struct osmo_st2_slot *slot) +{ + return _modem_sim_select(slot, 1); +} + +/*! \brief Request slot to send us status information about the modem */ +int osmo_st2_modem_get_status(struct osmo_st2_slot *slot) +{ + struct msgb *msg = st_msgb_alloc(); + + return osmo_st2_slot_tx_msg(slot, msg, SIMTRACE_MSGC_MODEM, SIMTRACE_MSGT_BD_MODEM_STATUS); +} diff --git a/host/lib/usb_util.c b/host/lib/usb_util.c new file mode 100644 index 0000000..d55bbc7 --- /dev/null +++ b/host/lib/usb_util.c @@ -0,0 +1,34 @@ +/* usb_util - USB related utilities for SIMtrace 2 USB devices + * + * (C) 2016-2019 by Harald Welte <hwelte@hmw-consulting.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <errno.h> +#include <getopt.h> + +#include <osmocom/core/utils.h> + +#include <osmocom/usb/libusb.h> +#include <osmocom/simtrace2/simtrace_usb.h> + +/*! list of USB idVendor/idProduct tuples of devices using simtrace2 firmware */ +const struct dev_id osmo_st2_compatible_dev_ids[] = { + { USB_VENDOR_OPENMOKO, USB_PRODUCT_OWHW_SAM3 }, + { USB_VENDOR_OPENMOKO, USB_PRODUCT_QMOD_SAM3 }, + { USB_VENDOR_OPENMOKO, USB_PRODUCT_SIMTRACE2 }, + { USB_VENDOR_OPENMOKO, USB_PRODUCT_OCTSIMTEST }, + { USB_VENDOR_OPENMOKO, USB_PRODUCT_NGFF_CARDEM }, + { 0, 0 } +}; diff --git a/host/libosmo-simtrace2.pc.in b/host/libosmo-simtrace2.pc.in new file mode 100644 index 0000000..6e9f6f2 --- /dev/null +++ b/host/libosmo-simtrace2.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: Osmocom SIMtrace2 library +Description: Library for SIM Card / Smart Card tracing + emulation +Version: @VERSION@ +Libs: -L${libdir} -losmo-simtrace2 +Cflags: -I${includedir}/ diff --git a/host/libusb_util.c b/host/libusb_util.c deleted file mode 100644 index 45e3f50..0000000 --- a/host/libusb_util.c +++ /dev/null @@ -1,297 +0,0 @@ -/* libisb utilities - * - * (C) 2010-2016 by Harald Welte <hwelte@hmw-consulting.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include <errno.h> -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <string.h> - -#include <libusb.h> - -#include "libusb_util.h" - -static char path_buf[USB_MAX_PATH_LEN]; - -static char *get_path(libusb_device *dev) -{ -#if (defined(LIBUSB_API_VERSION) && LIBUSB_API_VERSION >= 0x01000102) || (defined(LIBUSBX_API_VERSION) && LIBUSBX_API_VERSION >= 0x01000102) - uint8_t path[8]; - int r,j; - r = libusb_get_port_numbers(dev, path, sizeof(path)); - if (r > 0) { - sprintf(path_buf,"%d-%d",libusb_get_bus_number(dev),path[0]); - for (j = 1; j < r; j++){ - sprintf(path_buf+strlen(path_buf),".%d",path[j]); - }; - } - return path_buf; -#else -# warning "libusb too old - building without USB path support!" - return NULL; -#endif -} - -static int match_dev_id(const struct libusb_device_descriptor *desc, const struct dev_id *id) -{ - if ((desc->idVendor == id->vendor_id) && (desc->idProduct == id->product_id)) - return 1; - return 0; -} - - -static int match_dev_ids(const struct libusb_device_descriptor *desc, const struct dev_id *ids) -{ - const struct dev_id *id; - - for (id = ids; id->vendor_id || id->product_id; id++) { - if (match_dev_id(desc, id)) - return 1; - } - return 0; -} - -libusb_device **find_matching_usb_devs(const struct dev_id *dev_ids) -{ - libusb_device **list; - libusb_device **out = calloc(256, sizeof(libusb_device *)); - libusb_device **cur = out; - unsigned int i; - int rc; - - if (!out) - return NULL; - - rc = libusb_get_device_list(NULL, &list); - if (rc <= 0) { - perror("No USB devices found"); - free(out); - return NULL; - } - - for (i = 0; list[i] != NULL; i++) { - struct libusb_device_descriptor dev_desc; - libusb_device *dev = list[i]; - - rc = libusb_get_device_descriptor(dev, &dev_desc); - if (rc < 0) { - perror("Couldn't get device descriptor\n"); - libusb_unref_device(dev); - continue; - } - - if (match_dev_ids(&dev_desc, dev_ids)) { - *cur = dev; - cur++; - /* FIXME: overflow check */ - } else - libusb_unref_device(dev); - } - if (cur == out) { - libusb_free_device_list(list, 1); - free(out); - return NULL; - } - - libusb_free_device_list(list, 0); - return out; -} - -int dev_find_matching_interfaces(libusb_device *dev, int class, int sub_class, int protocol, - struct usb_interface_match *out, unsigned int out_len) -{ - struct libusb_device_descriptor dev_desc; - int rc, i, out_idx = 0; - uint8_t addr; - char *path; - - rc = libusb_get_device_descriptor(dev, &dev_desc); - if (rc < 0) { - perror("Couldn't get device descriptor\n"); - return -EIO; - } - - addr = libusb_get_device_address(dev); - path = get_path(dev); - - /* iterate over all configurations */ - for (i = 0; i < dev_desc.bNumConfigurations; i++) { - struct libusb_config_descriptor *conf_desc; - int j; - - rc = libusb_get_config_descriptor(dev, i, &conf_desc); - if (rc < 0) { - fprintf(stderr, "Couldn't get config descriptor %u\n", i); - continue; - } - /* iterate over all interfaces */ - for (j = 0; j < conf_desc->bNumInterfaces; j++) { - const struct libusb_interface *intf = &conf_desc->interface[j]; - int k; - /* iterate over all alternate settings */ - for (k = 0; k < intf->num_altsetting; k++) { - const struct libusb_interface_descriptor *if_desc; - if_desc = &intf->altsetting[k]; - if (class >= 0 && if_desc->bInterfaceClass != class) - continue; - if (sub_class >= 0 && if_desc->bInterfaceSubClass != sub_class) - continue; - if (protocol >= 0 && if_desc->bInterfaceProtocol != protocol) - continue; - /* MATCH! */ - out[out_idx].usb_dev = dev; - out[out_idx].vendor = dev_desc.idVendor; - out[out_idx].product = dev_desc.idProduct; - out[out_idx].addr = addr; - strncpy(out[out_idx].path, path, sizeof(out[out_idx].path)-1); - out[out_idx].path[sizeof(out[out_idx].path)-1] = '\0'; - out[out_idx].configuration = conf_desc->bConfigurationValue; - out[out_idx].interface = if_desc->bInterfaceNumber; - out[out_idx].altsetting = if_desc->bAlternateSetting; - out[out_idx].class = if_desc->bInterfaceClass; - out[out_idx].sub_class = if_desc->bInterfaceSubClass; - out[out_idx].protocol = if_desc->bInterfaceProtocol; - out[out_idx].string_idx = if_desc->iInterface; - out_idx++; - if (out_idx >= out_len) - return out_idx; - } - } - } - return out_idx; -} - -int usb_match_interfaces(libusb_context *ctx, const struct dev_id *dev_ids, - int class, int sub_class, int protocol, - struct usb_interface_match *out, unsigned int out_len) -{ - struct usb_interface_match *out_cur = out; - unsigned int out_len_remain = out_len; - libusb_device **list; - libusb_device **dev; - - list = find_matching_usb_devs(dev_ids); - if (!list) - return 0; - - for (dev = list; *dev; dev++) { - int rc; - -#if 0 - struct libusb_device_descriptor dev_desc; - uint8_t ports[8]; - uint8_t addr; - rc = libusb_get_device_descriptor(*dev, &dev_desc); - if (rc < 0) { - perror("Cannot get device descriptor"); - continue; - } - - addr = libusb_get_device_address(*dev); - - rc = libusb_get_port_numbers(*dev, ports, sizeof(ports)); - if (rc < 0) { - perror("Cannot get device path"); - continue; - } - - printf("Found USB Device %04x:%04x at address %d\n", - dev_desc.idVendor, dev_desc.idProduct, addr); -#endif - - rc = dev_find_matching_interfaces(*dev, class, sub_class, protocol, out_cur, out_len_remain); - if (rc < 0) - continue; - out_cur += rc; - out_len_remain -= rc; - - } - return out_len - out_len_remain; -} - -libusb_device_handle *usb_open_claim_interface(libusb_context *ctx, - const struct usb_interface_match *ifm) -{ - int rc, config; - struct dev_id dev_ids[] = { { ifm->vendor, ifm->product }, { 0, 0 } }; - libusb_device **list; - libusb_device **dev; - libusb_device_handle *usb_devh = NULL; - - list = find_matching_usb_devs(dev_ids); - if (!list) { - perror("No USB device with matching VID/PID"); - return NULL; - } - - for (dev = list; *dev; dev++) { - int addr; - char *path; - - addr = libusb_get_device_address(*dev); - path = get_path(*dev); - if ((ifm->addr && addr == ifm->addr) || - (strlen(ifm->path) && !strcmp(path, ifm->path))) { - rc = libusb_open(*dev, &usb_devh); - if (rc < 0) { - fprintf(stderr, "Cannot open device: %s\n", libusb_error_name(rc)); - usb_devh = NULL; - break; - } - rc = libusb_get_configuration(usb_devh, &config); - if (rc < 0) { - fprintf(stderr, "Cannot get current configuration: %s\n", libusb_error_name(rc)); - libusb_close(usb_devh); - usb_devh = NULL; - break; - } - if (config != ifm->configuration) { - rc = libusb_set_configuration(usb_devh, ifm->configuration); - if (rc < 0) { - fprintf(stderr, "Cannot set configuration: %s\n", libusb_error_name(rc)); - libusb_close(usb_devh); - usb_devh = NULL; - break; - } - } - rc = libusb_claim_interface(usb_devh, ifm->interface); - if (rc < 0) { - fprintf(stderr, "Cannot claim interface: %s\n", libusb_error_name(rc)); - libusb_close(usb_devh); - usb_devh = NULL; - break; - } - rc = libusb_set_interface_alt_setting(usb_devh, ifm->interface, ifm->altsetting); - if (rc < 0) { - fprintf(stderr, "Cannot set interface altsetting: %s\n", libusb_error_name(rc)); - libusb_release_interface(usb_devh, ifm->interface); - libusb_close(usb_devh); - usb_devh = NULL; - break; - } - } - } - - /* unref / free list */ - for (dev = list; *dev; dev++) - libusb_unref_device(*dev); - free(list); - - return usb_devh; -} diff --git a/host/libusb_util.h b/host/libusb_util.h deleted file mode 100644 index 2b2d92e..0000000 --- a/host/libusb_util.h +++ /dev/null @@ -1,70 +0,0 @@ -/* libisb utilities - * - * (C) 2010-2016 by Harald Welte <hwelte@hmw-consulting.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#pragma once - -#include <libusb.h> - -#define USB_MAX_PATH_LEN 20 - -struct dev_id { - uint16_t vendor_id; - uint16_t product_id; -}; - -/* Find any USB devices in the system matching the given Vendor and - * Product ID */ -libusb_device **find_matching_usb_devs(const struct dev_id *dev_ids); - -/* structure describing a single matching interface found */ -struct usb_interface_match { - /* libusb device E*/ - libusb_device *usb_dev; - /* Vendor ID of the device running matching interface */ - uint16_t vendor; - /* Product ID of the device running matching interface */ - uint16_t product; - /* USB Bus Address */ - uint8_t addr; - /* physical path */ - char path[USB_MAX_PATH_LEN]; - /* configuration of matching interface */ - uint8_t configuration; - /* interface number of matching interface */ - uint8_t interface; - /* altsetting of matching interface */ - uint8_t altsetting; - /* bInterfaceClass of matching interface */ - uint8_t class; - /* bInterfaceSubClass of matching interface */ - uint8_t sub_class; - /* bInterfaceProtocol of matching interface */ - uint8_t protocol; - /* index of string descriptor of matching interface */ - uint8_t string_idx; -}; - -int dev_find_matching_interfaces(libusb_device *dev, int class, int sub_class, int protocol, - struct usb_interface_match *out, unsigned int out_len); - -int usb_match_interfaces(libusb_context *ctx, const struct dev_id *dev_ids, - int class, int sub_class, int protocol, - struct usb_interface_match *out, unsigned int out_len); - -libusb_device_handle *usb_open_claim_interface(libusb_context *ctx, - const struct usb_interface_match *ifm); diff --git a/host/simtrace.h b/host/simtrace.h deleted file mode 100644 index c4a20da..0000000 --- a/host/simtrace.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _SIMTRACE_H -#define _SIMTRACE_H - -#define SIMTRACE_USB_VENDOR 0x1d50 -#define SIMTRACE_USB_PRODUCT 0x60e3 - -#endif diff --git a/host/simtrace2-discovery.c b/host/simtrace2-discovery.c deleted file mode 100644 index a7306ce..0000000 --- a/host/simtrace2-discovery.c +++ /dev/null @@ -1,94 +0,0 @@ -/* simtrace2-discovery - host PC library to scan for matching USB - * devices - * - * (C) 2016 by Harald Welte <hwelte@hmw-consulting.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include <stdint.h> - -#include <libusb.h> - -/*! \brief obtain the endpoint addresses for a given USB interface */ -int get_usb_ep_addrs(libusb_device_handle *devh, unsigned int if_num, - uint8_t *out, uint8_t *in, uint8_t *irq) -{ - libusb_device *dev = libusb_get_device(devh); - struct libusb_config_descriptor *cdesc; - const struct libusb_interface_descriptor *idesc; - const struct libusb_interface *iface; - int rc, l; - - rc = libusb_get_active_config_descriptor(dev, &cdesc); - if (rc < 0) - return rc; - - iface = &cdesc->interface[if_num]; - /* FIXME: we assume there's no altsetting */ - idesc = &iface->altsetting[0]; - - for (l = 0; l < idesc->bNumEndpoints; l++) { - const struct libusb_endpoint_descriptor *edesc = &idesc->endpoint[l]; - switch (edesc->bmAttributes & 3) { - case LIBUSB_TRANSFER_TYPE_BULK: - if (edesc->bEndpointAddress & 0x80) { - if (in) - *in = edesc->bEndpointAddress; - } else { - if (out) - *out = edesc->bEndpointAddress; - } - break; - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - if (irq) - *irq = edesc->bEndpointAddress; - break; - default: - break; - } - } - return 0; -} - -#if 0 - struct libusb_device_descriptor ddesc; - int rc, i, j, k; - - rc = libusb_get_device_descriptor(devh, &ddesc); - if (rc < 0) - return; - - for (i = 0; i < ddesc.bNumConfigurations; i++) { - struct libusb_config_descriptor *cdesc; - rc = libusb_get_config_descriptor(devh, i, &cdesc); - if (rc < 0) - return; - - for (j = 0; j < cdesc->bNumInterfaces; j++) { - const struct libusb_interface *iface = cdesc->interface[j]; - for (k = 0; k < iface->num_altsetting; k++) { - const struct libusb_interface_descriptor *idesc = iface->altsetting[k]; - /* make sure this is the interface we're looking for */ - if (idesc->bInterfaceClass != 0xFF || - idesc->bInterfaceSubClass != if_class || - idsec->bInterfaceProtocol != if_proto) - continue; - /* FIXME */ - } - } - - libusb_free_config_descriptor(cdesc); - } -#endif diff --git a/host/simtrace2-discovery.h b/host/simtrace2-discovery.h deleted file mode 100644 index cfba956..0000000 --- a/host/simtrace2-discovery.h +++ /dev/null @@ -1,26 +0,0 @@ -/* simtrace2-discovery - host PC library to scan for matching USB - * devices - * - * (C) 2016 by Harald Welte <hwelte@hmw-consulting.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#pragma once - -#include <stdint.h> -#include <libusb.h> - -int get_usb_ep_addrs(libusb_device_handle *devh, unsigned int if_num, - uint8_t *out, uint8_t *in, uint8_t *irq); diff --git a/host/simtrace2-remsim.c b/host/simtrace2-remsim.c deleted file mode 100644 index 73a7272..0000000 --- a/host/simtrace2-remsim.c +++ /dev/null @@ -1,775 +0,0 @@ -/* simtrace2-remsim - main program for the host PC to provide a remote SIM - * using the SIMtrace 2 firmware in card emulation mode - * - * (C) 2016-2017 by Harald Welte <hwelte@hmw-consulting.de> - * (C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include <errno.h> -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdint.h> -#include <signal.h> -#include <time.h> -#define _GNU_SOURCE -#include <getopt.h> - -#include <sys/time.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> - -#include <libusb.h> - -#include "libusb_util.h" -#include "simtrace.h" -#include "simtrace_prot.h" -#include "apdu_dispatch.h" -#include "simtrace2-discovery.h" - -#include <osmocom/core/gsmtap.h> -#include <osmocom/core/gsmtap_util.h> -#include <osmocom/core/utils.h> -#include <osmocom/core/socket.h> -#include <osmocom/core/msgb.h> -#include <osmocom/sim/class_tables.h> -#include <osmocom/sim/sim.h> - -/* transport to a SIMtrace device */ -struct st_transport { - /* USB */ - struct libusb_device_handle *usb_devh; - struct { - uint8_t in; - uint8_t out; - uint8_t irq_in; - } usb_ep; - - /* UDP */ - int udp_fd; -}; - -/* a SIMtrace slot; communicates over a transport */ -struct st_slot { - /* transport through which the slot can be reached */ - struct st_transport *transp; - /* number of the slot within the transport */ - uint8_t slot_nr; -}; - -/* One istance of card emulation */ -struct cardem_inst { - /* slot on which this card emulation instance runs */ - struct st_slot *slot; - /* libosmosim SIM card profile */ - const struct osim_cla_ins_card_profile *card_prof; - /* libosmosim SIM card channel */ - struct osim_chan_hdl *chan; -}; - -/* global GSMTAP instance */ -static struct gsmtap_inst *g_gti; - -static int gsmtap_send_sim(const uint8_t *apdu, unsigned int len) -{ - struct gsmtap_hdr *gh; - unsigned int gross_len = len + sizeof(*gh); - uint8_t *buf = malloc(gross_len); - int rc; - - if (!buf) - return -ENOMEM; - - memset(buf, 0, sizeof(*gh)); - gh = (struct gsmtap_hdr *) buf; - gh->version = GSMTAP_VERSION; - gh->hdr_len = sizeof(*gh)/4; - gh->type = GSMTAP_TYPE_SIM; - - memcpy(buf + sizeof(*gh), apdu, len); - - rc = write(gsmtap_inst_fd(g_gti), buf, gross_len); - if (rc < 0) { - perror("write gsmtap"); - free(buf); - return rc; - } - - free(buf); - return 0; -} - -/*********************************************************************** - * SIMTRACE pcore protocol - ***********************************************************************/ - -/*! \brief allocate a message buffer for simtrace use */ -static struct msgb *st_msgb_alloc(void) -{ - return msgb_alloc_headroom(1024+32, 32, "SIMtrace"); -} - -#if 0 -static void apdu_out_cb(uint8_t *buf, unsigned int len, void *user_data) -{ - printf("APDU: %s\n", osmo_hexdump(buf, len)); - gsmtap_send_sim(buf, len); -} -#endif - -/*! \brief Transmit a given command to the SIMtrace2 device */ -int st_transp_tx_msg(struct st_transport *transp, struct msgb *msg) -{ - int rc; - - printf("<- %s\n", msgb_hexdump(msg)); - - if (transp->udp_fd < 0) { - int xfer_len; - - rc = libusb_bulk_transfer(transp->usb_devh, transp->usb_ep.out, - msgb_data(msg), msgb_length(msg), - &xfer_len, 100000); - } else { - rc = write(transp->udp_fd, msgb_data(msg), msgb_length(msg)); - } - - msgb_free(msg); - return rc; -} - -static struct simtrace_msg_hdr *st_push_hdr(struct msgb *msg, uint8_t msg_class, uint8_t msg_type, - uint8_t slot_nr) -{ - struct simtrace_msg_hdr *sh; - - sh = (struct simtrace_msg_hdr *) msgb_push(msg, sizeof(*sh)); - memset(sh, 0, sizeof(*sh)); - sh->msg_class = msg_class; - sh->msg_type = msg_type; - sh->slot_nr = slot_nr; - sh->msg_len = msgb_length(msg); - - return sh; -} - -/* transmit a given message to a specified slot. Expects all headers - * present before calling the function */ -int st_slot_tx_msg(struct st_slot *slot, struct msgb *msg, - uint8_t msg_class, uint8_t msg_type) -{ - st_push_hdr(msg, msg_class, msg_type, slot->slot_nr); - - return st_transp_tx_msg(slot->transp, msg); -} - -/*********************************************************************** - * Card Emulation protocol - ***********************************************************************/ - - -/*! \brief Request the SIMtrace2 to generate a card-insert signal */ -static int cardem_request_card_insert(struct cardem_inst *ci, bool inserted) -{ - struct msgb *msg = st_msgb_alloc(); - struct cardemu_usb_msg_cardinsert *cins; - - cins = (struct cardemu_usb_msg_cardinsert *) msgb_put(msg, sizeof(*cins)); - memset(cins, 0, sizeof(*cins)); - if (inserted) - cins->card_insert = 1; - - return st_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DT_CEMU_CARDINSERT); -} - -/*! \brief Request the SIMtrace2 to transmit a Procedure Byte, then Rx */ -static int cardem_request_pb_and_rx(struct cardem_inst *ci, uint8_t pb, uint8_t le) -{ - struct msgb *msg = st_msgb_alloc(); - struct cardemu_usb_msg_tx_data *txd; - txd = (struct cardemu_usb_msg_tx_data *) msgb_put(msg, sizeof(*txd)); - - printf("<= %s(%02x, %d)\n", __func__, pb, le); - - memset(txd, 0, sizeof(*txd)); - txd->data_len = 1; - txd->flags = CEMU_DATA_F_PB_AND_RX; - /* one data byte */ - msgb_put_u8(msg, pb); - - return st_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DT_CEMU_TX_DATA); -} - -/*! \brief Request the SIMtrace2 to transmit a Procedure Byte, then Tx */ -static int cardem_request_pb_and_tx(struct cardem_inst *ci, uint8_t pb, - const uint8_t *data, uint16_t data_len_in) -{ - struct msgb *msg = st_msgb_alloc(); - struct cardemu_usb_msg_tx_data *txd; - uint8_t *cur; - - txd = (struct cardemu_usb_msg_tx_data *) msgb_put(msg, sizeof(*txd)); - - printf("<= %s(%02x, %s, %d)\n", __func__, pb, - osmo_hexdump(data, data_len_in), data_len_in); - - memset(txd, 0, sizeof(*txd)); - txd->data_len = 1 + data_len_in; - txd->flags = CEMU_DATA_F_PB_AND_TX; - /* procedure byte */ - msgb_put_u8(msg, pb); - /* data */ - cur = msgb_put(msg, data_len_in); - memcpy(cur, data, data_len_in); - - return st_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DT_CEMU_TX_DATA); -} - -/*! \brief Request the SIMtrace2 to send a Status Word */ -static int cardem_request_sw_tx(struct cardem_inst *ci, const uint8_t *sw) -{ - struct msgb *msg = st_msgb_alloc(); - struct cardemu_usb_msg_tx_data *txd; - uint8_t *cur; - - txd = (struct cardemu_usb_msg_tx_data *) msgb_put(msg, sizeof(*txd)); - - printf("<= %s(%02x %02x)\n", __func__, sw[0], sw[1]); - - memset(txd, 0, sizeof(*txd)); - txd->data_len = 2; - txd->flags = CEMU_DATA_F_PB_AND_TX | CEMU_DATA_F_FINAL; - cur = msgb_put(msg, 2); - cur[0] = sw[0]; - cur[1] = sw[1]; - - return st_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DT_CEMU_TX_DATA); -} - -static void atr_update_csum(uint8_t *atr, unsigned int atr_len) -{ - uint8_t csum = 0; - int i; - - for (i = 1; i < atr_len - 1; i++) - csum = csum ^ atr[i]; - - atr[atr_len-1] = csum; -} - -static int cardem_request_set_atr(struct cardem_inst *ci, const uint8_t *atr, unsigned int atr_len) -{ - struct msgb *msg = st_msgb_alloc(); - struct cardemu_usb_msg_set_atr *satr; - uint8_t *cur; - - satr = (struct cardemu_usb_msg_set_atr *) msgb_put(msg, sizeof(*satr)); - - printf("<= %s(%s)\n", __func__, osmo_hexdump(atr, atr_len)); - - memset(satr, 0, sizeof(*satr)); - satr->atr_len = atr_len; - cur = msgb_put(msg, atr_len); - memcpy(cur, atr, atr_len); - - return st_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DT_CEMU_SET_ATR); -} - -/*********************************************************************** - * Modem Control protocol - ***********************************************************************/ - -static int _modem_reset(struct st_slot *slot, uint8_t asserted, uint16_t pulse_ms) -{ - struct msgb *msg = st_msgb_alloc(); - struct st_modem_reset *sr ; - - sr = (struct st_modem_reset *) msgb_put(msg, sizeof(*sr)); - sr->asserted = asserted; - sr->pulse_duration_msec = pulse_ms; - - return st_slot_tx_msg(slot, msg, SIMTRACE_MSGC_MODEM, SIMTRACE_MSGT_DT_MODEM_RESET); -} - -/*! \brief pulse the RESET line of the modem for \a duration_ms milli-seconds*/ -int st_modem_reset_pulse(struct st_slot *slot, uint16_t duration_ms) -{ - return _modem_reset(slot, 2, duration_ms); -} - -/*! \brief assert the RESET line of the modem */ -int st_modem_reset_active(struct st_slot *slot) -{ - return _modem_reset(slot, 1, 0); -} - -/*! \brief de-assert the RESET line of the modem */ -int st_modem_reset_inactive(struct st_slot *slot) -{ - return _modem_reset(slot, 0, 0); -} - -static int _modem_sim_select(struct st_slot *slot, uint8_t remote_sim) -{ - struct msgb *msg = st_msgb_alloc(); - struct st_modem_sim_select *ss; - - ss = (struct st_modem_sim_select *) msgb_put(msg, sizeof(*ss)); - ss->remote_sim = remote_sim; - - return st_slot_tx_msg(slot, msg, SIMTRACE_MSGC_MODEM, SIMTRACE_MSGT_DT_MODEM_SIM_SELECT); -} - -/*! \brief select local (physical) SIM for given slot */ -int st_modem_sim_select_local(struct st_slot *slot) -{ - return _modem_sim_select(slot, 0); -} - -/*! \brief select remote (emulated/forwarded) SIM for given slot */ -int st_modem_sim_select_remote(struct st_slot *slot) -{ - return _modem_sim_select(slot, 1); -} - -/*! \brief Request slot to send us status information about the modem */ -int st_modem_get_status(struct st_slot *slot) -{ - struct msgb *msg = st_msgb_alloc(); - - return st_slot_tx_msg(slot, msg, SIMTRACE_MSGC_MODEM, SIMTRACE_MSGT_BD_MODEM_STATUS); -} - - -/*********************************************************************** - * Incoming Messages - ***********************************************************************/ - -/*! \brief Process a STATUS message from the SIMtrace2 */ -static int process_do_status(struct cardem_inst *ci, uint8_t *buf, int len) -{ - struct cardemu_usb_msg_status *status; - status = (struct cardemu_usb_msg_status *) buf; - - printf("=> STATUS: flags=0x%x, fi=%u, di=%u, wi=%u wtime=%u\n", - status->flags, status->fi, status->di, status->wi, - status->waiting_time); - - return 0; -} - -/*! \brief Process a PTS indication message from the SIMtrace2 */ -static int process_do_pts(struct cardem_inst *ci, uint8_t *buf, int len) -{ - struct cardemu_usb_msg_pts_info *pts; - pts = (struct cardemu_usb_msg_pts_info *) buf; - - printf("=> PTS req: %s\n", osmo_hexdump(pts->req, sizeof(pts->req))); - - return 0; -} - -/*! \brief Process a ERROR indication message from the SIMtrace2 */ -static int process_do_error(struct cardem_inst *ci, uint8_t *buf, int len) -{ - struct cardemu_usb_msg_error *err; - err = (struct cardemu_usb_msg_error *) buf; - - printf("=> ERROR: %u/%u/%u: %s\n", - err->severity, err->subsystem, err->code, - err->msg_len ? (char *)err->msg : ""); - - return 0; -} - -/*! \brief Process a RX-DATA indication message from the SIMtrace2 */ -static int process_do_rx_da(struct cardem_inst *ci, uint8_t *buf, int len) -{ - static struct apdu_context ac; - struct cardemu_usb_msg_rx_data *data; - int rc; - - data = (struct cardemu_usb_msg_rx_data *) buf; - - printf("=> DATA: flags=%x, %s: ", data->flags, - osmo_hexdump(data->data, data->data_len)); - - rc = apdu_segment_in(&ac, data->data, data->data_len, - data->flags & CEMU_DATA_F_TPDU_HDR); - - if (rc & APDU_ACT_TX_CAPDU_TO_CARD) { - struct msgb *tmsg = msgb_alloc(1024, "TPDU"); - struct osim_reader_hdl *rh = ci->chan->card->reader; - uint8_t *cur; - - /* Copy TPDU header */ - cur = msgb_put(tmsg, sizeof(ac.hdr)); - memcpy(cur, &ac.hdr, sizeof(ac.hdr)); - /* Copy D(c), if any */ - if (ac.lc.tot) { - cur = msgb_put(tmsg, ac.lc.tot); - memcpy(cur, ac.dc, ac.lc.tot); - } - /* send to actual card */ - tmsg->l3h = tmsg->tail; - rc = rh->ops->transceive(rh, tmsg); - if (rc < 0) { - fprintf(stderr, "error during transceive: %d\n", rc); - msgb_free(tmsg); - return rc; - } - msgb_apdu_sw(tmsg) = msgb_get_u16(tmsg); - ac.sw[0] = msgb_apdu_sw(tmsg) >> 8; - ac.sw[1] = msgb_apdu_sw(tmsg) & 0xff; - printf("SW=0x%04x, len_rx=%d\n", msgb_apdu_sw(tmsg), msgb_l3len(tmsg)); - if (msgb_l3len(tmsg)) - cardem_request_pb_and_tx(ci, ac.hdr.ins, tmsg->l3h, msgb_l3len(tmsg)); - cardem_request_sw_tx(ci, ac.sw); - } else if (ac.lc.tot > ac.lc.cur) { - cardem_request_pb_and_rx(ci, ac.hdr.ins, ac.lc.tot - ac.lc.cur); - } - return 0; -} - -#if 0 - case SIMTRACE_CMD_DO_ERROR - rc = process_do_error(ci, buf, len); - break; -#endif - -/*! \brief Process an incoming message from the SIMtrace2 */ -static int process_usb_msg(struct cardem_inst *ci, uint8_t *buf, int len) -{ - struct simtrace_msg_hdr *sh = (struct simtrace_msg_hdr *)buf; - int rc; - - printf("-> %s\n", osmo_hexdump(buf, len)); - - buf += sizeof(*sh); - - switch (sh->msg_type) { - case SIMTRACE_MSGT_BD_CEMU_STATUS: - rc = process_do_status(ci, buf, len); - break; - case SIMTRACE_MSGT_DO_CEMU_PTS: - rc = process_do_pts(ci, buf, len); - break; - case SIMTRACE_MSGT_DO_CEMU_RX_DATA: - rc = process_do_rx_da(ci, buf, len); - break; - default: - printf("unknown simtrace msg type 0x%02x\n", sh->msg_type); - rc = -1; - break; - } - - return rc; -} - -static void print_welcome(void) -{ - printf("simtrace2-remsim - Remote SIM card forwarding\n" - "(C) 2010-2017, Harald Welte <laforge@gnumonks.org>\n" - "(C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>\n\n"); -} - -static void print_help(void) -{ - printf( "\t-r\t--remote-udp-host HOST\n" - "\t-p\t--remote-udp-port PORT\n" - "\t-h\t--help\n" - "\t-i\t--gsmtap-ip\tA.B.C.D\n" - "\t-a\t--skip-atr\n" - "\t-k\t--keep-running\n" - "\t-V\t--usb-vendor\tVENDOR_ID\n" - "\t-P\t--usb-product\tPRODUCT_ID\n" - "\t-C\t--usb-config\tCONFIG_ID\n" - "\t-I\t--usb-interface\tINTERFACE_ID\n" - "\t-S\t--usb-altsetting ALTSETTING_ID\n" - "\t-A\t--usb-address\tADDRESS\n" - "\t-H\t--usb-path\tPATH\n" - "\n" - ); -} - -static const struct option opts[] = { - { "remote-udp-host", 1, 0, 'r' }, - { "remote-udp-port", 1, 0, 'p' }, - { "gsmtap-ip", 1, 0, 'i' }, - { "skip-atr", 0, 0, 'a' }, - { "help", 0, 0, 'h' }, - { "keep-running", 0, 0, 'k' }, - { "usb-vendor", 1, 0, 'V' }, - { "usb-product", 1, 0, 'P' }, - { "usb-config", 1, 0, 'C' }, - { "usb-interface", 1, 0, 'I' }, - { "usb-altsetting", 1, 0, 'S' }, - { "usb-address", 1, 0, 'A' }, - { "usb-path", 1, 0, 'H' }, - { NULL, 0, 0, 0 } -}; - -static void run_mainloop(struct cardem_inst *ci) -{ - struct st_transport *transp = ci->slot->transp; - unsigned int msg_count, byte_count = 0; - uint8_t buf[16*265]; - int xfer_len; - int rc; - - printf("Entering main loop\n"); - - while (1) { - /* read data from SIMtrace2 device (local or via USB) */ - if (transp->udp_fd < 0) { - rc = libusb_bulk_transfer(transp->usb_devh, transp->usb_ep.in, - buf, sizeof(buf), &xfer_len, 100); - if (rc < 0 && rc != LIBUSB_ERROR_TIMEOUT && - rc != LIBUSB_ERROR_INTERRUPTED && - rc != LIBUSB_ERROR_IO) { - fprintf(stderr, "BULK IN transfer error; rc=%d\n", rc); - return; - } - } else { - rc = read(transp->udp_fd, buf, sizeof(buf)); - if (rc <= 0) { - fprintf(stderr, "shor read from UDP\n"); - return; - } - xfer_len = rc; - } - /* dispatch any incoming data */ - if (xfer_len > 0) { - printf("URB: %s\n", osmo_hexdump(buf, xfer_len)); - process_usb_msg(ci, buf, xfer_len); - msg_count++; - byte_count += xfer_len; - } - } -} - -static struct st_transport _transp; - -static struct st_slot _slot = { - .transp = &_transp, - .slot_nr = 0, -}; - -struct cardem_inst _ci = { - .slot = &_slot, -}; - -struct cardem_inst *ci = &_ci; - -static void signal_handler(int signal) -{ - switch (signal) { - case SIGINT: - cardem_request_card_insert(ci, false); - exit(0); - break; - default: - break; - } -} - -int main(int argc, char **argv) -{ - struct st_transport *transp = ci->slot->transp; - char *gsmtap_host = "127.0.0.1"; - int rc; - int c, ret = 1; - int skip_atr = 0; - int keep_running = 0; - int remote_udp_port = 52342; - int if_num = 0, vendor_id = -1, product_id = -1; - int config_id = -1, altsetting = 0, addr = -1; - char *remote_udp_host = NULL; - char *path = NULL; - struct osim_reader_hdl *reader; - struct osim_card_hdl *card; - - print_welcome(); - - while (1) { - int option_index = 0; - - c = getopt_long(argc, argv, "r:p:hi:V:P:C:I:S:A:H:ak", opts, &option_index); - if (c == -1) - break; - switch (c) { - case 'r': - remote_udp_host = optarg; - break; - case 'p': - remote_udp_port = atoi(optarg); - break; - case 'h': - print_help(); - exit(0); - break; - case 'i': - gsmtap_host = optarg; - break; - case 'a': - skip_atr = 1; - break; - case 'k': - keep_running = 1; - break; - case 'V': - vendor_id = strtol(optarg, NULL, 16); - break; - case 'P': - product_id = strtol(optarg, NULL, 16); - break; - case 'C': - config_id = atoi(optarg); - break; - case 'I': - if_num = atoi(optarg); - break; - case 'S': - altsetting = atoi(optarg); - break; - case 'A': - addr = atoi(optarg); - break; - case 'H': - path = optarg; - break; - } - } - - if (!remote_udp_host && (vendor_id < 0 || product_id < 0)) { - fprintf(stderr, "You have to specify the vendor and product ID\n"); - goto do_exit; - } - - transp->udp_fd = -1; - - ci->card_prof = &osim_uicc_sim_cic_profile; - - if (!remote_udp_host) { - rc = libusb_init(NULL); - if (rc < 0) { - fprintf(stderr, "libusb initialization failed\n"); - goto do_exit; - } - } else { - transp->udp_fd = osmo_sock_init(AF_INET, SOCK_DGRAM, IPPROTO_UDP, - remote_udp_host, remote_udp_port+if_num, - OSMO_SOCK_F_CONNECT); - if (transp->udp_fd < 0) { - fprintf(stderr, "error binding UDP port\n"); - goto do_exit; - } - } - - g_gti = gsmtap_source_init(gsmtap_host, GSMTAP_UDP_PORT, 0); - if (!g_gti) { - perror("unable to open GSMTAP"); - goto close_exit; - } - gsmtap_source_add_sink(g_gti); - - reader = osim_reader_open(OSIM_READER_DRV_PCSC, 0, "", NULL); - if (!reader) { - perror("unable to open PC/SC reader"); - goto close_exit; - } - - card = osim_card_open(reader, OSIM_PROTO_T0); - if (!card) { - perror("unable to open SIM card"); - goto close_exit; - } - - ci->chan = llist_entry(card->channels.next, struct osim_chan_hdl, list); - if (!ci->chan) { - perror("SIM card has no channel?!?"); - goto close_exit; - } - - signal(SIGINT, &signal_handler); - - do { - if (transp->udp_fd < 0) { - struct usb_interface_match _ifm, *ifm = &_ifm; - ifm->vendor = vendor_id; - ifm->product = product_id; - ifm->configuration = config_id; - ifm->interface = if_num; - ifm->altsetting = altsetting; - ifm->addr = addr; - if (path) - osmo_strlcpy(ifm->path, path, sizeof(ifm->path)); - transp->usb_devh = usb_open_claim_interface(NULL, ifm); - if (!transp->usb_devh) { - fprintf(stderr, "can't open USB device\n"); - goto close_exit; - } - - rc = libusb_claim_interface(transp->usb_devh, if_num); - if (rc < 0) { - fprintf(stderr, "can't claim interface %d; rc=%d\n", if_num, rc); - goto close_exit; - } - - rc = get_usb_ep_addrs(transp->usb_devh, if_num, &transp->usb_ep.out, - &transp->usb_ep.in, &transp->usb_ep.irq_in); - if (rc < 0) { - fprintf(stderr, "can't obtain EP addrs; rc=%d\n", rc); - goto close_exit; - } - } - - /* simulate card-insert to modem (owhw, not qmod) */ - cardem_request_card_insert(ci, true); - - /* select remote (forwarded) SIM */ - st_modem_sim_select_remote(ci->slot); - - /* set the ATR */ - uint8_t real_atr[] = { 0x3B, 0x9F, 0x96, 0x80, 0x1F, 0xC7, 0x80, 0x31, - 0xA0, 0x73, 0xBE, 0x21, 0x13, 0x67, 0x43, 0x20, - 0x07, 0x18, 0x00, 0x00, 0x01, 0xA5 }; - atr_update_csum(real_atr, sizeof(real_atr)); - cardem_request_set_atr(ci, real_atr, sizeof(real_atr)); - - /* select remote (forwarded) SIM */ - st_modem_reset_pulse(ci->slot, 300); - - run_mainloop(ci); - ret = 0; - - if (transp->udp_fd < 0) - libusb_release_interface(transp->usb_devh, 0); -close_exit: - if (transp->usb_devh) - libusb_close(transp->usb_devh); - if (keep_running) - sleep(1); - } while (keep_running); - - if (transp->udp_fd < 0) - libusb_exit(NULL); -do_exit: - return ret; -} diff --git a/host/simtrace_prot.h b/host/simtrace_prot.h deleted file mode 120000 index a9fffe1..0000000 --- a/host/simtrace_prot.h +++ /dev/null @@ -1 +0,0 @@ -../firmware/libcommon/include/simtrace_prot.h
\ No newline at end of file diff --git a/host/simtrace_usb.h b/host/simtrace_usb.h deleted file mode 120000 index f1e0982..0000000 --- a/host/simtrace_usb.h +++ /dev/null @@ -1 +0,0 @@ -../firmware/libcommon/include/simtrace_usb.h
\ No newline at end of file diff --git a/host/src/Makefile.am b/host/src/Makefile.am new file mode 100644 index 0000000..17be9eb --- /dev/null +++ b/host/src/Makefile.am @@ -0,0 +1,16 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -g $(LIBOSMOCORE_CFLAGS) $(LIBOSMOSIM_CFLAGS) $(LIBOSMOUSB_CFLAGS) $(LIBUSB_CFLAGS) $(COVERAGE_FLAGS) +AM_LDFLAGS=$(COVERAGE_LDFLAGS) + +LDADD= $(top_builddir)/lib/libosmo-simtrace2.la \ + $(LIBOSMOCORE_LIBS) $(LIBOSMOSIM_LIBS) $(LIBOSMOUSB_LIBS) $(LIBUSB_LIBS) + +bin_PROGRAMS = simtrace2-cardem-pcsc simtrace2-list simtrace2-sniff simtrace2-tool + +simtrace2_cardem_pcsc_SOURCES = simtrace2-cardem-pcsc.c + +simtrace2_list_SOURCES = simtrace2_usb.c + +simtrace2_sniff_SOURCES = simtrace2-sniff.c + +simtrace2_tool_SOURCES = simtrace2-tool.c diff --git a/host/src/simtrace2-cardem-pcsc.c b/host/src/simtrace2-cardem-pcsc.c new file mode 100644 index 0000000..4acf268 --- /dev/null +++ b/host/src/simtrace2-cardem-pcsc.c @@ -0,0 +1,683 @@ +/* simtrace2-cardem-pcsc - main program for the host PC to provide a remote SIM + * using the SIMtrace 2 firmware in card emulation mode + * + * (C) 2016-2022 by Harald Welte <hwelte@hmw-consulting.de> + * (C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <errno.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <signal.h> +#include <time.h> +#define _GNU_SOURCE +#include <getopt.h> + +#include <sys/time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <libusb.h> + +#include <osmocom/usb/libusb.h> +#include <osmocom/simtrace2/simtrace2_api.h> +#include <osmocom/simtrace2/simtrace_prot.h> +#include <osmocom/simtrace2/apdu_dispatch.h> +#include <osmocom/simtrace2/gsmtap.h> + +#include <osmocom/core/utils.h> +#include <osmocom/core/socket.h> +#include <osmocom/core/msgb.h> +#include <osmocom/core/select.h> +#include <osmocom/core/logging.h> +#include <osmocom/core/application.h> +#include <osmocom/sim/class_tables.h> +#include <osmocom/sim/sim.h> + +#define LOGCI(ci, lvl, fmt, args ...) LOGP(DLGLOBAL, lvl, fmt, ## args) + +static void atr_update_csum(uint8_t *atr, unsigned int atr_len) +{ + uint8_t csum = 0; + int i; + + for (i = 1; i < atr_len - 1; i++) + csum = csum ^ atr[i]; + + atr[atr_len-1] = csum; +} + +static void cemu_status_flags2str(char *out, unsigned int out_len, uint32_t flags) +{ + snprintf(out, out_len, "%s%s%s%s%s", + flags & CEMU_STATUS_F_RESET_ACTIVE ? "RESET " : "", + flags & CEMU_STATUS_F_VCC_PRESENT ? "VCC " : "", + flags & CEMU_STATUS_F_CLK_ACTIVE ? "CLK " : "", + flags & CEMU_STATUS_F_CARD_INSERT ? "CARD_PRES " : "", + flags & CEMU_STATUS_F_RCEMU_ACTIVE ? "RCEMU " : ""); +} + +static uint32_t last_status_flags = 0; + +#define NO_RESET 0 +#define COLD_RESET 1 +#define WARM_RESET 2 + +static void update_status_flags(struct osmo_st2_cardem_inst *ci, uint32_t flags) +{ + struct osim_card_hdl *card = ci->chan->card; + int reset = NO_RESET; + + /* check if card is _now_ operational: VCC+CLK present, RST absent */ + if ((flags & CEMU_STATUS_F_VCC_PRESENT) && (flags & CEMU_STATUS_F_CLK_ACTIVE) && + !(flags & CEMU_STATUS_F_RESET_ACTIVE)) { + if (last_status_flags & CEMU_STATUS_F_RESET_ACTIVE) { + /* a reset has just ended, forward it to the real card */ + if (last_status_flags & CEMU_STATUS_F_VCC_PRESENT) + reset = WARM_RESET; + else + reset = COLD_RESET; + } else if (!(last_status_flags & CEMU_STATUS_F_VCC_PRESENT)) { + /* power-up has just happened, perform cold reset */ + reset = COLD_RESET; + } + } else if (flags == CEMU_STATUS_F_VCC_PRESENT && + !(last_status_flags & CEMU_STATUS_F_VCC_PRESENT)) { + /* improper power-up: Only power enabled, but no reset active. */ + reset = COLD_RESET; + } + + if (reset) { + LOGCI(ci, LOGL_NOTICE, "%s Resetting card in reader...\n", + reset == COLD_RESET ? "Cold" : "Warm"); + osim_card_reset(card, reset == COLD_RESET ? true : false); + + /* Mark reset event in GSMTAP wireshark trace */ + osmo_st2_gsmtap_send_apdu(GSMTAP_SIM_ATR, card->atr, card->atr_len); + } + + last_status_flags = flags; +} + +static const char *cemu_data_flags2str(uint32_t flags) +{ + static char out[64]; + snprintf(out, sizeof(out), "%s%s%s%s", + flags & CEMU_DATA_F_TPDU_HDR ? "HDR " : "", + flags & CEMU_DATA_F_FINAL ? "FINAL " : "", + flags & CEMU_DATA_F_PB_AND_TX ? "PB_AND_TX " : "", + flags & CEMU_DATA_F_PB_AND_RX ? "PB_AND_RX" : ""); + return out; +} + +/*********************************************************************** + * Incoming Messages + ***********************************************************************/ + +/*! \brief Process a STATUS message from the SIMtrace2 */ +static int process_do_status(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len) +{ + struct cardemu_usb_msg_status *status = (struct cardemu_usb_msg_status *) buf; + char fbuf[80]; + + cemu_status_flags2str(fbuf, sizeof(fbuf), status->flags); + LOGCI(ci, LOGL_NOTICE, "=> STATUS: flags=0x%x, fi=%u, di=%u, wi=%u wtime=%u (%s)\n", + status->flags, status->fi, status->di, status->wi, + status->waiting_time, fbuf); + + update_status_flags(ci, status->flags); + + return 0; +} + +/*! \brief Process a PTS indication message from the SIMtrace2 */ +static int process_do_pts(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len) +{ + struct cardemu_usb_msg_pts_info *pts; + pts = (struct cardemu_usb_msg_pts_info *) buf; + + LOGCI(ci, LOGL_NOTICE, "=> PTS req: %s\n", osmo_hexdump(pts->req, pts->pts_len)); + + return 0; +} + +/*! \brief Process a RX-DATA indication message from the SIMtrace2 */ +static int process_do_rx_da(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len) +{ + static struct osmo_apdu_context ac; + struct cardemu_usb_msg_rx_data *data; + int rc; + + data = (struct cardemu_usb_msg_rx_data *) buf; + + LOGCI(ci, LOGL_INFO, "=> DATA: flags=0x%02x (%s), %s\n ", data->flags, + cemu_data_flags2str(data->flags), osmo_hexdump(data->data, data->data_len)); + + rc = osmo_apdu_segment_in(&ac, data->data, data->data_len, + data->flags & CEMU_DATA_F_TPDU_HDR); + if (rc < 0) { + /* At this point the communication is broken. We cannot keep running, as we + * don't know if we should continue transmitting or receiving. Only a successful + * return value by osmo_apdu_segment_in() would allow us to know this. */ + LOGCI(ci, LOGL_FATAL, "Failed to recognize APDU, terminating\n"); + exit(1); + } + + if (rc & APDU_ACT_TX_CAPDU_TO_CARD) { + struct msgb *tmsg = msgb_alloc(1024, "TPDU"); + struct osim_reader_hdl *rh = ci->chan->card->reader; + uint8_t *cur; + + /* Copy TPDU header */ + cur = msgb_put(tmsg, sizeof(ac.hdr)); + memcpy(cur, &ac.hdr, sizeof(ac.hdr)); + /* Copy D(c), if any */ + if (ac.lc.tot) { + cur = msgb_put(tmsg, ac.lc.tot); + memcpy(cur, ac.dc, ac.lc.tot); + } + /* send to actual card */ + tmsg->l3h = tmsg->tail; + rc = rh->ops->transceive(rh, tmsg); + if (rc < 0) { + fprintf(stderr, "error during transceive: %d\n", rc); + msgb_free(tmsg); + return rc; + } + /* send via GSMTAP for wireshark tracing */ + osmo_st2_gsmtap_send_apdu(GSMTAP_SIM_APDU, tmsg->data, msgb_length(tmsg)); + + msgb_apdu_sw(tmsg) = msgb_get_u16(tmsg); + ac.sw[0] = msgb_apdu_sw(tmsg) >> 8; + ac.sw[1] = msgb_apdu_sw(tmsg) & 0xff; + if (msgb_l3len(tmsg)) + osmo_st2_cardem_request_pb_and_tx(ci, ac.hdr.ins, tmsg->l3h, msgb_l3len(tmsg)); + osmo_st2_cardem_request_sw_tx(ci, ac.sw); + } else if (ac.lc.tot > ac.lc.cur) { + osmo_st2_cardem_request_pb_and_rx(ci, ac.hdr.ins, ac.lc.tot - ac.lc.cur); + } + return 0; +} + +/*! \brief Process an incoming message from the SIMtrace2 */ +static int process_usb_msg(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len) +{ + struct simtrace_msg_hdr *sh = (struct simtrace_msg_hdr *)buf; + int rc; + + buf += sizeof(*sh); + + switch (sh->msg_type) { + case SIMTRACE_MSGT_BD_CEMU_STATUS: + rc = process_do_status(ci, buf, len); + break; + case SIMTRACE_MSGT_DO_CEMU_PTS: + rc = process_do_pts(ci, buf, len); + break; + case SIMTRACE_MSGT_DO_CEMU_RX_DATA: + rc = process_do_rx_da(ci, buf, len); + break; + case SIMTRACE_MSGT_BD_CEMU_CONFIG: + /* firmware confirms configuration change; ignore */ + rc = 0; + break; + default: + printf("unknown simtrace msg type 0x%02x\n", sh->msg_type); + rc = -1; + break; + } + + return rc; +} + +/*! \brief Process a STATUS message on IRQ endpoint from the SIMtrace2 */ +static int process_irq_status(struct osmo_st2_cardem_inst *ci, const uint8_t *buf, int len) +{ + const struct cardemu_usb_msg_status *status = (struct cardemu_usb_msg_status *) buf; + char fbuf[80]; + + cemu_status_flags2str(fbuf, sizeof(fbuf), status->flags); + LOGCI(ci, LOGL_NOTICE, "=> IRQ STATUS: flags=0x%x, fi=%u, di=%u, wi=%u wtime=%u (%s)\n", + status->flags, status->fi, status->di, status->wi, + status->waiting_time, fbuf); + + update_status_flags(ci, status->flags); + + return 0; +} + +static int process_usb_msg_irq(struct osmo_st2_cardem_inst *ci, const uint8_t *buf, unsigned int len) +{ + struct simtrace_msg_hdr *sh = (struct simtrace_msg_hdr *)buf; + int rc; + + buf += sizeof(*sh); + + switch (sh->msg_type) { + case SIMTRACE_MSGT_BD_CEMU_STATUS: + rc = process_irq_status(ci, buf, len); + break; + default: + LOGCI(ci, LOGL_ERROR, "unknown simtrace msg type 0x%02x\n", sh->msg_type); + rc = -1; + break; + } + + return rc; +} + +static void usb_in_xfer_cb(struct libusb_transfer *xfer) +{ + struct osmo_st2_cardem_inst *ci = xfer->user_data; + int rc; + + switch (xfer->status) { + case LIBUSB_TRANSFER_COMPLETED: + /* hand the message up the stack */ + process_usb_msg(ci, xfer->buffer, xfer->actual_length); + break; + case LIBUSB_TRANSFER_ERROR: + LOGCI(ci, LOGL_FATAL, "USB IN transfer error, trying resubmit\n"); + break; + case LIBUSB_TRANSFER_NO_DEVICE: + LOGCI(ci, LOGL_FATAL, "USB device disappeared\n"); + exit(1); + break; + default: + LOGCI(ci, LOGL_FATAL, "USB IN transfer failed, status=%u\n", xfer->status); + exit(1); + break; + } + + /* re-submit the IN transfer */ + rc = libusb_submit_transfer(xfer); + OSMO_ASSERT(rc == 0); +} + + +static void allocate_and_submit_in(struct osmo_st2_cardem_inst *ci) +{ + struct osmo_st2_transport *transp = ci->slot->transp; + struct libusb_transfer *xfer; + int rc; + + xfer = libusb_alloc_transfer(0); + OSMO_ASSERT(xfer); + xfer->dev_handle = transp->usb_devh; + xfer->flags = 0; + xfer->type = LIBUSB_TRANSFER_TYPE_BULK; + xfer->endpoint = transp->usb_ep.in; + xfer->timeout = 0; + xfer->user_data = ci; + xfer->length = 16*256; + + xfer->buffer = libusb_dev_mem_alloc(xfer->dev_handle, xfer->length); + OSMO_ASSERT(xfer->buffer); + xfer->callback = usb_in_xfer_cb; + + /* submit the IN transfer */ + rc = libusb_submit_transfer(xfer); + OSMO_ASSERT(rc == 0); +} + + +static void usb_irq_xfer_cb(struct libusb_transfer *xfer) +{ + struct osmo_st2_cardem_inst *ci = xfer->user_data; + int rc; + + switch (xfer->status) { + case LIBUSB_TRANSFER_COMPLETED: + process_usb_msg_irq(ci, xfer->buffer, xfer->actual_length); + break; + case LIBUSB_TRANSFER_ERROR: + LOGCI(ci, LOGL_FATAL, "USB INT transfer error, trying resubmit\n"); + break; + case LIBUSB_TRANSFER_NO_DEVICE: + LOGCI(ci, LOGL_FATAL, "USB device disappeared\n"); + exit(1); + break; + default: + LOGCI(ci, LOGL_FATAL, "USB INT transfer failed, status=%u\n", xfer->status); + exit(1); + break; + } + + /* re-submit the IN transfer */ + rc = libusb_submit_transfer(xfer); + OSMO_ASSERT(rc == 0); +} + + +static void allocate_and_submit_irq(struct osmo_st2_cardem_inst *ci) +{ + struct osmo_st2_transport *transp = ci->slot->transp; + struct libusb_transfer *xfer; + int rc; + + xfer = libusb_alloc_transfer(0); + OSMO_ASSERT(xfer); + xfer->dev_handle = transp->usb_devh; + xfer->flags = 0; + xfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT; + xfer->endpoint = transp->usb_ep.irq_in; + xfer->timeout = 0; + xfer->user_data = ci; + xfer->length = 64; + + xfer->buffer = libusb_dev_mem_alloc(xfer->dev_handle, xfer->length); + OSMO_ASSERT(xfer->buffer); + xfer->callback = usb_irq_xfer_cb; + + /* submit the IN transfer */ + rc = libusb_submit_transfer(xfer); + OSMO_ASSERT(rc == 0); +} + + + +static void print_welcome(void) +{ + printf("simtrace2-cardem-pcsc - Using PC/SC reader as SIM\n" + "(C) 2010-2022, Harald Welte <laforge@gnumonks.org>\n" + "(C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>\n\n"); +} + +static void print_help(void) +{ + printf( "\t-h\t--help\n" + "\t-i\t--gsmtap-ip\tA.B.C.D\n" + "\t-a\t--skip-atr\n" + "\t-t\t--set-atr\tATR-STRING in HEX\n" + "\t-k\t--keep-running\n" + "\t-n\t--pcsc-reader-num\n" + "\t-V\t--usb-vendor\tVENDOR_ID\n" + "\t-P\t--usb-product\tPRODUCT_ID\n" + "\t-C\t--usb-config\tCONFIG_ID\n" + "\t-I\t--usb-interface\tINTERFACE_ID\n" + "\t-S\t--usb-altsetting ALTSETTING_ID\n" + "\t-A\t--usb-address\tADDRESS\n" + "\t-H\t--usb-path\tPATH\n" + "\n" + ); +} + +static const struct option opts[] = { + { "gsmtap-ip", 1, 0, 'i' }, + { "skip-atr", 0, 0, 'a' }, + { "set-atr", 1, 0, 't' }, + { "help", 0, 0, 'h' }, + { "keep-running", 0, 0, 'k' }, + { "pcsc-reader-num", 1, 0, 'n' }, + { "usb-vendor", 1, 0, 'V' }, + { "usb-product", 1, 0, 'P' }, + { "usb-config", 1, 0, 'C' }, + { "usb-interface", 1, 0, 'I' }, + { "usb-altsetting", 1, 0, 'S' }, + { "usb-address", 1, 0, 'A' }, + { "usb-path", 1, 0, 'H' }, + { NULL, 0, 0, 0 } +}; + +static void run_mainloop(struct osmo_st2_cardem_inst *ci) +{ + printf("Entering main loop\n"); + while (1) { + osmo_select_main(0); + } +} + +static struct osmo_st2_transport _transp; + +static struct osmo_st2_slot _slot = { + .transp = &_transp, + .slot_nr = 0, +}; + +struct osmo_st2_cardem_inst _ci = { + .slot = &_slot, +}; + +struct osmo_st2_cardem_inst *ci = &_ci; + +static void signal_handler(int signal) +{ + switch (signal) { + case SIGINT: + osmo_st2_cardem_request_card_insert(ci, false); + osmo_st2_modem_sim_select_local(ci->slot); + exit(0); + break; + default: + break; + } +} + +static struct log_info log_info = {}; + +int main(int argc, char **argv) +{ + struct osmo_st2_transport *transp = ci->slot->transp; + char *gsmtap_host = "127.0.0.1"; + int rc; + int c, ret = 1; + int skip_atr = 0; + char *atr = NULL; + uint8_t override_atr[OSIM_MAX_ATR_LEN]; + int override_atr_len = 0; + int keep_running = 0; + int if_num = 0, vendor_id = -1, product_id = -1; + int config_id = -1, altsetting = 0, addr = -1; + int reader_num = 0; + char *path = NULL; + struct osim_reader_hdl *reader; + struct osim_card_hdl *card; + + print_welcome(); + + osmo_init_logging2(NULL, &log_info); + + rc = osmo_libusb_init(NULL); + if (rc < 0) { + fprintf(stderr, "libusb initialization failed\n"); + return rc; + } + + log_set_print_category_hex(osmo_stderr_target, false); + log_set_print_category(osmo_stderr_target, true); + log_set_print_level(osmo_stderr_target, true); + log_set_print_filename_pos(osmo_stderr_target, LOG_FILENAME_POS_LINE_END); + log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE); + log_set_category_filter(osmo_stderr_target, DLINP, 1, LOGL_DEBUG); + log_set_category_filter(osmo_stderr_target, DLGLOBAL, 1, LOGL_DEBUG); + + while (1) { + int option_index = 0; + + c = getopt_long(argc, argv, "hi:V:P:C:I:S:A:H:akn:t:", opts, &option_index); + if (c == -1) + break; + switch (c) { + case 'h': + print_help(); + exit(0); + break; + case 'i': + gsmtap_host = optarg; + break; + case 'a': + skip_atr = 1; + break; + case 't': + atr = optarg; + break; + case 'k': + keep_running = 1; + break; + case 'n': + reader_num = atoi(optarg); + break; + case 'V': + vendor_id = strtol(optarg, NULL, 16); + break; + case 'P': + product_id = strtol(optarg, NULL, 16); + break; + case 'C': + config_id = atoi(optarg); + break; + case 'I': + if_num = atoi(optarg); + break; + case 'S': + altsetting = atoi(optarg); + break; + case 'A': + addr = atoi(optarg); + break; + case 'H': + path = optarg; + break; + } + } + + if (atr) { + override_atr_len = osmo_hexparse(atr, override_atr, sizeof(override_atr)); + if (override_atr_len < 2) { + fprintf(stderr, "Invalid ATR - please omit a leading 0x and only use valid hex " + "digits and whitespace. ATRs need to be between 2 and 33 bytes long.\n"); + goto do_exit; + } + } + + if (vendor_id < 0 || product_id < 0) { + fprintf(stderr, "You have to specify the vendor and product ID\n"); + goto do_exit; + } + + ci->card_prof = &osim_uicc_sim_cic_profile; + + rc = osmo_st2_gsmtap_init(gsmtap_host); + if (rc < 0) { + perror("unable to open GSMTAP"); + goto close_exit; + } + + reader = osim_reader_open(OSIM_READER_DRV_PCSC, reader_num, "", NULL); + if (!reader) { + perror("unable to open PC/SC reader"); + goto close_exit; + } + + card = osim_card_open(reader, OSIM_PROTO_T0); + if (!card) { + perror("unable to open SIM card"); + goto close_exit; + } + + ci->chan = llist_entry(card->channels.next, struct osim_chan_hdl, list); + if (!ci->chan) { + perror("SIM card has no channel?!?"); + goto close_exit; + } + + signal(SIGINT, &signal_handler); + + do { + struct usb_interface_match _ifm, *ifm = &_ifm; + memset(ifm, 0, sizeof(*ifm)); + ifm->vendor = vendor_id; + ifm->product = product_id; + ifm->configuration = config_id; + ifm->interface = if_num; + ifm->altsetting = altsetting; + if (addr > 0 && addr < 256) + ifm->addr = addr; + if (path) + osmo_strlcpy(ifm->path, path, sizeof(ifm->path)); + transp->udp_fd = -1; + transp->usb_async = true; + transp->usb_devh = osmo_libusb_open_claim_interface(NULL, NULL, ifm); + if (!transp->usb_devh) { + fprintf(stderr, "can't open USB device: %s\n", strerror(errno)); + goto close; + } + + rc = libusb_claim_interface(transp->usb_devh, if_num); + if (rc < 0) { + fprintf(stderr, "can't claim interface %d; rc=%d\n", if_num, rc); + goto close; + } + + rc = osmo_libusb_get_ep_addrs(transp->usb_devh, if_num, &transp->usb_ep.out, + &transp->usb_ep.in, &transp->usb_ep.irq_in); + if (rc < 0) { + fprintf(stderr, "can't obtain EP addrs; rc=%d\n", rc); + goto close; + } + + allocate_and_submit_irq(ci); + for (int i = 0; i < 4; i++) + allocate_and_submit_in(ci); + + /* request firmware to generate STATUS on IRQ endpoint */ + osmo_st2_cardem_request_config(ci, CEMU_FEAT_F_STATUS_IRQ); + + /* simulate card-insert to modem (owhw, not qmod) */ + osmo_st2_cardem_request_card_insert(ci, true); + + /* select remote (forwarded) SIM */ + osmo_st2_modem_sim_select_remote(ci->slot); + + if (!skip_atr) { + /* set the ATR */ + if (override_atr_len) { + /* user has specified an override-ATR */ + atr_update_csum(override_atr, override_atr_len); + osmo_st2_cardem_request_set_atr(ci, override_atr, override_atr_len); + } else { + /* use the real ATR of the card */ + osmo_st2_cardem_request_set_atr(ci, card->atr, card->atr_len); + } + } + + /* select remote (forwarded) SIM */ + osmo_st2_modem_reset_pulse(ci->slot, 300); + + run_mainloop(ci); + ret = 0; + + libusb_release_interface(transp->usb_devh, 0); + +close: + if (transp->usb_devh) { + libusb_close(transp->usb_devh); + transp->usb_devh = NULL; + } + if (keep_running) + sleep(1); + } while (keep_running); + +close_exit: + if (transp->usb_devh) + libusb_close(transp->usb_devh); + + osmo_libusb_exit(NULL); +do_exit: + return ret; +} diff --git a/host/simtrace2-sniff.c b/host/src/simtrace2-sniff.c index dddf5cf..8504e8b 100644 --- a/host/simtrace2-sniff.c +++ b/host/src/simtrace2-sniff.c @@ -13,10 +13,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include <errno.h> #include <unistd.h> @@ -37,33 +33,18 @@ #include <libusb.h> -#include "libusb_util.h" -#include "simtrace.h" -#include "simtrace_usb.h" -#include "simtrace_prot.h" -#include "simtrace2-discovery.h" +#include <osmocom/usb/libusb.h> +#include <osmocom/simtrace2/simtrace_usb.h> +#include <osmocom/simtrace2/simtrace_prot.h> + +#include <osmocom/simtrace2/gsmtap.h> -#include <osmocom/core/gsmtap.h> -#include <osmocom/core/gsmtap_util.h> #include <osmocom/core/utils.h> #include <osmocom/core/socket.h> #include <osmocom/core/msgb.h> #include <osmocom/sim/class_tables.h> #include <osmocom/sim/sim.h> -/* as of August 26, 2018 we don't have any released libosmocore version which includes those - * definitions yet. Let's ensure some backwards compatibility: */ -#ifndef GSMTAP_SIM_APDU -#define GSMTAP_SIM_APDU 0x00 /* APDU data (complete APDU) */ -#define GSMTAP_SIM_ATR 0x01 /* card ATR data */ -#define GSMTAP_SIM_PPS_REQ 0x02 /* PPS request data */ -#define GSMTAP_SIM_PPS_RSP 0x03 /* PPS response data */ -#define GSMTAP_SIM_TPDU_HDR 0x04 /* TPDU command header */ -#define GSMTAP_SIM_TPDU_CMD 0x05 /* TPDU command body */ -#define GSMTAP_SIM_TPDU_RSP 0x06 /* TPDU response body */ -#define GSMTAP_SIM_TPDU_SW 0x07 /* TPDU response trailer */ -#endif - /* transport to a SIMtrace device */ struct st_transport { /* USB */ @@ -75,90 +56,27 @@ struct st_transport { } usb_ep; }; -/* global GSMTAP instance */ -static struct gsmtap_inst *g_gti; - -static int gsmtap_send_sim(uint8_t sub_type, const uint8_t *data, unsigned int len) -{ - struct gsmtap_hdr *gh; - unsigned int gross_len = len + sizeof(*gh); - uint8_t *buf = malloc(gross_len); - int rc; - - if (!buf) - return -ENOMEM; - - memset(buf, 0, sizeof(*gh)); - gh = (struct gsmtap_hdr *) buf; - gh->version = GSMTAP_VERSION; - gh->hdr_len = sizeof(*gh)/4; - gh->type = GSMTAP_TYPE_SIM; - gh->sub_type = sub_type; - - memcpy(buf + sizeof(*gh), data, len); - - rc = write(gsmtap_inst_fd(g_gti), buf, gross_len); - if (rc < 0) { - perror("write gsmtap"); - free(buf); - return rc; - } - - free(buf); - return 0; -} - const struct value_string change_flags[] = { - { - .value = SNIFF_CHANGE_FLAG_CARD_INSERT, - .str = "card inserted", - }, - { - .value = SNIFF_CHANGE_FLAG_CARD_EJECT, - .str = "card ejected", - }, - { - .value = SNIFF_CHANGE_FLAG_RESET_ASSERT, - .str = "reset asserted", - }, - { - .value = SNIFF_CHANGE_FLAG_RESET_DEASSERT, - .str = "reset de-asserted", - }, - { - .value = SNIFF_CHANGE_FLAG_TIMEOUT_WT, - .str = "data transfer timeout", - }, - { - .value = 0, - .str = NULL, - }, + { SNIFF_CHANGE_FLAG_CARD_INSERT, "card inserted" }, + { SNIFF_CHANGE_FLAG_CARD_EJECT, "card ejected" }, + { SNIFF_CHANGE_FLAG_RESET_ASSERT, "reset asserted" }, + { SNIFF_CHANGE_FLAG_RESET_DEASSERT, "reset de-asserted" }, + { SNIFF_CHANGE_FLAG_TIMEOUT_WT, "data transfer timeout" }, + { 0, NULL } }; const struct value_string data_flags[] = { - { - .value = SNIFF_DATA_FLAG_ERROR_INCOMPLETE, - .str = "incomplete", - }, - { - .value = SNIFF_DATA_FLAG_ERROR_MALFORMED, - .str = "malformed", - }, - { - .value = SNIFF_DATA_FLAG_ERROR_CHECKSUM, - .str = "checksum error", - }, - { - .value = 0, - .str = NULL, - }, + { SNIFF_DATA_FLAG_ERROR_INCOMPLETE, "incomplete" }, + { SNIFF_DATA_FLAG_ERROR_MALFORMED, "malformed" }, + { SNIFF_DATA_FLAG_ERROR_CHECKSUM, "checksum error" }, + { 0, NULL } }; static void print_flags(const struct value_string* flag_meanings, uint32_t nb_flags, uint32_t flags) { uint32_t i; for (i = 0; i < nb_flags; i++) { if (flags & flag_meanings[i].value) { - printf(flag_meanings[i].str); + printf("%s", flag_meanings[i].str); flags &= ~flag_meanings[i].value; if (flags) { printf(", "); @@ -252,11 +170,11 @@ static int process_data(enum simtrace_msg_type_sniff type, const uint8_t *buf, i /* Send message as GSNTAP */ switch (type) { case SIMTRACE_MSGT_SNIFF_ATR: - gsmtap_send_sim(GSMTAP_SIM_ATR, data->data, data->length); + osmo_st2_gsmtap_send_apdu(GSMTAP_SIM_ATR, data->data, data->length); break; case SIMTRACE_MSGT_SNIFF_TPDU: /* TPDU is now considered as APDU since SIMtrace sends complete TPDU */ - gsmtap_send_sim(GSMTAP_SIM_APDU, data->data, data->length); + osmo_st2_gsmtap_send_apdu(GSMTAP_SIM_APDU, data->data, data->length); break; default: break; @@ -393,6 +311,7 @@ static const struct option opts[] = { /* Known USB device with SIMtrace firmware supporting sniffer */ static const struct dev_id compatible_dev_ids[] = { { USB_VENDOR_OPENMOKO, USB_PRODUCT_SIMTRACE2 }, + { USB_VENDOR_OPENMOKO, USB_PRODUCT_NGFF_CARDEM }, { 0, 0 } }; @@ -420,7 +339,7 @@ int main(int argc, char **argv) while (1) { int option_index = 0; - char c = getopt_long(argc, argv, "hi:kV:P:C:I:S:A:", opts, &option_index); + int c = getopt_long(argc, argv, "hi:kV:P:C:I:S:A:", opts, &option_index); if (c == -1) break; switch (c) { @@ -456,13 +375,13 @@ int main(int argc, char **argv) } /* Scan for available SIMtrace USB devices supporting sniffing */ - rc = libusb_init(NULL); + rc = osmo_libusb_init(NULL); if (rc < 0) { fprintf(stderr, "libusb initialization failed\n"); goto do_exit; } struct usb_interface_match ifm_scan[16]; - int num_interfaces = usb_match_interfaces(NULL, compatible_dev_ids, + int num_interfaces = osmo_libusb_find_matching_interfaces(NULL, compatible_dev_ids, USB_CLASS_PROPRIETARY, SIMTRACE_SNIFFER_USB_SUBCLASS, -1, ifm_scan, ARRAY_SIZE(ifm_scan)); if (num_interfaces <= 0) { perror("No compatible USB devices found"); @@ -523,9 +442,9 @@ int main(int argc, char **argv) } struct usb_interface_match ifm_selected = ifm_filtered[0]; printf("Using USB device %04x:%04x Addr=%u, Path=%s, Cfg=%u, Intf=%u, Alt=%u: %d/%d/%d ", - ifm_selected.vendor, ifm_selected.product, ifm_selected.addr, ifm_selected.path, - ifm_selected.configuration, ifm_selected.interface, ifm_selected.altsetting, - ifm_selected.class, ifm_selected.sub_class, ifm_selected.protocol); + ifm_selected.vendor, ifm_selected.product, ifm_selected.addr, ifm_selected.path, + ifm_selected.configuration, ifm_selected.interface, ifm_selected.altsetting, + ifm_selected.class, ifm_selected.sub_class, ifm_selected.protocol); libusb_device_handle *dev_handle; rc = libusb_open(ifm_selected.usb_dev, &dev_handle); if (rc < 0) { @@ -542,19 +461,18 @@ int main(int argc, char **argv) } printf("(%s)\n", strbuf); - g_gti = gsmtap_source_init(gsmtap_host, GSMTAP_UDP_PORT, 0); - if (!g_gti) { + rc = osmo_st2_gsmtap_init(gsmtap_host); + if (rc < 0) { perror("unable to open GSMTAP"); goto close_exit; } - gsmtap_source_add_sink(g_gti); signal(SIGINT, &signal_handler); do { - _transp.usb_devh = usb_open_claim_interface(NULL, &ifm_selected); + _transp.usb_devh = osmo_libusb_open_claim_interface(NULL, NULL, &ifm_selected); if (!_transp.usb_devh) { - fprintf(stderr, "can't open USB device\n"); + fprintf(stderr, "can't open USB device: %s\n", strerror(errno)); goto close_exit; } @@ -564,8 +482,8 @@ int main(int argc, char **argv) goto close_exit; } - rc = get_usb_ep_addrs(_transp.usb_devh, ifm_selected.interface, &_transp.usb_ep.out, - &_transp.usb_ep.in, &_transp.usb_ep.irq_in); + rc = osmo_libusb_get_ep_addrs(_transp.usb_devh, ifm_selected.interface, &_transp.usb_ep.out, + &_transp.usb_ep.in, &_transp.usb_ep.irq_in); if (rc < 0) { fprintf(stderr, "can't obtain EP addrs; rc=%d\n", rc); goto close_exit; @@ -583,7 +501,7 @@ close_exit: sleep(1); } while (keep_running); - libusb_exit(NULL); + osmo_libusb_exit(NULL); do_exit: return ret; } diff --git a/host/src/simtrace2-tool.c b/host/src/simtrace2-tool.c new file mode 100644 index 0000000..fdf0d56 --- /dev/null +++ b/host/src/simtrace2-tool.c @@ -0,0 +1,361 @@ +/* simtrace2-tool - main program for the host PC to provide a remote SIM + * using the SIMtrace 2 firmware in card emulation mode + * + * (C) 2019 by Harald Welte <hwelte@hmw-consulting.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <errno.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <signal.h> +#define _GNU_SOURCE +#include <getopt.h> + +#include <sys/types.h> + +#include <libusb.h> + +#include <osmocom/usb/libusb.h> +#include <osmocom/simtrace2/simtrace2_api.h> +#include <osmocom/simtrace2/simtrace_prot.h> +#include <osmocom/simtrace2/gsmtap.h> + +#include <osmocom/core/utils.h> +#include <osmocom/core/msgb.h> +#include <osmocom/core/logging.h> +#include <osmocom/core/application.h> + +/*********************************************************************** + * Incoming Messages + ***********************************************************************/ + +static void print_welcome(void) +{ + printf("simtrace2-tool\n" + "(C) 2019 Harald Welte <laforge@gnumonks.org>\n"); +} + +static void print_help(void) +{ + printf( "simtrace2-tool [OPTIONS] COMMAND\n\n"); + printf( "Options:\n" + "\t-h\t--help\n" + "\t-V\t--usb-vendor\tVENDOR_ID\n" + "\t-P\t--usb-product\tPRODUCT_ID\n" + "\t-C\t--usb-config\tCONFIG_ID\n" + "\t-I\t--usb-interface\tINTERFACE_ID\n" + "\t-S\t--usb-altsetting ALTSETTING_ID\n" + "\t-A\t--usb-address\tADDRESS\n" + "\t-H\t--usb-path\tPATH\n" + "\n" + ); + printf( "Commands:\n" + "\tmodem reset (enable|disable|cycle)\n" + "\tmodem sim-switch (local|remote)\n" + "\tmodem sim-card (insert|remove)\n" + "\n"); +} + +static const struct option opts[] = { + { "help", 0, 0, 'h' }, + { "usb-vendor", 1, 0, 'V' }, + { "usb-product", 1, 0, 'P' }, + { "usb-config", 1, 0, 'C' }, + { "usb-interface", 1, 0, 'I' }, + { "usb-altsetting", 1, 0, 'S' }, + { "usb-address", 1, 0, 'A' }, + { "usb-path", 1, 0, 'H' }, + { NULL, 0, 0, 0 } +}; + +static void run_mainloop(struct osmo_st2_cardem_inst *ci) +{ + struct osmo_st2_transport *transp = ci->slot->transp; + uint8_t buf[16*265]; + int xfer_len; + int rc; + + while (1) { + /* read data from SIMtrace2 device */ + rc = libusb_bulk_transfer(transp->usb_devh, transp->usb_ep.in, + buf, sizeof(buf), &xfer_len, 100); + if (rc < 0 && rc != LIBUSB_ERROR_TIMEOUT && + rc != LIBUSB_ERROR_INTERRUPTED && + rc != LIBUSB_ERROR_IO) { + fprintf(stderr, "BULK IN transfer error; rc=%d\n", rc); + return; + } + /* break the loop if no new messages arrive within 100ms */ + if (rc == LIBUSB_ERROR_TIMEOUT) + return; + } +} + +static struct osmo_st2_transport _transp; + +static struct osmo_st2_slot _slot = { + .transp = &_transp, + .slot_nr = 0, +}; + +struct osmo_st2_cardem_inst _ci = { + .slot = &_slot, +}; + +struct osmo_st2_cardem_inst *ci = &_ci; + +/* perform a modem reset */ +static int do_modem_reset(int argc, char **argv) +{ + char *command; + if (argc < 1) + command = "cycle"; + else { + command = argv[0]; + argc--; + argv++; + } + + if (!strcmp(command, "enable")) { + printf("Activating Modem RESET\n"); + return osmo_st2_modem_reset_active(ci->slot); + } else if (!strcmp(command, "disable")) { + printf("Deactivating Modem RESET\n"); + return osmo_st2_modem_reset_inactive(ci->slot); + } else if (!strcmp(command, "cycle")) { + printf("Pulsing Modem RESET (1s)\n"); + return osmo_st2_modem_reset_pulse(ci->slot, 1000); + } else { + fprintf(stderr, "Unsupported modem reset command: '%s'\n", command); + return -EINVAL; + } + return 0; +} + +/* switch between local and remote (emulated) SIM */ +static int do_modem_sim_switch(int argc, char **argv) +{ + char *command; + if (argc < 1) + return -EINVAL; + command = argv[0]; + argc--; + argv++; + + if (!strcmp(command, "local")) { + printf("Setting SIM=LOCAL; Modem reset recommended\n"); + return osmo_st2_modem_sim_select_local(ci->slot); + } else if (!strcmp(command, "remote")) { + printf("Setting SIM=REMOTE; Modem reset recommended\n"); + return osmo_st2_modem_sim_select_remote(ci->slot); + } else { + fprintf(stderr, "Unsupported modem sim-switch command: '%s'\n", command); + return -EINVAL; + } + return 0; +} + +/* emulate SIM card insertion / removal from modem */ +static int do_modem_sim_card(int argc, char **argv) +{ + char *command; + if (argc < 1) + return -EINVAL; + command = argv[0]; + argc--; + argv++; + + if (!strcmp(command, "insert")) { + printf("Setting SIM=INSERTED; Modem reset recommended\n"); + return osmo_st2_cardem_request_card_insert(ci, 1); + } else if (!strcmp(command, "remove")) { + printf("Setting SIM=REMOVED; Modem reset recommended\n"); + return osmo_st2_cardem_request_card_insert(ci, 0); + } else { + fprintf(stderr, "Unsupported modem sim-card command: '%s'\n", command); + return -EINVAL; + } + return 0; +} + +static int do_subsys_modem(int argc, char **argv) +{ + char *command; + int rc; + + if (argc < 1) + return -EINVAL; + command = argv[0]; + argc--; + argv++; + + if (!strcmp(command, "reset")) { + rc = do_modem_reset(argc, argv); + } else if (!strcmp(command, "sim-switch")) { + rc = do_modem_sim_switch(argc, argv); + } else if (!strcmp(command, "sim-card")) { + rc = do_modem_sim_card(argc, argv); + } else { + fprintf(stderr, "Unsupported command for subsystem modem: '%s'\n", command); + return -EINVAL; + } + + return rc; +} + +static int do_command(int argc, char **argv) +{ + char *subsys; + int rc; + + if (argc < 1) + return -EINVAL; + subsys = argv[0]; + argc--; + argv++; + + if (!strcmp(subsys, "modem")) + rc = do_subsys_modem(argc, argv); + else { + fprintf(stderr, "Unsupported subsystem '%s'\n", subsys); + rc = -EINVAL; + } + + return rc; +} + +static struct log_info log_info = {}; + +int main(int argc, char **argv) +{ + struct osmo_st2_transport *transp = ci->slot->transp; + int rc; + int c, ret = 1; + int if_num = 0, vendor_id = -1, product_id = -1; + int config_id = -1, altsetting = 0, addr = -1; + char *path = NULL; + + while (1) { + int option_index = 0; + + c = getopt_long(argc, argv, "hV:P:C:I:S:A:H:", opts, &option_index); + if (c == -1) + break; + switch (c) { + case 'h': + print_help(); + exit(0); + break; + case 'V': + vendor_id = strtol(optarg, NULL, 16); + break; + case 'P': + product_id = strtol(optarg, NULL, 16); + break; + case 'C': + config_id = atoi(optarg); + break; + case 'I': + if_num = atoi(optarg); + break; + case 'S': + altsetting = atoi(optarg); + break; + case 'A': + addr = atoi(optarg); + break; + case 'H': + path = optarg; + break; + } + } + + if (vendor_id < 0 || product_id < 0) { + fprintf(stderr, "You have to specify the vendor and product ID\n"); + goto do_exit; + } + + transp->udp_fd = -1; + + print_welcome(); + + osmo_init_logging2(NULL, &log_info); + + rc = osmo_libusb_init(NULL); + if (rc < 0) { + fprintf(stderr, "libusb initialization failed\n"); + goto do_exit; + } + + do { + if (transp->udp_fd < 0) { + struct usb_interface_match _ifm, *ifm = &_ifm; + memset(ifm, 0, sizeof(*ifm)); + ifm->vendor = vendor_id; + ifm->product = product_id; + ifm->configuration = config_id; + ifm->interface = if_num; + ifm->altsetting = altsetting; + if (addr > 0 && addr < 256) + ifm->addr = addr; + if (path) + osmo_strlcpy(ifm->path, path, sizeof(ifm->path)); + transp->usb_devh = osmo_libusb_open_claim_interface(NULL, NULL, ifm); + if (!transp->usb_devh) { + fprintf(stderr, "can't open USB device: %s\n", strerror(errno)); + goto close_exit; + } + + rc = osmo_libusb_get_ep_addrs(transp->usb_devh, if_num, &transp->usb_ep.out, + &transp->usb_ep.in, &transp->usb_ep.irq_in); + if (rc < 0) { + fprintf(stderr, "can't obtain EP addrs; rc=%d\n", rc); + goto close_exit; + } + } + + if (argc - optind <= 0) { + fprintf(stderr, "You have to specify a command to execute\n"); + exit(1); + } + + rc = do_command(argc-optind, argv+optind); + switch (rc) { + case 0: + break; + case -EINVAL: + fprintf(stderr, "Error: Invalid command/syntax\n"); + exit(1); + break; + default: + fprintf(stderr, "Error executing command: %d\n", rc); + exit(1); + break; + } + + run_mainloop(ci); + ret = 0; + + libusb_release_interface(transp->usb_devh, 0); +close_exit: + if (transp->usb_devh) + libusb_close(transp->usb_devh); + } while (0); + + osmo_libusb_exit(NULL); +do_exit: + return ret; +} diff --git a/host/simtrace2_usb.c b/host/src/simtrace2_usb.c index 1e3104a..b329ead 100644 --- a/host/simtrace2_usb.c +++ b/host/src/simtrace2_usb.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include <stdio.h> #include <stdint.h> @@ -22,25 +18,21 @@ #include <errno.h> #include <osmocom/core/utils.h> +#include <osmocom/core/logging.h> +#include <osmocom/core/application.h> -#include "libusb_util.h" -#include "simtrace_usb.h" - -static const struct dev_id compatible_dev_ids[] = { - { USB_VENDOR_OPENMOKO, USB_PRODUCT_OWHW_SAM3 }, - { USB_VENDOR_OPENMOKO, USB_PRODUCT_QMOD_SAM3 }, - { USB_VENDOR_OPENMOKO, USB_PRODUCT_SIMTRACE2 }, - { 0, 0 } -}; +#include <osmocom/usb/libusb.h> +#include <osmocom/simtrace2/simtrace_usb.h> +#include <osmocom/simtrace2/usb_util.h> static int find_devices(void) { struct usb_interface_match ifm[16]; int rc, i, num_interfaces; - /* scan for USB devices matching SIMtrace USB ID with proprietary class */ - rc = usb_match_interfaces(NULL, compatible_dev_ids, - USB_CLASS_PROPRIETARY, -1, -1, ifm, ARRAY_SIZE(ifm)); + /* scan for USB devices matching SIMtrace USB ID with proprietary class */ + rc = osmo_libusb_find_matching_interfaces(NULL, osmo_st2_compatible_dev_ids, + USB_CLASS_PROPRIETARY, -1, -1, ifm, ARRAY_SIZE(ifm)); printf("USB matches: %d\n", rc); if (rc < 0) return rc; @@ -81,9 +73,12 @@ static int find_devices(void) return num_interfaces; } +static struct log_info log_info = {}; + int main(int argc, char **argv) { - libusb_init(NULL); + osmo_init_logging2(NULL, &log_info); + OSMO_ASSERT(osmo_libusb_init(NULL) == 0); find_devices(); return 0; } diff --git a/host/usb2udp.c b/host/usb2udp.c deleted file mode 100644 index 97ffad0..0000000 --- a/host/usb2udp.c +++ /dev/null @@ -1,286 +0,0 @@ -/* simtrace - main program for the host PC - * - * (C) 2010-2016 by Harald Welte <hwelte@hmw-consulting.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include <errno.h> -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdint.h> -#include <time.h> -#define _GNU_SOURCE -#include <getopt.h> -#include <poll.h> - -#include <sys/time.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> - -#include <libusb.h> - -#include "simtrace_usb.h" -#include "simtrace_prot.h" -#include "apdu_dispatch.h" -#include "simtrace2-discovery.h" - -#include <osmocom/core/utils.h> -#include <osmocom/core/socket.h> -#include <osmocom/core/select.h> - -struct libusb_device_handle *g_devh; -static struct sockaddr_in g_sa_remote; -static struct osmo_fd g_udp_ofd; - -static void print_welcome(void) -{ - printf("usb2udp - UDP/IP forwarding of SIMtrace card emulation\n" - "(C) 2016 by Harald Welte <laforge@gnumonks.org>\n\n"); -} - -static void print_help(void) -{ - printf( "\t-h\t--help\n" - "\t-i\t--interface <0-255>\n" - "\n" - ); -} - -struct ep_buf { - uint8_t ep; - uint8_t buf[1024]; - struct libusb_transfer *xfer; -}; -static struct ep_buf g_buf_in; -static struct ep_buf g_buf_out; - -static void usb_in_xfer_cb(struct libusb_transfer *xfer) -{ - int rc; - - printf("xfer_cb(ep=%02x): status=%d, flags=0x%x, type=%u, len=%u, act_len=%u\n", - xfer->endpoint, xfer->status, xfer->flags, xfer->type, xfer->length, xfer->actual_length); - switch (xfer->status) { - case LIBUSB_TRANSFER_COMPLETED: - if (xfer->endpoint == g_buf_in.ep) { - /* process the data */ - printf("read %d bytes from SIMTRACE, forwarding to UDP\n", xfer->actual_length); - rc = sendto(g_udp_ofd.fd, xfer->buffer, xfer->actual_length, 0, (struct sockaddr *)&g_sa_remote, sizeof(g_sa_remote)); - if (rc <= 0) { - fprintf(stderr, "error writing to UDP\n"); - } - /* and re-submit the URB */ - libusb_submit_transfer(xfer); - } else if (xfer->endpoint == g_buf_out.ep) { - /* re-enable reading from the UDP side */ - g_udp_ofd.when |= BSC_FD_READ; - } - break; - default: - fprintf(stderr, "xfer_cb(ERROR '%s')\n", osmo_hexdump_nospc(xfer->buffer, xfer->actual_length)); - break; - } -} - -static void init_ep_buf(struct ep_buf *epb) -{ - if (!epb->xfer) - epb->xfer = libusb_alloc_transfer(0); - - epb->xfer->flags = 0; - - libusb_fill_bulk_transfer(epb->xfer, g_devh, epb->ep, epb->buf, sizeof(epb->buf), usb_in_xfer_cb, NULL, 0); -} - -/*********************************************************************** - * libosmocore main loop integration of libusb async I/O - ***********************************************************************/ - -static int g_libusb_pending = 0; - -static int ofd_libusb_cb(struct osmo_fd *ofd, unsigned int what) -{ - /* FIXME */ - g_libusb_pending = 1; - - return 0; -} - -/* call-back when libusb adds a FD */ -static void libusb_fd_added_cb(int fd, short events, void *user_data) -{ - struct osmo_fd *ofd = talloc_zero(NULL, struct osmo_fd); - - printf("%s(%u, %x)\n", __func__, fd, events); - - ofd->fd = fd; - ofd->cb = &ofd_libusb_cb; - if (events & POLLIN) - ofd->when |= BSC_FD_READ; - if (events & POLLOUT) - ofd->when |= BSC_FD_WRITE; - - osmo_fd_register(ofd); -} - -/* call-back when libusb removes a FD */ -static void libusb_fd_removed_cb(int fd, void *user_data) -{ - - printf("%s(%u)\n", __func__, fd); -#if 0 - struct osmo_fd *ofd; - /* FIXME: This needs new export in libosmocore! */ - ofd = osmo_fd_get_by_fd(fd); - - if (ofd) { - osmo_fd_unregister(ofd); - talloc_free(ofd); - } -#endif -} - -/* call-back when the UDP socket is readable */ -static int ofd_udp_cb(struct osmo_fd *ofd, unsigned int what) -{ - int rc; - socklen_t addrlen = sizeof(g_sa_remote); - - rc = recvfrom(ofd->fd, g_buf_out.buf, sizeof(g_buf_out.buf), 0, - (struct sockaddr *)&g_sa_remote, &addrlen); - if (rc <= 0) { - fprintf(stderr, "error reading from UDP\n"); - return 0; - } - printf("read %d bytes from UDP, forwarding to SIMTRACE\n", rc); - g_buf_out.xfer->length = rc; - - /* disable further READ interest for the UDP socket */ - ofd->when &= ~BSC_FD_READ; - - /* submit the URB on the OUT end point */ - libusb_submit_transfer(g_buf_out.xfer); - - return 0; -} - -static void run_mainloop(void) -{ - int rc; - - printf("Entering main loop\n"); - - while (1) { - osmo_select_main(0); - if (g_libusb_pending) { - struct timeval tv; - memset(&tv, 0, sizeof(tv)); - rc = libusb_handle_events_timeout_completed(NULL, &tv, NULL); - if (rc != 0) { - fprintf(stderr, "handle_events_timeout_completed == %d\n", rc); - break; - } - } - } -} - -int main(int argc, char **argv) -{ - int rc; - int c, ret = 1; - int local_udp_port = 52342; - unsigned int if_num = 0; - - print_welcome(); - - while (1) { - int option_index = 0; - static const struct option opts[] = { - { "udp-port", 1, 0, 'u' }, - { "interface", 1, 0, 'I' }, - { "help", 0, 0, 'h' }, - { NULL, 0, 0, 0 } - }; - - c = getopt_long(argc, argv, "u:I:h", opts, &option_index); - if (c == -1) - break; - switch (c) { - case 'u': - local_udp_port = atoi(optarg); - break; - case 'I': - if_num = atoi(optarg); - break; - case 'h': - print_help(); - exit(0); - break; - } - } - - rc = libusb_init(NULL); - if (rc < 0) { - fprintf(stderr, "libusb initialization failed\n"); - goto close_exit; - } - - libusb_set_pollfd_notifiers(NULL, &libusb_fd_added_cb, &libusb_fd_removed_cb, NULL); - - g_devh = libusb_open_device_with_vid_pid(NULL, USB_VENDOR_OPENMOKO, USB_PRODUCT_OWHW_SAM3); - if (!g_devh) { - fprintf(stderr, "can't open USB device\n"); - goto close_exit; - } - - rc = libusb_claim_interface(g_devh, if_num); - if (rc < 0) { - fprintf(stderr, "can't claim interface %u; rc=%d\n", if_num, rc); - goto close_exit; - } - - /* open UDP socket, register with select handling and mark it - * readable */ - g_udp_ofd.cb = ofd_udp_cb; - osmo_sock_init_ofd(&g_udp_ofd, AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, local_udp_port + if_num, OSMO_SOCK_F_BIND); - - rc = get_usb_ep_addrs(g_devh, if_num, &g_buf_out.ep, &g_buf_in.ep, NULL); - if (rc < 0) { - fprintf(stderr, "couldn't find enpdoint addresses; rc=%d\n", rc); - goto close_exit; - } - /* initialize USB buffers / transfers */ - init_ep_buf(&g_buf_out); - init_ep_buf(&g_buf_in); - - /* submit the first transfer for the IN endpoint */ - libusb_submit_transfer(g_buf_in.xfer); - - run_mainloop(); - - ret = 0; - - libusb_release_interface(g_devh, 0); -close_exit: - if (g_devh) - libusb_close(g_devh); - - libusb_exit(NULL); - return ret; -} |