Adicionar primeiro

This commit is contained in:
2025-06-06 21:17:25 +01:00
parent c188084ba4
commit 282e7f517b
841 changed files with 199592 additions and 1 deletions

View File

@@ -0,0 +1,493 @@
# 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: 160
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_integrity_vec'
- '__bio_for_each_segment'
- 'bio_for_each_segment'
- 'bio_for_each_segment_all'
- 'bio_list_for_each'
- 'bip_for_each_vec'
- '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'
- '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_connector_for_each_possible_encoder'
- 'drm_for_each_connector_iter'
- 'drm_for_each_crtc'
- '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_active_drhd_unit'
- 'for_each_active_iommu'
- 'for_each_available_child_of_node'
- 'for_each_bio'
- 'for_each_board_func_rsrc'
- 'for_each_bvec'
- 'for_each_card_components'
- 'for_each_card_links'
- 'for_each_card_links_safe'
- 'for_each_card_prelinks'
- 'for_each_card_rtds'
- 'for_each_card_rtds_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_dev_addr'
- '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_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_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_lru'
- 'for_each_matching_node'
- 'for_each_matching_node_and_match'
- 'for_each_memblock'
- 'for_each_memblock_type'
- 'for_each_memcg_cache_index'
- 'for_each_mem_pfn_range'
- 'for_each_mem_range'
- 'for_each_mem_range_rev'
- 'for_each_migratetype_order'
- 'for_each_msi_entry'
- 'for_each_msi_entry_safe'
- 'for_each_net'
- 'for_each_netdev'
- 'for_each_netdev_continue'
- 'for_each_netdev_continue_rcu'
- '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_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_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_property_of_node'
- 'for_each_registered_fb'
- 'for_each_reserved_mem_region'
- 'for_each_rtd_codec_dai'
- 'for_each_rtd_codec_dai_rollback'
- 'for_each_rtdcom'
- 'for_each_rtdcom_safe'
- 'for_each_set_bit'
- 'for_each_set_bit_from'
- 'for_each_sg'
- 'for_each_sg_dma_page'
- 'for_each_sg_page'
- 'for_each_sibling_event'
- 'for_each_subelement'
- 'for_each_subelement_extid'
- 'for_each_subelement_id'
- '__for_each_thread'
- 'for_each_thread'
- '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_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_ul'
- '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'
- 'kvm_for_each_memslot'
- 'kvm_for_each_vcpu'
- 'list_for_each'
- 'list_for_each_codec'
- 'list_for_each_codec_safe'
- '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_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'
- 'media_device_for_each_entity'
- 'media_device_for_each_intf'
- 'media_device_for_each_link'
- 'media_device_for_each_pad'
- 'mp_bvec_for_each_page'
- 'mp_bvec_for_each_segment'
- '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'
- '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'
- 'rbtree_postorder_for_each_entry_safe'
- 'rdma_for_each_port'
- '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_from'
- '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_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'
- 'xa_for_each'
- 'xa_for_each_marked'
- 'xa_for_each_start'
- 'xas_for_each'
- 'xas_for_each_conflict'
- 'xas_for_each_marked'
- 'zorro_for_each_dev'
#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: Inner
#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: Never
...

17
components/api/lib/cAT/.gitignore vendored Executable file
View File

@@ -0,0 +1,17 @@
.vscode
lib
bin
dist
build
CMakeLists.txt.user
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_deps

View File

@@ -0,0 +1,11 @@
language: c
compiler:
- gcc
before_script:
- mkdir build
- cd build
- cmake ..
script: make && make test

View File

@@ -0,0 +1,148 @@
cmake_minimum_required( VERSION 3.0 )
project( libcat LANGUAGES C )
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
enable_testing( )
include_directories( ${PROJECT_SOURCE_DIR}/src )
file( GLOB SRC_FILES src/*.c )
add_library( cat SHARED ${SRC_FILES} )
set_target_properties( cat PROPERTIES VERSION 0.11.1 SOVERSION 1 )
target_compile_options( cat PRIVATE -Werror -Wall -Wextra -pedantic )
install( TARGETS cat DESTINATION lib )
install( FILES src/cat.h DESTINATION include/cat )
add_executable( demo example/demo.c )
target_link_libraries( demo cat )
add_executable( basic example/basic.c )
target_link_libraries( basic cat )
add_executable( unsolicited example/unsolicited.c )
target_link_libraries( unsolicited cat )
add_executable( test_parse tests/test_parse.c )
target_link_libraries( test_parse cat )
add_test( test_parse ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_parse )
add_executable( test_run tests/test_run.c )
target_link_libraries( test_run cat )
add_test( test_run ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_run )
add_executable( test_read tests/test_read.c )
target_link_libraries( test_read cat )
add_test( test_read ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_read )
add_executable( test_write tests/test_write.c )
target_link_libraries( test_write cat )
add_test( test_write ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_write )
add_executable( test_write_parse tests/test_write_parse.c )
target_link_libraries( test_write_parse cat )
add_test( test_write_parse ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_write_parse )
add_executable( test_write_int_range tests/test_write_int_range.c )
target_link_libraries( test_write_int_range cat )
add_test( test_write_int_range ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_write_int_range )
add_executable( test_write_uint_range tests/test_write_uint_range.c )
target_link_libraries( test_write_uint_range cat )
add_test( test_write_uint_range ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_write_uint_range )
add_executable( test_write_hex_range tests/test_write_hex_range.c )
target_link_libraries( test_write_hex_range cat )
add_test( test_write_hex_range ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_write_hex_range )
add_executable( test_write_hex_buffer tests/test_write_hex_buffer.c )
target_link_libraries( test_write_hex_buffer cat )
add_test( test_write_hex_buffer ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_write_hex_buffer )
add_executable( test_write_string_buffer tests/test_write_string_buffer.c )
target_link_libraries( test_write_string_buffer cat )
add_test( test_write_string_buffer ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_write_string_buffer )
add_executable( test_read_args tests/test_read_args.c )
target_link_libraries( test_read_args cat )
add_test( test_read_args ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_read_args )
add_executable( test_test tests/test_test.c )
target_link_libraries( test_test cat )
add_test( test_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_test )
add_executable( test_test_args tests/test_test_args.c )
target_link_libraries( test_test_args cat )
add_test( test_test_args ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_test_args )
add_executable( test_mutex tests/test_mutex.c )
target_link_libraries( test_mutex cat )
add_test( test_mutex ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_mutex )
add_executable( test_unsolicited_read tests/test_unsolicited_read.c )
target_link_libraries( test_unsolicited_read cat )
add_test( test_unsolicited_read ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_unsolicited_read )
add_executable( test_unsolicited_read_stress tests/test_unsolicited_read_stress.c )
target_link_libraries( test_unsolicited_read_stress cat )
add_test( test_unsolicited_read_stress ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_unsolicited_read_stress )
add_executable( test_unsolicited_read_buffer tests/test_unsolicited_read_buffer.c ${SRC_FILES})
set_target_properties( test_unsolicited_read_buffer PROPERTIES COMPILE_DEFINITIONS "CAT_UNSOLICITED_CMD_BUFFER_SIZE=2" )
add_test( test_unsolicited_read_buffer ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_unsolicited_read_buffer )
add_executable( test_hold_state tests/test_hold_state.c )
target_link_libraries( test_hold_state cat )
add_test( test_hold_state ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_hold_state )
add_executable( test_return_read tests/test_return_read.c )
target_link_libraries( test_return_read cat )
add_test( test_return_read ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_return_read )
add_executable( test_return_write tests/test_return_write.c )
target_link_libraries( test_return_write cat )
add_test( test_return_write ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_return_write )
add_executable( test_unsolicited_test tests/test_unsolicited_test.c )
target_link_libraries( test_unsolicited_test cat )
add_test( test_unsolicited_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_unsolicited_test )
add_executable( test_return_test tests/test_return_test.c )
target_link_libraries( test_return_test cat )
add_test( test_return_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_return_test )
add_executable( test_return_run tests/test_return_run.c )
target_link_libraries( test_return_run cat )
add_test( test_return_run ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_return_run )
add_executable( test_test_only tests/test_test_only.c )
target_link_libraries( test_test_only cat )
add_test( test_test_only ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_test_only )
add_executable( test_search_cmd tests/test_search_cmd.c )
target_link_libraries( test_search_cmd cat )
add_test( test_search_cmd ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_search_cmd )
add_executable( test_order tests/test_order.c )
target_link_libraries( test_order cat )
add_test( test_order ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_order )
add_executable( test_cmd_list tests/test_cmd_list.c )
target_link_libraries( test_cmd_list cat )
add_test( test_cmd_list ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_cmd_list )
add_executable( test_var_access tests/test_var_access.c )
target_link_libraries( test_var_access cat )
add_test( test_var_access ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_var_access )
add_executable( test_shortcuts tests/test_shortcuts.c )
target_link_libraries( test_shortcuts cat )
add_test( test_shortcuts ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/test_shortcuts )
add_custom_target( check COMMAND ${CMAKE_CTEST_COMMAND} --verbose )
add_custom_target( cleanall COMMAND rm -rf Makefile CMakeCache.txt CMakeFiles/ bin/ lib/ cmake_install.cmake CTestTestfile.cmake Testing/ )
add_custom_target( uninstall COMMAND xargs rm < install_manifest.txt )

21
components/api/lib/cAT/LICENSE Executable file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

211
components/api/lib/cAT/README.md Executable file
View File

@@ -0,0 +1,211 @@
[![Build Status](https://travis-ci.org/marcinbor85/cat.svg?branch=master)](https://travis-ci.org/marcinbor85/cat)
# libcat (cAT)
Plain C library for parsing AT commands for use in host devices.
## Features
* blazing fast, non-blocking, robust implementation
* 100% static implementation (without any dynamic memory allocation)
* very small footprint (both RAM and ROM)
* support for READ, WRITE, TEST and RUN type commands
* commands shortcuts (auto select best command candidate)
* single request - multiple responses
* unsolicited read/test command support
* hold state for delayed responses for time-consuming tasks
* high-level memory variables mapping arguments parsing
* variables accessors (read and write, read only, write only)
* automatic arguments types validating
* automatic format test responses for commands with variables
* CRLF and LF compatible
* case-insensitive
* dedicated for embedded systems
* object-oriented architecture
* separated interface for low-level layer
* fully asynchronous input/output operations
* multiplatform and portable
* asynchronous api with event callbacks
* print registered commands list feature
* only two source files
* wide unit tests
## Build
Build and install:
```sh
cmake .
make
make test
sudo make install
```
## Example basic demo posibilities
```console
AT+PRINT=? # TEST command
+PRINT=<X:UINT8[RW]>,<Y:UINT8[RW]>,<MESSAGE:STRING[RW]> # Automatic response
Printing something special at (X,Y). # Automatic response
OK # Automatic acknowledge
AT+PRINT? # READ command
+PRINT=0,0,"" # Automatic response
OK # Automatic acknowledge
AT+PRINT=xyz,-2 # WRITE command
ERROR # Automatic acknowledge
AT+PRINT=1,2,"test" # WRITE command
OK # Automatic acknowledge
AT+PRINT # RUN command
some printing at (1,2) with text "test" # Manual response
OK # Automatic acknowledge
```
## Example unsolicited demo posibilities
```console
AT+START=? # TEST command
+START=<MODE:UINT32[WO]> # Automatic response
Start scanning after write (0 - wifi, 1 - bluetooth). # Automatic response
OK # Automatic acknowledge
AT+START=0 # WRITE command
+SCAN=-10,"wifi1" # Unsolicited read response
+SCAN=-50,"wifi2" # Unsolicited read response
+SCAN=-20,"wifi3" # Unsolicited read response
OK # Unsolicited acknowledge
AT+START=1 # WRITE command
+SCAN=-20,"bluetooth1" # Unsolicited read response
OK # Unsolicited acknowledge
AT+SCAN=? # TEST command
+SCAN=<RSSI:INT32[RO]>,<SSID:STRING[RO]> # Automatic response
Scan result record. # Automatic response
OK # Automatic acknowledge
```
## Usage
Define High-Level variables:
```c
static uint8_t x;
static uint8_t y;
static char msg[32];
static struct cat_variable go_vars[] = {
{
.type = CAT_VAR_UINT_DEC, /* unsigned int variable */
.data = &x,
.data_size = sizeof(x),
.write = x_write,
.name = "X",
.access = CAT_VAR_ACCESS_READ_WRITE,
},
{
.type = CAT_VAR_UINT_DEC, /* unsigned int variable */
.data = &y,
.data_size = sizeof(y),
.write = y_write,
.access = CAT_VAR_ACCESS_READ_WRITE,
},
{
.type = CAT_VAR_BUF_STRING, /* string variable */
.data = msg,
.data_size = sizeof(msg),
.write = msg_write,
.access = CAT_VAR_ACCESS_READ_WRITE,
}
};
```
Define AT commands descriptor:
```c
static struct cat_command cmds[] = {
{
.name = "TEST",
.read = test_read, /* read handler for ATTEST? command */
.write = test_write, /* write handler for ATTEST={val} command */
.run = test_run /* run handler for ATTEST command */
},
{
.name = "+NUM",
.write = num_write, /* write handler for AT+NUM={val} command */
.read = num_read /* read handler for AT+NUM? command */
},
{
.name = "+GO",
.write = go_write, /* write handler for AT+GO={x},{y},{msg} command */
.var = go_vars, /* attach variables to command */
.var_num = sizeof(go_vars) / sizeof(go_vars[0]),
.need_all_vars = true
},
{
.name = "RESTART",
.run = restart_run /* run handler for ATRESTART command */
}
};
```
Define AT command parser descriptor:
```c
static char working_buf[128]; /* working buffer, must be declared manually */
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = working_buf,
.buf_size = sizeof(working_buf),
};
```
Define IO low-level layer interface:
```c
static int write_char(char ch)
{
putc(ch, stdout);
return 1;
}
static int read_char(char *ch)
{
*ch = getch();
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
```
Initialize AT command parser and run:
```c
struct cat_object at; /* at command parser object */
cat_init(&at, &desc, &iface, NULL); /* initialize at command parser object */
while (1) {
cat_service(&at) /* periodically call at command parser service */
... /* other stuff, running in main loop */
}
```

View File

@@ -0,0 +1,70 @@
TODO:
- differentation of variables for read and write commands
- help command (printing all commands posibilities with descriptions)
- documentation updated (buffer sized, return enum types, write variable nums, buf size hints)
- helper setters and getters for variables
0.11.0
* optional context in commands and data_getter in variables
* optional extended read and write variable handler with parent command
0.10.1
* single working buffer insteads of two separated for atcmd and unsolicited events
0.10.0
* separate atcmd and unsolicited event state machines
0.9.0
* variables accessors
0.8.1
* fix commands shourtcuts
0.8.0
* print commands list feature
0.7.1
* more flexible command group initialization (pointers)
0.7.0
* function for checking unsolicited buffer
* some refactoring regarding unsolicited buffer
* helper function cat_search_variable_by_name added
* commands group with searching feature added
* disable feature for commands and groups added
0.6.0
* async non blocking io->write
* async unsolicited read/test event (injected at idle and hold state)
* hold commands parse processing feature (for delayed unsolicited read responses)
* behavior differentation by callbacks return values
* only-test flag in commands descriptor (for fast disable read/write/run)
* helper function for searching command by name
* multiple responses triggered by single request pattern support
* generic mutex descriptor interface
* return value states enum types
0.5.3
* function for checking internal busy state added
0.5.2
* small fix in auto description response
0.5.1
* description field in command added (used in auto help message)
0.5.0
* test command parser with auto help messages
* output string end-line encoding same as input string
* very basic demo example application added
0.4.0
* high level parsing for command arguments
* int, uint, hex, hexbuf, string argument types
* validating arguments values range
0.3.0
* independent buffers (parsing buffer and state buffer)
0.2.0
* passing command struct instead of command name in command handlers

View File

@@ -0,0 +1,161 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
/* variables assigned to print command */
static uint8_t x;
static uint8_t y;
static char message[16];
/* helper variable used to exit demo code */
static bool quit_flag;
/* run command handler with application dependent login print code */
static int print_run(const struct cat_command *cmd)
{
printf("some printing at (%d,%d) with text \"%s\"\n", x, y, message);
return 0;
}
/* run command handler attached to HELP command for printing commands list */
static int print_cmd_list(const struct cat_command *cmd)
{
return CAT_RETURN_STATE_PRINT_CMD_LIST_OK;
}
/* run command handler with custom exit mechanism */
static int quit_run(const struct cat_command *cmd)
{
quit_flag = true;
return 0;
}
/* declaring print variables array */
static struct cat_variable print_vars[] = {
{
.type = CAT_VAR_UINT_DEC,
.data = &x,
.data_size = sizeof(x),
.name = "X",
.access = CAT_VAR_ACCESS_READ_WRITE,
},
{
.type = CAT_VAR_UINT_DEC,
.data = &y,
.data_size = sizeof(y),
.name = "Y",
.access = CAT_VAR_ACCESS_READ_WRITE,
},
{
.type = CAT_VAR_BUF_STRING,
.data = message,
.data_size = sizeof(message),
.name = "MESSAGE",
.access = CAT_VAR_ACCESS_READ_WRITE,
}
};
/* declaring commands array */
static struct cat_command cmds[] = {
{
.name = "+PRINT",
.description = "Printing something special at (X,Y).",
.run = print_run,
.var = print_vars,
.var_num = sizeof(print_vars) / sizeof(print_vars[0]),
.need_all_vars = true
},
{
.name = "#HELP",
.run = print_cmd_list,
},
{
.name = "#QUIT",
.run = quit_run
},
};
/* working buffer */
static char buf[128];
/* declaring parser descriptor */
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf)
};
/* custom target dependent input output handlers */
static int write_char(char ch)
{
putc(ch, stdout);
return 1;
}
static int read_char(char *ch)
{
*ch = getc(stdin);
return 1;
}
/* declaring input output interface descriptor for parser */
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
int main(int argc, char **argv)
{
struct cat_object at;
/* initializing */
cat_init(&at, &desc, &iface, NULL);
/* main loop with exit code conditions */
while ((cat_service(&at) != 0) && (quit_flag == 0)) {};
/* goodbye message */
printf("Bye!\n");
return 0;
}

View File

@@ -0,0 +1,260 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static int32_t speed;
static uint16_t adr;
static uint8_t x;
static uint8_t y;
static uint8_t bytes_buf[4];
static char msg[16];
static bool quit_flag;
static int x_write(const struct cat_variable *var, size_t write_size)
{
printf("x variable updated internally to: %u\n", x);
return 0;
}
static int y_write(const struct cat_variable *var, size_t write_size)
{
printf("y variable updated internally to: %u\n", y);
return 0;
}
static int msg_write(const struct cat_variable *var, size_t write_size)
{
printf("msg variable updated %lu bytes internally to: <%s>\n", write_size, msg);
return 0;
}
static int speed_write(const struct cat_variable *var, size_t write_size)
{
printf("speed variable updated internally to: %d\n", speed);
return 0;
}
static int adr_write(const struct cat_variable *var, size_t write_size)
{
printf("adr variable updated internally to: 0x%04X\n", adr);
return 0;
}
static int bytesbuf_write(const struct cat_variable *var, size_t write_size)
{
int i = 0;
printf("bytes_buf variable updated %lu bytes internally to: ", write_size);
for (i = 0; i < sizeof(bytes_buf); i++)
printf("%02X", bytes_buf[i]);
printf("\n");
return 0;
}
static int go_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num)
{
int i = 0;
printf("<%s>: x=%d y=%d msg=%s @ speed=%d\n",
cmd->name,
*(uint8_t*)(cmd->var[0].data),
*(uint8_t*)(cmd->var[1].data),
msg,
speed
);
printf("<bytes>: ");
for (i = 0; i < sizeof(bytes_buf); i++)
printf("%02X", bytes_buf[i]);
printf("\n");
return 0;
}
static int set_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num)
{
printf("<%s>: SET SPEED TO = %d\n",
cmd->name,
speed
);
return 0;
}
static int set_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
return 0;
}
static int test_run(const struct cat_command *cmd)
{
printf("TEST: <%s>", cmd->name);
return 0;
}
static int quit_run(const struct cat_command *cmd)
{
printf("QUIT: <%s>", cmd->name);
quit_flag = true;
return 0;
}
static int print_cmd_list(const struct cat_command *cmd)
{
return CAT_RETURN_STATE_PRINT_CMD_LIST_OK;
}
static struct cat_variable go_vars[] = {
{
.type = CAT_VAR_UINT_DEC,
.data = &x,
.data_size = sizeof(x),
.write = x_write,
.name = "x"
},
{
.type = CAT_VAR_UINT_DEC,
.data = &y,
.data_size = sizeof(y),
.write = y_write,
.name = "y"
},
{
.type = CAT_VAR_BUF_STRING,
.data = msg,
.data_size = sizeof(msg),
.write = msg_write,
.name = "msg"
}
};
static struct cat_variable set_vars[] = {
{
.type = CAT_VAR_INT_DEC,
.data = &speed,
.data_size = sizeof(speed),
.write = speed_write,
.name = "speed"
},
{
.type = CAT_VAR_NUM_HEX,
.data = &adr,
.data_size = sizeof(adr),
.write = adr_write,
.name = "address"
},
{
.type = CAT_VAR_BUF_HEX,
.data = &bytes_buf,
.data_size = sizeof(bytes_buf),
.write = bytesbuf_write,
.name = "buffer"
}
};
static struct cat_command cmds[] = {
{
.name = "+GO",
.write = go_write,
.var = go_vars,
.var_num = sizeof(go_vars) / sizeof(go_vars[0]),
.need_all_vars = true
},
{
.name = "+SET",
.write = set_write,
.read = set_read,
.var = set_vars,
.var_num = sizeof(set_vars) / sizeof(set_vars[0]),
},
{
.name = "#TEST",
.run = test_run
},
{
.name = "#HELP",
.run = print_cmd_list,
},
{
.name = "#QUIT",
.run = quit_run
},
};
static char buf[128];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf)
};
static int write_char(char ch)
{
putc(ch, stdout);
return 1;
}
static int read_char(char *ch)
{
*ch = getc(stdin);
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
int main(int argc, char **argv)
{
struct cat_object at;
cat_init(&at, &desc, &iface, NULL);
while ((cat_service(&at) != 0) && (quit_flag == 0)) {};
printf("Bye!\n");
return 0;
}

View File

@@ -0,0 +1,251 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
/* variables assigned to scan command */
static int rssi;
static char ssid[16];
/* helper variable used to exit demo code */
static bool quit_flag;
/* variables assigned to start command */
static int mode;
/* main at command parser object */
struct cat_object at;
struct scan_results {
int rssi;
char ssid[16];
};
/* static const scan results */
static const struct scan_results results[2][3] = {
{
{
.rssi = -10,
.ssid = "wifi1",
},
{
.rssi = -50,
.ssid = "wifi2",
},
{
.rssi = -20,
.ssid = "wifi3",
}
},
{
{
.rssi = -20,
.ssid = "bluetooth1",
}
}
};
/* helper variable */
static int scan_index;
/* run command handler with custom exit mechanism */
static int quit_run(const struct cat_command *cmd)
{
quit_flag = true;
return 0;
}
/* helper function */
static void load_scan_results(int index)
{
rssi = results[mode][index].rssi;
strcpy(ssid, results[mode][index].ssid);
}
/* declaring scan variables array */
static struct cat_variable scan_vars[] = {
{
.type = CAT_VAR_INT_DEC,
.data = &rssi,
.data_size = sizeof(rssi),
.name = "RSSI"
},
{
.type = CAT_VAR_BUF_STRING,
.data = ssid,
.data_size = sizeof(ssid),
.name = "SSID"
}
};
/* forward declaration */
static cat_return_state scan_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size);
/* unsolicited command */
static struct cat_command scan_cmd = {
.name = "+SCAN",
.read = scan_read,
.var = scan_vars,
.var_num = sizeof(scan_vars) / sizeof(scan_vars[0])
};
/* unsolicited read callback handler */
static cat_return_state scan_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
int max = (mode == 0) ? 3 : 1;
scan_index++;
if (scan_index > max)
return CAT_RETURN_STATE_HOLD_EXIT_OK;
load_scan_results(scan_index);
cat_trigger_unsolicited_read(&at, &scan_cmd);
return CAT_RETURN_STATE_DATA_NEXT;
}
/* mode variable validator */
static int mode_write(const struct cat_variable *var, const size_t write_size)
{
if (*(int*)var->data >= 2)
return -1;
return 0;
}
/* start write callback handler */
static cat_return_state start_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num)
{
scan_index = 0;
load_scan_results(scan_index);
cat_trigger_unsolicited_read(&at, &scan_cmd);
return CAT_RETURN_STATE_HOLD;
}
/* run command handler attached to HELP command for printing commands list */
static int print_cmd_list(const struct cat_command *cmd)
{
return CAT_RETURN_STATE_PRINT_CMD_LIST_OK;
}
/* declaring start command variables array */
static struct cat_variable start_vars[] = {
{
.type = CAT_VAR_UINT_DEC,
.data = &mode,
.data_size = sizeof(mode),
.name = "MODE",
.write = mode_write,
.access = CAT_VAR_ACCESS_WRITE_ONLY,
}
};
/* declaring commands array */
static struct cat_command cmds[] = {
{
.name = "+START",
.description = "Start scanning after write (0 - wifi, 1 - bluetooth).",
.write = start_write,
.var = start_vars,
.var_num = sizeof(start_vars) / sizeof(start_vars[0]),
.need_all_vars = true
},
{
.name = "+SCAN",
.description = "Scan result record.",
.only_test = true,
.var = scan_vars,
.var_num = sizeof(scan_vars) / sizeof(scan_vars[0])
},
{
.name = "#HELP",
.run = print_cmd_list,
},
{
.name = "#QUIT",
.run = quit_run
},
};
/* working buffer */
static char buf[128];
/* declaring parser descriptor */
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf),
};
/* custom target dependent input output handlers */
static int write_char(char ch)
{
putc(ch, stdout);
return 1;
}
static int read_char(char *ch)
{
*ch = getc(stdin);
return 1;
}
/* declaring input output interface descriptor for parser */
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
int main(int argc, char **argv)
{
/* initializing */
cat_init(&at, &desc, &iface, NULL);
/* main loop with exit code conditions */
while ((cat_service(&at) != 0) && (quit_flag == 0)) {};
/* goodbye message */
printf("Bye!\n");
return 0;
}

2757
components/api/lib/cAT/src/cat.c Executable file

File diff suppressed because it is too large Load Diff

557
components/api/lib/cAT/src/cat.h Executable file
View File

@@ -0,0 +1,557 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef CAT_H
#define CAT_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
/* only forward declarations (looks for definition below) */
struct cat_command;
struct cat_variable;
#ifndef CAT_UNSOLICITED_CMD_BUFFER_SIZE
/* unsolicited command buffer default size (can by override externally during compilation) */
#define CAT_UNSOLICITED_CMD_BUFFER_SIZE ((size_t)(1))
#endif
/* enum type with variable type definitions */
typedef enum {
CAT_VAR_INT_DEC = 0, /* decimal encoded signed integer variable */
CAT_VAR_UINT_DEC, /* decimal encoded unsigned integer variable */
CAT_VAR_NUM_HEX, /* hexadecimal encoded unsigned integer variable */
CAT_VAR_BUF_HEX, /* asciihex encoded bytes array */
CAT_VAR_BUF_STRING /* string variable */
} cat_var_type;
/* enum type wirh variable accessors definitions */
typedef enum {
CAT_VAR_ACCESS_READ_WRITE = 0, /* there will be possible to read and write variable */
CAT_VAR_ACCESS_READ_ONLY, /* there will be possible to read only variable */
CAT_VAR_ACCESS_WRITE_ONLY, /* there will be possible to write only variable */
} cat_var_access;
/* enum type with function status */
typedef enum {
CAT_STATUS_ERROR_BUFFER_EMPTY = -7,
CAT_STATUS_ERROR_NOT_HOLD = -6,
CAT_STATUS_ERROR_BUFFER_FULL = -5,
CAT_STATUS_ERROR_UNKNOWN_STATE = -4,
CAT_STATUS_ERROR_MUTEX_LOCK = -3,
CAT_STATUS_ERROR_MUTEX_UNLOCK = -2,
CAT_STATUS_ERROR = -1,
CAT_STATUS_OK = 0,
CAT_STATUS_BUSY = 1,
CAT_STATUS_HOLD = 2
} cat_status;
/**
* Write variable function handler
*
* This callback function is called after variable update immediatly.
* User application can validate writed value and check for amount of data size was written.
* This handler is optional, so when is not defined, operations will be fully automatically.
*
* @param var - pointer to struct descriptor of parsed variable
* @param write_size - size of data was written (useful especially with hexbuf var type)
* @return 0 - ok, else error and stop parsing
* */
typedef int (*cat_var_write_handler)(const struct cat_variable *var, const size_t write_size);
/**
* Read variable function handler
*
* This callback function is called just before variable value read.
* User application can copy data from private fields to variable connected with parsed command.
* This handler is optional, so when is not defined, operations will be fully automatically.
*
* @param var - pointer to struct descriptor of parsed variable
* @return 0 - ok, else error and stop parsing
* */
typedef int (*cat_var_read_handler)(const struct cat_variable *var);
/**
* Write variable extended function handler
*
* This callback function is called after variable update immediatly.
* User application can validate writed value and check for amount of data size was written.
* This handler is optional, so when is not defined, operations will be fully automatically.
*
* @param var - pointer to struct descriptor of parsed variable
* @param cmd - pointer to variable parent command structure
* @param write_size - size of data was written (useful especially with hexbuf var type)
* @return 0 - ok, else error and stop parsing
* */
typedef int (*cat_var_write_ex_handler)(const struct cat_variable *var, const struct cat_command *cmd, const size_t write_size);
/**
* Read variable function handler
*
* This callback function is called just before variable value read.
* User application can copy data from private fields to variable connected with parsed command.
* This handler is optional, so when is not defined, operations will be fully automatically.
*
* @param var - pointer to struct descriptor of parsed variable
* @param cmd - pointer to variable parent command structure
* @return 0 - ok, else error and stop parsing
* */
typedef int (*cat_var_read_ex_handler)(const struct cat_variable *var, const struct cat_command *cmd);
/**
* Data getter for variable.
* The purpose of this function is to replace statically allocated data and data_size fields
* with function pointer with context. Then the data and data_size from this getter would be
* changed and returned runtime.
*
* @param var - pointer to struct descriptor of parsed variable
* @param context - command context
* @param size - pointer to variable where should be placed data size
* @return pointer to data array from context
*/
typedef void* (*cat_var_data_getter)(const struct cat_variable *var, void *context, size_t *data_size);
struct cat_variable {
const char *name; /* variable name (optional - using only for auto format test command response) */
cat_var_type type; /* variable type (needed for parsing and validating) */
void *data; /* generic pointer to statically allocated memory for variable data read/write/validate operations */
size_t data_size; /* variable data size, pointed by data pointer */
cat_var_access access; /* variable accessor */
cat_var_write_handler write; /* write variable handler */
cat_var_read_handler read; /* read variable handler */
cat_var_write_ex_handler write_ex; /* optional write variable extended handler */
cat_var_read_ex_handler read_ex; /* optional read variable extended handler */
cat_var_data_getter data_getter; /* optional data getter for dynamic linking data and data_size */
};
/* enum type with command callbacks return values meaning */
typedef enum {
CAT_RETURN_STATE_ERROR = -1, /* immediatly error acknowledge */
CAT_RETURN_STATE_DATA_OK, /* send current data buffer followed by ok acknowledge */
CAT_RETURN_STATE_DATA_NEXT, /* send current data buffer and go to next callback iteration */
CAT_RETURN_STATE_NEXT, /* go to next callback iteration without sending anything */
CAT_RETURN_STATE_OK, /* immediatly ok acknowledge */
CAT_RETURN_STATE_HOLD, /* enable hold parser state */
CAT_RETURN_STATE_HOLD_EXIT_OK, /* exit from hold state with OK response */
CAT_RETURN_STATE_HOLD_EXIT_ERROR, /* exit from hold state with ERROR response */
CAT_RETURN_STATE_PRINT_CMD_LIST_OK, /* print commands list followed by ok acknowledge (only in TEST and RUN) */
} cat_return_state;
/**
* Write command function handler (AT+CMD=)
*
* This callback function is called after parsing all connected variables.
* User application can validate all variales at once at this moment, or copy them to the other application layer buffer.
* User can check number of variables or make custom process of parsing non standard arguments format.
* This handler is optional, so when is not defined, operations on variables will be fully automatically.
* If neither write handler nor variables not defined, then write command type is not available.
*
* @param cmd - pointer to struct descriptor of processed command
* @param data - pointer to arguments buffer for custom parsing
* @param data_size - length of arguments buffer
* @param args_num - number of passed arguments connected to variables
* @return according to cat_return_state enum definitions
* */
typedef cat_return_state (*cat_cmd_write_handler)(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num);
/**
* Read command function handler (AT+CMD?)
*
* This callback function is called after format all connected variables.
* User application can change automatic response, or add some custom data to response.
* This handler is optional, so when is not defined, operations on variables will be fully automatically.
* If neither read handler nor variables not defined, then read command type is not available.
*
* @param cmd - pointer to struct descriptor of processed command
* @param data - pointer to arguments buffer for custom parsing
* @param data_size - pointer to length of arguments buffer (can be modifed if needed)
* @param max_data_size - maximum length of buffer pointed by data pointer
* @return according to cat_return_state enum definitions
* */
typedef cat_return_state (*cat_cmd_read_handler)(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size);
/**
* Run command function handler (AT+CMD)
*
* No operations on variables are done.
* This handler is optional.
* If run handler not defined, then run command type is not available.
*
* @param cmd - pointer to struct descriptor of processed command
* @return according to cat_return_state enum definitions
* */
typedef cat_return_state (*cat_cmd_run_handler)(const struct cat_command *cmd);
/**
* Test command function handler (AT+CMD=?)
*
* This callback function is called after format all connected variables.
* User application can change automatic response, or add some custom data to response.
* This handler is optional, so when is not defined, operations on variables will be fully automatically.
* If neither test handler nor variables not defined, then test command type is not available.
* Exception of this rule is write command without variables.
* In this case, the "question mark" will be passed as a custom argument to the write handler.
*
* @param cmd - pointer to struct descriptor of processed command
* @param data - pointer to arguments buffer for custom parsing
* @param data_size - pointer to length of arguments buffer (can be modifed if needed)
* @param max_data_size - maximum length of buffer pointed by data pointer
* @return according to cat_return_state enum definitions
* */
typedef cat_return_state (*cat_cmd_test_handler)(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size);
/* enum type with main at parser fsm state */
typedef enum {
CAT_STATE_ERROR = -1,
CAT_STATE_IDLE,
CAT_STATE_PARSE_PREFIX,
CAT_STATE_PARSE_COMMAND_CHAR,
CAT_STATE_UPDATE_COMMAND_STATE,
CAT_STATE_WAIT_READ_ACKNOWLEDGE,
CAT_STATE_SEARCH_COMMAND,
CAT_STATE_COMMAND_FOUND,
CAT_STATE_COMMAND_NOT_FOUND,
CAT_STATE_PARSE_COMMAND_ARGS,
CAT_STATE_PARSE_WRITE_ARGS,
CAT_STATE_FORMAT_READ_ARGS,
CAT_STATE_WAIT_TEST_ACKNOWLEDGE,
CAT_STATE_FORMAT_TEST_ARGS,
CAT_STATE_WRITE_LOOP,
CAT_STATE_READ_LOOP,
CAT_STATE_TEST_LOOP,
CAT_STATE_RUN_LOOP,
CAT_STATE_HOLD,
CAT_STATE_FLUSH_IO_WRITE_WAIT,
CAT_STATE_FLUSH_IO_WRITE,
CAT_STATE_AFTER_FLUSH_RESET,
CAT_STATE_AFTER_FLUSH_OK,
CAT_STATE_AFTER_FLUSH_FORMAT_READ_ARGS,
CAT_STATE_AFTER_FLUSH_FORMAT_TEST_ARGS,
CAT_STATE_PRINT_CMD,
} cat_state;
/* enum type with type of command request */
typedef enum {
CAT_CMD_TYPE_NONE = -1,
CAT_CMD_TYPE_RUN,
CAT_CMD_TYPE_READ,
CAT_CMD_TYPE_WRITE,
CAT_CMD_TYPE_TEST,
CAT_CMD_TYPE__TOTAL_NUM
} cat_cmd_type;
/* structure with io interface functions */
struct cat_io_interface {
int (*write)(char ch); /* write char to output stream. return 1 if byte wrote successfully. */
int (*read)(char *ch); /* read char from input stream. return 1 if byte read successfully. */
};
/* structure with mutex interface functions */
struct cat_mutex_interface {
int (*lock)(void); /* lock mutex handler. return 0 if successfully locked, otherwise - cannot lock */
int (*unlock)(void); /* unlock mutex handler. return 0 if successfully unlocked, otherwise - cannot unlock */
};
/* structure with at command descriptor */
struct cat_command {
const char *name; /* at command name (case-insensitivity) */
const char *description; /* at command description (optionally - can be null) */
cat_cmd_write_handler write; /* write command handler */
cat_cmd_read_handler read; /* read command handler */
cat_cmd_run_handler run; /* run command handler */
cat_cmd_test_handler test; /* test command handler */
struct cat_variable const *var; /* pointer to array of variables assiocated with this command */
size_t var_num; /* number of variables in array */
bool need_all_vars; /* flag to need all vars parsing */
bool only_test; /* flag to disable read/write/run commands (only test auto description) */
bool disable; /* flag to completely disable command */
void* context; /* pointer to optional context structure */
};
struct cat_command_group {
const char *name; /* command group name (optional, for identification purpose) */
struct cat_command const *cmd; /* pointer to array of commands descriptor */
size_t cmd_num; /* number of commands in array */
bool disable; /* flag to completely disable all commands in group */
};
/* structure with at command parser descriptor */
struct cat_descriptor {
struct cat_command_group* const *cmd_group; /* pointer to array of commands group descriptor */
size_t cmd_group_num; /* number of commands group in array */
uint8_t *buf; /* pointer to working buffer (used to parse command argument) */
size_t buf_size; /* working buffer length */
/* optional unsolicited buffer, if not configured (NULL) */
/* then the buf will be divided into two smaller buffers */
uint8_t *unsolicited_buf; /* pointer to unsolicited working buffer (used to parse command argument) */
size_t unsolicited_buf_size; /* unsolicited working buffer length */
};
/* strcuture with unsolicited command buffered infos */
struct cat_unsolicited_cmd {
struct cat_command const *cmd; /* pointer to commands used to unsolicited event */
cat_cmd_type type; /* type of unsolicited event */
};
/* enum type with unsolicited events fsm state */
typedef enum {
CAT_UNSOLICITED_STATE_IDLE,
CAT_UNSOLICITED_STATE_FORMAT_READ_ARGS,
CAT_UNSOLICITED_STATE_FORMAT_TEST_ARGS,
CAT_UNSOLICITED_STATE_READ_LOOP,
CAT_UNSOLICITED_STATE_TEST_LOOP,
CAT_UNSOLICITED_STATE_FLUSH_IO_WRITE_WAIT,
CAT_UNSOLICITED_STATE_FLUSH_IO_WRITE,
CAT_UNSOLICITED_STATE_AFTER_FLUSH_RESET,
CAT_UNSOLICITED_STATE_AFTER_FLUSH_OK,
CAT_UNSOLICITED_STATE_AFTER_FLUSH_FORMAT_READ_ARGS,
CAT_UNSOLICITED_STATE_AFTER_FLUSH_FORMAT_TEST_ARGS,
} cat_unsolicited_state;
/* enum type with fsm type */
typedef enum {
CAT_FSM_TYPE_ATCMD,
CAT_FSM_TYPE_UNSOLICITED,
CAT_FSM_TYPE__TOTAL_NUM,
} cat_fsm_type;
struct cat_unsolicited_fsm {
cat_unsolicited_state state; /* current unsolicited fsm state */
size_t index; /* index used to iterate over commands and variables */
size_t position; /* position of actually parsed char in arguments string */
struct cat_command const *cmd; /* pointer to current command descriptor */
struct cat_variable const *var; /* pointer to current variable descriptor */
cat_cmd_type cmd_type; /* type of command request */
char const *write_buf; /* working buffer pointer used for asynch writing to io */
int write_state; /* before, data, after flush io write state */
cat_unsolicited_state write_state_after; /* parser state to set after flush io write */
struct cat_unsolicited_cmd unsolicited_cmd_buffer[CAT_UNSOLICITED_CMD_BUFFER_SIZE]; /* buffer with unsolicited commands used to unsolicited event */
size_t unsolicited_cmd_buffer_tail; /* tail index of unsolicited cmd buffer */
size_t unsolicited_cmd_buffer_head; /* head index of unsolicited cmd buffer */
size_t unsolicited_cmd_buffer_items_count; /* number of unsolicited cmd in buffer */
};
/* structure with main at command parser object */
struct cat_object {
struct cat_descriptor const *desc; /* pointer to at command parser descriptor */
struct cat_io_interface const *io; /* pointer to at command parser io interface */
struct cat_mutex_interface const *mutex; /* pointer to at command parser mutex interface */
size_t index; /* index used to iterate over commands and variables */
size_t partial_cntr; /* partial match commands counter */
size_t length; /* length of input command name and command arguments */
size_t position; /* position of actually parsed char in arguments string */
size_t write_size; /* size of parsed buffer hex or buffer string */
size_t commands_num; /* computed total number of registered commands */
struct cat_command const *cmd; /* pointer to current command descriptor */
struct cat_variable const *var; /* pointer to current variable descriptor */
cat_cmd_type cmd_type; /* type of command request */
char current_char; /* current received char from input stream */
cat_state state; /* current fsm state */
bool cr_flag; /* flag for detect <cr> char in input string */
bool hold_state_flag; /* status of hold state (independent from fsm states) */
int hold_exit_status; /* hold exit parameter with status */
char const *write_buf; /* working buffer pointer used for asynch writing to io */
int write_state; /* before, data, after flush io write state */
cat_state write_state_after; /* parser state to set after flush io write */
struct cat_unsolicited_fsm unsolicited_fsm;
};
/**
* Function used to initialize at command parser.
* Initialize starting values of object fields.
*
* @param self pointer to at command parser object to initialize
* @param desc pointer to at command parser descriptor
* @param io pointer to at command parser io low-level layer interface
* @param mutex pointer to at command partes mutex interface
*/
void cat_init(struct cat_object *self, const struct cat_descriptor *desc, const struct cat_io_interface *io, const struct cat_mutex_interface *mutex);
/**
* Function must be called periodically to asynchronoulsy run at command parser.
* Commands handlers will be call from this function context.
*
* @param self pointer to at command parser object
* @return according to cat_return_state enum definitions
*/
cat_status cat_service(struct cat_object *self);
/**
* Function return flag which indicating internal busy state.
* It is used to determine whether external application modules can use shared input / output interfaces functions.
* It is usefull especially in rtos environments.
* If internal parser state is busy by doing some processing then function return 1.
* If the function returns 0, then the external application modules can safely use the input / output interfaces functions shared with the library.
* If the function returns 1, then input / output interface function are used by internal parser functions.
*
* @param self pointer to at command parser object
* @return according to cat_return_state enum definitions
*/
cat_status cat_is_busy(struct cat_object *self);
/**
* Function return flag which indicating parsing hold state.
* If the function returns 0, then the at parsing process is normal.
* If the function returns 1, then the at parsing process is holded.
* To exit from hold state, user have to call cat_hold_exit or return HOLD_EXIT return value in callback.
*
* @param self pointer to at command parser object
* @return according to cat_return_state enum definitions
*/
cat_status cat_is_hold(struct cat_object *self);
/**
* Function return flag which indicating state of internal buffer of unsolicited events.
*
* @param self pointer to at command parser object
* @return CAT_STATUS_OK - buffer is not full, unsolicited event can be buffered
* CAT_STATUS_ERROR_BUFFER_FULL - buffer is full, unsolicited event cannot be buffered
* CAT_STATUS_ERROR_MUTEX_LOCK - cannot lock mutex error
* CAT_STATUS_ERROR_MUTEX_UNLOCK - cannot unlock mutex error
*/
cat_status cat_is_unsolicited_buffer_full(struct cat_object *self);
/**
* Function sends unsolicited event message.
* Command message is buffered inside parser in 1-level deep buffer and processed in cat_service context.
* Only command pointer is buffered, so command struct should be static or global until be fully processed.
*
* @param self pointer to at command parser object
* @param cmd pointer to command structure regarding which unsolicited event applies to
* @param type type of operation (only CAT_CMD_TYPE_READ and CAT_CMD_TYPE_TEST are allowed)
* @return according to cat_return_state enum definitions
*/
cat_status cat_trigger_unsolicited_event(struct cat_object *self, struct cat_command const *cmd, cat_cmd_type type);
/**
* Function sends unsolicited read event message.
* Command message is buffered inside parser in 1-level deep buffer and processed in cat_service context.
* Only command pointer is buffered, so command struct should be static or global until be fully processed.
*
* @param self pointer to at command parser object
* @param cmd pointer to command structure regarding which unsolicited read applies to
* @return according to cat_return_state enum definitions
*/
cat_status cat_trigger_unsolicited_read(struct cat_object *self, struct cat_command const *cmd);
/**
* Function sends unsolicited test event message.
* Command message is buffered inside parser in 1-level deep buffer and processed in cat_service context.
* Only command pointer is buffered, so command struct should be static or global until be fully processed.
*
* @param self pointer to at command parser object
* @param cmd pointer to command structure regarding which unsolicited test applies to
* @return according to cat_return_state enum definitions
*/
cat_status cat_trigger_unsolicited_test(struct cat_object *self, struct cat_command const *cmd);
/**
* Function used to exit from hold state with OK/ERROR response and back to idle state.
*
* @param self pointer to at command parser object
* @param status response status 0 - OK, else ERROR
* @return according to cat_return_state enum definitions
*/
cat_status cat_hold_exit(struct cat_object *self, cat_status status);
/**
* Function used to searching registered command by its name.
*
* @param self pointer to at command parser object
* @param name command name to search
* @return pointer to command object, NULL if command not found
*/
struct cat_command const* cat_search_command_by_name(struct cat_object *self, const char *name);
/**
* Function used to searching registered command group by its name.
*
* @param self pointer to at command parser object
* @param name command group name to search
* @return pointer to command group object, NULL if command group not found
*/
struct cat_command_group const* cat_search_command_group_by_name(struct cat_object *self, const char *name);
/**
* Function used to searching attached variable to command its name.
*
* @param self pointer to at command parser object
* @param cmd pointer to command in which variable will be searched
* @param name variable name to search
* @return pointer to command group object, NULL if command group not found
*/
struct cat_variable const* cat_search_variable_by_name(struct cat_object *self, struct cat_command const *cmd, const char *name);
/**
* Function used to check what command is currently processed.
* Function is not protected by mutex mechanism, due to processed cmd may change after function return.
* This only matters in multithreaded environments, it does not matter for one thread.
*
* @param self pointer to at command parser object
* @param fsm type of internal state machine to check current command
* @return pointer to command which is currently processed, NULL if no command is processed
*/
struct cat_command const* cat_get_processed_command(struct cat_object *self, cat_fsm_type fsm);
/**
* Function return unsolicited event command status.
* Function is not protected by mutex mechanism, due to processed cmd may change after function return.
* This only matters in multithreaded environments, it does not matter for one thread.
*
* @param self pointer to at command parser object
* @param cmd pointer to command in which variable will be searched
* @param type type of unsolicited event
* @return CAT_STATUS_OK - command is not buffered nor processed
* CAT_STATUS_BUSY - command is waiting in buffer or is processed
*/
cat_status cat_is_unsolicited_event_buffered(struct cat_object *self, struct cat_command const *cmd, cat_cmd_type type);
#ifdef __cplusplus
}
#endif
#endif /* CAT_H */

View File

@@ -0,0 +1,340 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char ack_results[512];
static int8_t var1;
static int8_t var2;
static char const *input_text;
static size_t input_index;
static int cmd_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num)
{
return 0;
}
static int cmd_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
return 0;
}
static int cmd_test(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
return 0;
}
static int cmd_run(const struct cat_command *cmd)
{
return 0;
}
static int var1_write(const struct cat_variable *var, size_t write_size)
{
return 0;
}
static int var2_write(const struct cat_variable *var, size_t write_size)
{
return 0;
}
static int print_cmd_list(const struct cat_command *cmd)
{
return CAT_RETURN_STATE_PRINT_CMD_LIST_OK;
}
static struct cat_variable vars[] = {
{
.type = CAT_VAR_INT_DEC,
.data = &var1,
.data_size = sizeof(var1),
.write = var1_write
}
};
static struct cat_variable vars_ro[] = {
{
.type = CAT_VAR_INT_DEC,
.data = &var1,
.data_size = sizeof(var1),
.write = var1_write,
.access = CAT_VAR_ACCESS_READ_ONLY
}
};
static struct cat_variable vars_wo[] = {
{
.type = CAT_VAR_INT_DEC,
.data = &var1,
.data_size = sizeof(var1),
.write = var1_write,
.access = CAT_VAR_ACCESS_WRITE_ONLY
}
};
static struct cat_variable vars2[] = {
{
.type = CAT_VAR_INT_DEC,
.data = &var1,
.data_size = sizeof(var1),
.write = var1_write
},
{
.type = CAT_VAR_INT_DEC,
.data = &var2,
.data_size = sizeof(var2),
.write = var2_write
}
};
static struct cat_variable vars2_ro[] = {
{
.type = CAT_VAR_INT_DEC,
.data = &var1,
.data_size = sizeof(var1),
.write = var1_write,
.access = CAT_VAR_ACCESS_READ_ONLY
},
{
.type = CAT_VAR_INT_DEC,
.data = &var2,
.data_size = sizeof(var2),
.write = var2_write
}
};
static struct cat_variable vars2_wo[] = {
{
.type = CAT_VAR_INT_DEC,
.data = &var1,
.data_size = sizeof(var1),
.write = var1_write,
.access = CAT_VAR_ACCESS_WRITE_ONLY
},
{
.type = CAT_VAR_INT_DEC,
.data = &var2,
.data_size = sizeof(var2),
.write = var2_write
}
};
static struct cat_command cmds[] = {
{
.name = "+V1",
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0])
},
{
.name = "+V1RO",
.var = vars_ro,
.var_num = sizeof(vars_ro) / sizeof(vars_ro[0])
},
{
.name = "+V1RW",
.var = vars_wo,
.var_num = sizeof(vars_wo) / sizeof(vars_wo[0])
},
{
.name = "+V11",
.var = vars2,
.var_num = sizeof(vars2) / sizeof(vars2[0])
},
{
.name = "+V11RO",
.var = vars2_ro,
.var_num = sizeof(vars2_ro) / sizeof(vars2_ro[0])
},
{
.name = "+V11WO",
.var = vars2_wo,
.var_num = sizeof(vars2_wo) / sizeof(vars2_wo[0])
},
{
.name = "+V2",
.write = cmd_write,
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0])
},
{
.name = "+V3",
.write = cmd_write,
.read = cmd_read,
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0])
},
{
.name = "+V4",
.write = cmd_write,
.read = cmd_read,
.test = cmd_test,
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0])
},
{
.name = "+V5",
.write = cmd_write,
.read = cmd_read,
.test = cmd_test,
.run = cmd_run,
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0])
},
{
.name = "+S1",
},
{
.name = "+S2",
.write = cmd_write,
},
{
.name = "+S3",
.write = cmd_write,
.read = cmd_read,
},
{
.name = "+S4",
.write = cmd_write,
.read = cmd_read,
.test = cmd_test,
},
{
.name = "+S5",
.write = cmd_write,
.read = cmd_read,
.test = cmd_test,
.run = cmd_run,
},
{
.name = "+D1",
.write = cmd_write,
.read = cmd_read,
.test = cmd_test,
.run = cmd_run,
.disable = true,
},
{
.name = "+T1",
.write = cmd_write,
.read = cmd_read,
.test = cmd_test,
.run = cmd_run,
.only_test = true,
},
{
.name = "+T2",
.only_test = true,
},
{
.name = "#HELP",
.run = print_cmd_list,
}
};
static char buf[512];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf),
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
memset(ack_results, 0, sizeof(ack_results));
}
static void print_raw_text(char *p)
{
while (*p != '\0') {
if (*p == '\n') {
printf("\\n");
} else {
putchar(*p);
}
p++;
}
}
int main(int argc, char **argv)
{
struct cat_object at;
cat_init(&at, &desc, &iface, NULL);
prepare_input("\nAT#HELP\n");
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nAT+V1?\nAT+V1=\nAT+V1=?\n\nAT+V1RO?\nAT+V1RO=?\n\nAT+V1RW=\nAT+V1RW=?\n\nAT+V11?\nAT+V11=\nAT+V11=?\n\nAT+V11RO?\nAT+V11RO=\nAT+V11RO=?\n\nAT+V11WO?\nAT+V11WO=\nAT+V11WO=?\n\nAT+V2?\nAT+V2=\nAT+V2=?\n\nAT+V3?\nAT+V3=\nAT+V3=?\n\nAT+V4?\nAT+V4=\nAT+V4=?\n\nAT+V5\nAT+V5?\nAT+V5=\nAT+V5=?\n\nAT+S2=\n\nAT+S3?\nAT+S3=\n\nAT+S4?\nAT+S4=\nAT+S4=?\n\nAT+S5\nAT+S5?\nAT+S5=\nAT+S5=?\n\nAT+T1=?\n\nAT#HELP\n\nOK\n") == 0);
return 0;
}

View File

@@ -0,0 +1,229 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char cmd_results[256];
static char var_read_results[256];
static char ack_results[256];
static char const *input_text;
static size_t input_index;
static int var_x, var_u1, var_u2;
static struct cat_object at;
static struct cat_command u_cmds[];
static cat_return_state cmd_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num)
{
cat_status s;
strcat(cmd_results, " write:");
strcat(cmd_results, cmd->name);
if (var_x < 2) {
s = cat_trigger_unsolicited_read(&at, &u_cmds[var_x]);
assert(s == CAT_STATUS_OK);
return CAT_RETURN_STATE_HOLD;
}
return CAT_RETURN_STATE_ERROR;
}
static cat_return_state cmd1_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
cat_status s;
strcat(cmd_results, " read1:");
strcat(cmd_results, cmd->name);
if (var_u1 > 0) {
var_u1--;
s = cat_trigger_unsolicited_read(&at, cmd);
assert(s == CAT_STATUS_OK);
return CAT_RETURN_STATE_DATA_OK;
}
return CAT_RETURN_STATE_HOLD_EXIT_OK;
}
static cat_return_state cmd2_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
cat_status s;
strcat(cmd_results, " read2:");
strcat(cmd_results, cmd->name);
if (var_u2 > 0) {
var_u2--;
s = cat_trigger_unsolicited_read(&at, cmd);
assert(s == CAT_STATUS_OK);
return CAT_RETURN_STATE_DATA_OK;
}
cat_hold_exit(&at, CAT_STATUS_OK);
return CAT_RETURN_STATE_DATA_OK;
}
static int var_read(const struct cat_variable *var)
{
strcat(var_read_results, " var_read:");
strcat(var_read_results, var->name);
return 0;
}
static struct cat_variable u_vars[] = {
{
.name = "U1",
.type = CAT_VAR_INT_DEC,
.data = &var_u1,
.data_size = sizeof(var_u1),
.read = var_read
},
{
.name = "U2",
.type = CAT_VAR_INT_DEC,
.data = &var_u2,
.data_size = sizeof(var_u2),
.read = var_read
}
};
static struct cat_variable vars[] = {
{
.name = "X",
.type = CAT_VAR_INT_DEC,
.data = &var_x,
.data_size = sizeof(var_x),
.read = var_read
}
};
static struct cat_command cmds[] = {
{
.name = "+CMD",
.write = cmd_write,
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0]),
}
};
static struct cat_command u_cmds[] = {
{
.name = "+U1CMD",
.read = cmd1_read,
.var = &u_vars[0],
.var_num = 1,
},
{
.name = "+U2CMD",
.read = cmd2_read,
.var = &u_vars[1],
.var_num = 1,
}
};
static char buf[128];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf),
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
var_u1 = 2;
var_u2 = 3;
memset(ack_results, 0, sizeof(ack_results));
memset(cmd_results, 0, sizeof(cmd_results));
memset(var_read_results, 0, sizeof(var_read_results));
}
static const char test_case_1[] = "\nAT+CMD=0\n\nAT+CMD=1\n";
int main(int argc, char **argv)
{
cat_status s;
cat_init(&at, &desc, &iface, NULL);
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+U1CMD=2\n\n+U1CMD=1\n\nOK\n\n+U2CMD=3\n\n+U2CMD=2\n\n+U2CMD=1\n\n+U2CMD=0\n\nOK\n") == 0);
assert(strcmp(cmd_results, " write:+CMD read1:+U1CMD read1:+U1CMD read1:+U1CMD write:+CMD read2:+U2CMD read2:+U2CMD read2:+U2CMD read2:+U2CMD") == 0);
assert(strcmp(var_read_results, " var_read:U1 var_read:U1 var_read:U1 var_read:U2 var_read:U2 var_read:U2 var_read:U2") == 0);
return 0;
}

View File

@@ -0,0 +1,185 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char run_results[256];
static char ack_results[256];
static char const *input_text;
static size_t input_index;
static int a_run(const struct cat_command *cmd)
{
strcat(run_results, " A:");
strcat(run_results, cmd->name);
return 0;
}
static int ap_run(const struct cat_command *cmd)
{
strcat(run_results, " AP:");
strcat(run_results, cmd->name);
return 0;
}
static int test_run(const struct cat_command *cmd)
{
strcat(run_results, " +TEST:");
strcat(run_results, cmd->name);
return 0;
}
static struct cat_command cmds[] = {
{
.name = "A",
.run = a_run
},
{
.name = "AP",
.run = ap_run
},
{
.name = "+TEST",
.run = test_run
}
};
static char buf[128];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf),
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static int mutex_ret_lock;
static int mutex_ret_unlock;
static int mutex_lock(void)
{
return mutex_ret_lock;
}
static int mutex_unlock(void)
{
return mutex_ret_unlock;
}
static struct cat_mutex_interface mutex = {
.lock = mutex_lock,
.unlock = mutex_unlock
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
mutex_ret_lock = 0;
mutex_ret_unlock = 0;
memset(run_results, 0, sizeof(run_results));
memset(ack_results, 0, sizeof(ack_results));
}
static const char test_case_1[] = "\nAT\nAT+test\n";
int main(int argc, char **argv)
{
struct cat_object at;
cat_init(&at, &desc, &iface, &mutex);
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n\nOK\n") == 0);
assert(strcmp(run_results, " +TEST:+TEST") == 0);
mutex_ret_lock = 1;
mutex_ret_unlock = 0;
assert(cat_service(&at) == CAT_STATUS_ERROR_MUTEX_LOCK);
mutex_ret_lock = 0;
mutex_ret_unlock = 1;
assert(cat_service(&at) == CAT_STATUS_ERROR_MUTEX_UNLOCK);
mutex_ret_lock = 1;
mutex_ret_unlock = 0;
assert(cat_is_busy(&at) == CAT_STATUS_ERROR_MUTEX_LOCK);
mutex_ret_lock = 0;
mutex_ret_unlock = 1;
assert(cat_is_busy(&at) == CAT_STATUS_ERROR_MUTEX_UNLOCK);
mutex_ret_lock = 0;
mutex_ret_unlock = 0;
assert(cat_service(&at) == CAT_STATUS_OK);
assert(cat_is_busy(&at) == CAT_STATUS_OK);
return 0;
}

View File

@@ -0,0 +1,223 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char run_results[256];
static char ack_results[256];
static char const *input_text;
static size_t input_index;
static int e_run(const struct cat_command *cmd)
{
strcat(run_results, " E:");
strcat(run_results, cmd->name);
return 0;
}
static int e0_run(const struct cat_command *cmd)
{
strcat(run_results, " E0:");
strcat(run_results, cmd->name);
return 0;
}
static int e1_run(const struct cat_command *cmd)
{
strcat(run_results, " E1:");
strcat(run_results, cmd->name);
return 0;
}
static struct cat_command cmds1[] = {
{
.name = "E",
.run = e_run,
},
{
.name = "E0",
.run = e0_run,
},
{
.name = "E1",
.run = e1_run,
}
};
static struct cat_command cmds2[] = {
{
.name = "E0",
.run = e0_run,
},
{
.name = "E1",
.run = e1_run,
},
{
.name = "E",
.run = e_run,
}
};
static struct cat_command cmds3[] = {
{
.name = "E0",
.run = e0_run,
},
{
.name = "E",
.run = e_run,
},
{
.name = "E1",
.run = e1_run,
}
};
static char buf[128];
static struct cat_command_group cmd_1_group = {
.cmd = cmds1,
.cmd_num = sizeof(cmds1) / sizeof(cmds1[0]),
};
static struct cat_command_group *cmd_1_desc[] = {
&cmd_1_group
};
static struct cat_descriptor desc_1 = {
.cmd_group = cmd_1_desc,
.cmd_group_num = sizeof(cmd_1_desc) / sizeof(cmd_1_desc[0]),
.buf = buf,
.buf_size = sizeof(buf),
};
static struct cat_command_group cmd_2_group = {
.cmd = cmds2,
.cmd_num = sizeof(cmds2) / sizeof(cmds2[0]),
};
static struct cat_command_group *cmd_2_desc[] = {
&cmd_2_group
};
static struct cat_descriptor desc_2 = {
.cmd_group = cmd_2_desc,
.cmd_group_num = sizeof(cmd_2_desc) / sizeof(cmd_2_desc[0]),
.buf = buf,
.buf_size = sizeof(buf),
};
static struct cat_command_group cmd_3_group = {
.cmd = cmds3,
.cmd_num = sizeof(cmds3) / sizeof(cmds3[0]),
};
static struct cat_command_group *cmd_3_desc[] = {
&cmd_3_group
};
static struct cat_descriptor desc_3 = {
.cmd_group = cmd_3_desc,
.cmd_group_num = sizeof(cmd_3_desc) / sizeof(cmd_3_desc[0]),
.buf = buf,
.buf_size = sizeof(buf),
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
memset(run_results, 0, sizeof(run_results));
memset(ack_results, 0, sizeof(ack_results));
}
static const char test_case_1[] = "\nATE\n\nATE0\n\nATE1\n";
int main(int argc, char **argv)
{
struct cat_object at;
cat_init(&at, &desc_1, &iface, NULL);
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n\nOK\n\nOK\n") == 0);
assert(strcmp(run_results, " E:E E0:E0 E1:E1") == 0);
cat_init(&at, &desc_2, &iface, NULL);
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n\nOK\n\nOK\n") == 0);
assert(strcmp(run_results, " E:E E0:E0 E1:E1") == 0);
cat_init(&at, &desc_3, &iface, NULL);
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n\nOK\n\nOK\n") == 0);
assert(strcmp(run_results, " E:E E0:E0 E1:E1") == 0);
return 0;
}

View File

@@ -0,0 +1,195 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char run_results[256];
static char ack_results[256];
static char const *input_text;
static size_t input_index;
static int a_run(const struct cat_command *cmd)
{
strcat(run_results, " A:");
strcat(run_results, cmd->name);
return 0;
}
static int ap_run(const struct cat_command *cmd)
{
strcat(run_results, " AP:");
strcat(run_results, cmd->name);
return 0;
}
static int test_run(const struct cat_command *cmd)
{
strcat(run_results, " +TEST:");
strcat(run_results, cmd->name);
return 0;
}
static struct cat_command cmds[] = {
{
.name = "A",
.run = a_run,
.disable = false,
},
{
.name = "AP",
.run = ap_run,
.disable = false,
},
{
.name = "+TEST",
.run = test_run,
.disable = false,
}
};
static char buf[128];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf),
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
memset(run_results, 0, sizeof(run_results));
memset(ack_results, 0, sizeof(ack_results));
}
static const char test_case_1[] = "\nsa\rAT\n\r\nAT\nAT+\n\nATA\r\natap\naaaattttap\na\n\r+test\r\n+testATA\nATAPATAP\n\rAT\rATA\nAT+test\r\n";
int main(int argc, char **argv)
{
struct cat_object at;
cat_init(&at, &desc, &iface, NULL);
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\r\nERROR\r\n\nOK\n\nOK\n\r\nOK\r\n\nOK\n\nERROR\n\nERROR\n\r\nERROR\r\n\nERROR\n\nERROR\n\r\nERROR\r\n\r\nOK\r\n") == 0);
assert(strcmp(run_results, " +TEST:+TEST A:A AP:AP +TEST:+TEST") == 0);
prepare_input("\nAT\n");
while (cat_service(&at) != 0) {};
assert(cat_is_busy(&at) == 0);
assert(strcmp(ack_results, "\nOK\n") == 0);
assert(strcmp(run_results, "") == 0);
prepare_input("\nAT+te");
while (cat_service(&at) != 0) {};
assert(cat_is_busy(&at) != 0);
assert(strcmp(ack_results, "") == 0);
assert(strcmp(run_results, "") == 0);
prepare_input("st\n");
while (cat_service(&at) != 0) {};
assert(cat_is_busy(&at) == 0);
assert(strcmp(ack_results, "\nOK\n") == 0);
assert(strcmp(run_results, " +TEST:+TEST") == 0);
struct cat_command *cmd;
cmd = (struct cat_command*)cat_search_command_by_name(&at, "A");
cmd->disable = true;
cmd = (struct cat_command*)cat_search_command_by_name(&at, "+TEST");
cmd->disable = true;
prepare_input("\nATA\n\nATAP\n\nAT+TEST\n");
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n\nOK\n\nERROR\n") == 0);
assert(strcmp(run_results, " AP:AP AP:AP") == 0);
struct cat_command_group *cmd_group;
cmd_group = (struct cat_command_group*)cat_search_command_group_by_name(&at, "standard");
assert(cmd_group == NULL);
cmd_desc[0]->name = "standard";
cmd_group = (struct cat_command_group*)cat_search_command_group_by_name(&at, "standard");
assert(cmd_group == cmd_desc[0]);
cmd_group->disable = true;
prepare_input("\nATA\n\nATAP\n\nAT+TEST\n");
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nERROR\n\nERROR\n\nERROR\n") == 0);
assert(strcmp(run_results, "") == 0);
return 0;
}

View File

@@ -0,0 +1,165 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char run_results[256];
static char read_results[256];
static char ack_results[256];
static char const *input_text;
static size_t input_index;
static int a_run(const struct cat_command *cmd)
{
strcat(run_results, " A_");
strcat(run_results, cmd->name);
return 0;
}
static int a_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
strcat(read_results, " A:");
strcat(read_results, cmd->name);
snprintf(data, max_data_size, "%s=A-val", cmd->name);
*data_size = strlen(data);
return 0;
}
static int ap_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
strcat(read_results, " AP:");
strcat(read_results, cmd->name);
*data_size = 0;
return 0;
}
static int test_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
strcat(read_results, " +TEST:");
strcat(read_results, cmd->name);
return -1;
}
static struct cat_command cmds[] = {
{
.name = "A",
.read = a_read,
.run = a_run
},
{
.name = "AP",
.read = ap_read
},
{
.name = "+TEST",
.read = test_read
},
{
.name = "+EMPTY"
}
};
static char buf[128];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf)
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
memset(run_results, 0, sizeof(run_results));
memset(ack_results, 0, sizeof(ack_results));
memset(read_results, 0, sizeof(read_results));
}
static const char test_case_1[] = "\nAT\r\nAT+\nAT+?\nATA?\r\nATAP\nATAP?\nATAPA?\nAT+TEST?\nAT+te?\nAT+e?\nAT+empTY?\r\nATA\r\n";
int main(int argc, char **argv)
{
struct cat_object at;
cat_init(&at, &desc, &iface, NULL);
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\r\nOK\r\n\nERROR\n\nERROR\n\r\nA=A-val\r\n\r\nOK\r\n\nERROR\n\nAP=\n\nOK\n\nERROR\n\nERROR\n\nERROR\n\nERROR\n\r\nERROR\r\n\r\nOK\r\n") == 0);
assert(strcmp(run_results, " A_A") == 0);
assert(strcmp(read_results, " A:A AP:AP +TEST:+TEST +TEST:+TEST") == 0);
return 0;
}

View File

@@ -0,0 +1,225 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char ack_results[256];
static int8_t var_int;
static uint8_t var_uint;
static uint8_t var_hex8;
static uint16_t var_hex16;
static uint32_t var_hex32;
static uint8_t var_buf[4];
static char var_string[16];
static char const *input_text;
static size_t input_index;
static int common_cntr;
static uint8_t ctx;
static int cmd_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
return 0;
}
static int cmd2_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
sprintf(data, "%s=test", cmd->name);
*data_size = strlen(data);
return 0;
}
static int common_var_read_handler(const struct cat_variable *var)
{
common_cntr++;
return 0;
}
static void* var_int_data_getter(const struct cat_variable *var, void *context, size_t *data_size)
{
*data_size = sizeof(var_int);
assert(context == &ctx);
return &var_int;
}
static struct cat_variable vars[] = {
{
.type = CAT_VAR_INT_DEC,
.read = common_var_read_handler,
.data_getter = var_int_data_getter,
},
{
.type = CAT_VAR_UINT_DEC,
.data = &var_uint,
.data_size = sizeof(var_uint),
.read = common_var_read_handler
},
{
.type = CAT_VAR_NUM_HEX,
.data = &var_hex8,
.data_size = sizeof(var_hex8),
.read = common_var_read_handler
},
{
.type = CAT_VAR_NUM_HEX,
.data = &var_hex16,
.data_size = sizeof(var_hex16),
.read = common_var_read_handler
},
{
.type = CAT_VAR_NUM_HEX,
.data = &var_hex32,
.data_size = sizeof(var_hex32),
.read = common_var_read_handler
},
{
.type = CAT_VAR_BUF_HEX,
.data = &var_buf,
.data_size = sizeof(var_buf),
.read = common_var_read_handler
},
{
.type = CAT_VAR_BUF_STRING,
.data = &var_string,
.data_size = sizeof(var_string),
.read = common_var_read_handler
}
};
static struct cat_command cmds[] = {
{
.name = "+SET",
.read = cmd_read,
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0]),
.context = &ctx,
},
{
.name = "+TEST",
.read = cmd2_read,
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0]),
.context = &ctx,
},
};
static char buf[128];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf)
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
var_int = -1;
var_uint = 255;
var_hex8 = 0xAA;
var_hex16 = 0x0123;
var_hex32 = 0xFF001234;
var_buf[0] = 0x12;
var_buf[1] = 0x34;
var_buf[2] = 0x56;
var_buf[3] = 0x78;
common_cntr = 0;
sprintf(var_string, "\\\"test\n");
memset(ack_results, 0, sizeof(ack_results));
}
static const char test_case_1[] = "\nAT+SET?\r\n";
static const char test_case_2[] = "\nAT+TEST?\n";
int main(int argc, char **argv)
{
struct cat_object at;
cat_init(&at, &desc, &iface, NULL);
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\r\n+SET=-1,255,0xAA,0x0123,0xFF001234,12345678,\"\\\\\\\"test\\n\"\r\n\r\nOK\r\n") == 0);
assert(common_cntr == 7);
prepare_input(test_case_2);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+TEST=test\n\nOK\n") == 0);
assert(common_cntr == 7);
return 0;
}

View File

@@ -0,0 +1,206 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char cmd_results[256];
static char ack_results[256];
static char const *input_text;
static size_t input_index;
static int var_x;
static struct cat_object at;
static cat_return_state ret;
static bool ret_error;
static cat_return_state cmd_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
strcat(cmd_results, " read:");
strcat(cmd_results, cmd->name);
if (cat_is_hold(&at) == CAT_STATUS_HOLD) {
var_x++;
if (var_x > 4) {
ret = (ret_error == false) ? CAT_RETURN_STATE_HOLD_EXIT_OK : CAT_RETURN_STATE_HOLD_EXIT_ERROR;
} else {
if (var_x == 4) {
strcpy(data, "test");
*data_size = strlen(data);
}
ret = CAT_RETURN_STATE_DATA_NEXT;
}
} else {
if ((ret == CAT_RETURN_STATE_DATA_NEXT) || (ret == CAT_RETURN_STATE_NEXT)) {
var_x++;
if (var_x > 2)
ret = CAT_RETURN_STATE_DATA_OK;
} else if (ret == CAT_RETURN_STATE_HOLD) {
cat_trigger_unsolicited_read(&at, cmd);
}
}
return ret;
}
static struct cat_variable vars[] = {
{
.name = "X",
.type = CAT_VAR_INT_DEC,
.data = &var_x,
.data_size = sizeof(var_x)
}
};
static struct cat_command cmds[] = {
{
.name = "+CMD",
.read = cmd_read,
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0]),
}
};
static char buf[128];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf),
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
var_x = 1;
memset(ack_results, 0, sizeof(ack_results));
memset(cmd_results, 0, sizeof(cmd_results));
}
static const char test_case_1[] = "\nAT+CMD?\n";
int main(int argc, char **argv)
{
cat_status s;
cat_init(&at, &desc, &iface, NULL);
ret = CAT_RETURN_STATE_ERROR;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nERROR\n") == 0);
assert(strcmp(cmd_results, " read:+CMD") == 0);
ret = CAT_RETURN_STATE_DATA_OK;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+CMD=1\n\nOK\n") == 0);
assert(strcmp(cmd_results, " read:+CMD") == 0);
ret = CAT_RETURN_STATE_DATA_NEXT;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+CMD=1\n\n+CMD=2\n\nOK\n") == 0);
assert(strcmp(cmd_results, " read:+CMD read:+CMD") == 0);
ret = CAT_RETURN_STATE_NEXT;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+CMD=2\n\nOK\n") == 0);
assert(strcmp(cmd_results, " read:+CMD read:+CMD") == 0);
ret = CAT_RETURN_STATE_OK;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n") == 0);
assert(strcmp(cmd_results, " read:+CMD") == 0);
ret_error = false;
ret = CAT_RETURN_STATE_HOLD;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+CMD=1\n\n+CMD=2\n\ntest\n\nOK\n") == 0);
assert(strcmp(cmd_results, " read:+CMD read:+CMD read:+CMD read:+CMD read:+CMD") == 0);
ret_error = true;
ret = CAT_RETURN_STATE_HOLD;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+CMD=1\n\n+CMD=2\n\ntest\n\nERROR\n") == 0);
assert(strcmp(cmd_results, " read:+CMD read:+CMD read:+CMD read:+CMD read:+CMD") == 0);
return 0;
}

View File

@@ -0,0 +1,236 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char cmd_results[256];
static char ack_results[256];
static char const *input_text;
static size_t input_index;
static int var_x;
static struct cat_object at;
static cat_return_state ret;
static bool ret_error;
static cat_return_state cmd_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
strcat(cmd_results, " read:");
strcat(cmd_results, cmd->name);
var_x++;
if (var_x > 5) {
ret = (ret_error == false) ? CAT_RETURN_STATE_HOLD_EXIT_OK : CAT_RETURN_STATE_HOLD_EXIT_ERROR;
} else {
if (var_x == 5) {
strcpy(data, "test");
*data_size = strlen(data);
}
ret = CAT_RETURN_STATE_DATA_NEXT;
}
return ret;
}
static cat_return_state cmd_run(const struct cat_command *cmd)
{
strcat(cmd_results, " run:");
strcat(cmd_results, cmd->name);
if ((ret == CAT_RETURN_STATE_DATA_NEXT) || (ret == CAT_RETURN_STATE_NEXT)) {
var_x++;
if (var_x > 3)
ret = CAT_RETURN_STATE_DATA_OK;
} else if (ret == CAT_RETURN_STATE_HOLD) {
cat_trigger_unsolicited_read(&at, cmd);
}
return ret;
}
static struct cat_variable vars[] = {
{
.name = "X",
.type = CAT_VAR_INT_DEC,
.data = &var_x,
.data_size = sizeof(var_x)
}
};
static struct cat_command cmds[] = {
{
.name = "+CMD",
.run = cmd_run,
.read = cmd_read,
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0]),
}
};
static char buf[128];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf),
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
var_x = 2;
memset(ack_results, 0, sizeof(ack_results));
memset(cmd_results, 0, sizeof(cmd_results));
}
static const char test_case_1[] = "\nAT+CMD\n";
int main(int argc, char **argv)
{
cat_status s;
cat_init(&at, &desc, &iface, NULL);
ret = CAT_RETURN_STATE_ERROR;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nERROR\n") == 0);
assert(strcmp(cmd_results, " run:+CMD") == 0);
assert(var_x == 2);
ret = CAT_RETURN_STATE_DATA_OK;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n") == 0);
assert(strcmp(cmd_results, " run:+CMD") == 0);
assert(var_x == 2);
ret = CAT_RETURN_STATE_DATA_NEXT;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n") == 0);
assert(strcmp(cmd_results, " run:+CMD run:+CMD") == 0);
assert(var_x == 4);
ret = CAT_RETURN_STATE_NEXT;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n") == 0);
assert(strcmp(cmd_results, " run:+CMD run:+CMD") == 0);
assert(var_x == 4);
ret = CAT_RETURN_STATE_OK;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n") == 0);
assert(strcmp(cmd_results, " run:+CMD") == 0);
assert(var_x == 2);
ret_error = false;
ret = CAT_RETURN_STATE_HOLD;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+CMD=2\n\n+CMD=3\n\ntest\n\nOK\n") == 0);
assert(strcmp(cmd_results, " run:+CMD read:+CMD read:+CMD read:+CMD read:+CMD") == 0);
assert(var_x == 6);
ret_error = true;
ret = CAT_RETURN_STATE_HOLD;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+CMD=2\n\n+CMD=3\n\ntest\n\nERROR\n") == 0);
assert(strcmp(cmd_results, " run:+CMD read:+CMD read:+CMD read:+CMD read:+CMD") == 0);
assert(var_x == 6);
ret = CAT_RETURN_STATE_HOLD_EXIT_ERROR;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nERROR\n") == 0);
assert(strcmp(cmd_results, " run:+CMD") == 0);
assert(var_x == 2);
ret = CAT_RETURN_STATE_HOLD_EXIT_OK;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nERROR\n") == 0);
assert(strcmp(cmd_results, " run:+CMD") == 0);
assert(var_x == 2);
return 0;
}

View File

@@ -0,0 +1,206 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char cmd_results[256];
static char ack_results[256];
static char const *input_text;
static size_t input_index;
static int var_x;
static struct cat_object at;
static cat_return_state ret;
static bool ret_error;
static cat_return_state cmd_test(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
strcat(cmd_results, " test:");
strcat(cmd_results, cmd->name);
if (cat_is_hold(&at) == CAT_STATUS_HOLD) {
var_x++;
if (var_x > 4) {
ret = (ret_error == false) ? CAT_RETURN_STATE_HOLD_EXIT_OK : CAT_RETURN_STATE_HOLD_EXIT_ERROR;
} else {
if (var_x == 4) {
strcpy(data, "test");
*data_size = strlen(data);
}
ret = CAT_RETURN_STATE_DATA_NEXT;
}
} else {
if ((ret == CAT_RETURN_STATE_DATA_NEXT) || (ret == CAT_RETURN_STATE_NEXT)) {
var_x++;
if (var_x > 2)
ret = CAT_RETURN_STATE_DATA_OK;
} else if (ret == CAT_RETURN_STATE_HOLD) {
cat_trigger_unsolicited_test(&at, cmd);
}
}
return ret;
}
static struct cat_variable vars[] = {
{
.name = "X",
.type = CAT_VAR_INT_DEC,
.data = &var_x,
.data_size = sizeof(var_x)
}
};
static struct cat_command cmds[] = {
{
.name = "+CMD",
.test = cmd_test,
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0]),
}
};
static char buf[128];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf),
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
var_x = 1;
memset(ack_results, 0, sizeof(ack_results));
memset(cmd_results, 0, sizeof(cmd_results));
}
static const char test_case_1[] = "\nAT+CMD=?\n";
int main(int argc, char **argv)
{
cat_status s;
cat_init(&at, &desc, &iface, NULL);
ret = CAT_RETURN_STATE_ERROR;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nERROR\n") == 0);
assert(strcmp(cmd_results, " test:+CMD") == 0);
ret = CAT_RETURN_STATE_DATA_OK;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+CMD=<X:INT32[RW]>\n\nOK\n") == 0);
assert(strcmp(cmd_results, " test:+CMD") == 0);
ret = CAT_RETURN_STATE_DATA_NEXT;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+CMD=<X:INT32[RW]>\n\n+CMD=<X:INT32[RW]>\n\nOK\n") == 0);
assert(strcmp(cmd_results, " test:+CMD test:+CMD") == 0);
ret = CAT_RETURN_STATE_NEXT;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+CMD=<X:INT32[RW]>\n\nOK\n") == 0);
assert(strcmp(cmd_results, " test:+CMD test:+CMD") == 0);
ret = CAT_RETURN_STATE_OK;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n") == 0);
assert(strcmp(cmd_results, " test:+CMD") == 0);
ret_error = false;
ret = CAT_RETURN_STATE_HOLD;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+CMD=<X:INT32[RW]>\n\n+CMD=<X:INT32[RW]>\n\ntest\n\nOK\n") == 0);
assert(strcmp(cmd_results, " test:+CMD test:+CMD test:+CMD test:+CMD test:+CMD") == 0);
ret_error = true;
ret = CAT_RETURN_STATE_HOLD;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+CMD=<X:INT32[RW]>\n\n+CMD=<X:INT32[RW]>\n\ntest\n\nERROR\n") == 0);
assert(strcmp(cmd_results, " test:+CMD test:+CMD test:+CMD test:+CMD test:+CMD") == 0);
return 0;
}

View File

@@ -0,0 +1,236 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char cmd_results[256];
static char ack_results[256];
static char const *input_text;
static size_t input_index;
static int var_x;
static struct cat_object at;
static cat_return_state ret;
static bool ret_error;
static cat_return_state cmd_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
strcat(cmd_results, " read:");
strcat(cmd_results, cmd->name);
var_x++;
if (var_x > 5) {
ret = (ret_error == false) ? CAT_RETURN_STATE_HOLD_EXIT_OK : CAT_RETURN_STATE_HOLD_EXIT_ERROR;
} else {
if (var_x == 5) {
strcpy(data, "test");
*data_size = strlen(data);
}
ret = CAT_RETURN_STATE_DATA_NEXT;
}
return ret;
}
static cat_return_state cmd_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num)
{
strcat(cmd_results, " write:");
strcat(cmd_results, cmd->name);
if ((ret == CAT_RETURN_STATE_DATA_NEXT) || (ret == CAT_RETURN_STATE_NEXT)) {
var_x++;
if (var_x > 3)
ret = CAT_RETURN_STATE_DATA_OK;
} else if (ret == CAT_RETURN_STATE_HOLD) {
cat_trigger_unsolicited_read(&at, cmd);
}
return ret;
}
static struct cat_variable vars[] = {
{
.name = "X",
.type = CAT_VAR_INT_DEC,
.data = &var_x,
.data_size = sizeof(var_x)
}
};
static struct cat_command cmds[] = {
{
.name = "+CMD",
.write = cmd_write,
.read = cmd_read,
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0]),
}
};
static char buf[128];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf),
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
var_x = 1;
memset(ack_results, 0, sizeof(ack_results));
memset(cmd_results, 0, sizeof(cmd_results));
}
static const char test_case_1[] = "\nAT+CMD=2\n";
int main(int argc, char **argv)
{
cat_status s;
cat_init(&at, &desc, &iface, NULL);
ret = CAT_RETURN_STATE_ERROR;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nERROR\n") == 0);
assert(strcmp(cmd_results, " write:+CMD") == 0);
assert(var_x == 2);
ret = CAT_RETURN_STATE_DATA_OK;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n") == 0);
assert(strcmp(cmd_results, " write:+CMD") == 0);
assert(var_x == 2);
ret = CAT_RETURN_STATE_DATA_NEXT;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n") == 0);
assert(strcmp(cmd_results, " write:+CMD write:+CMD") == 0);
assert(var_x == 4);
ret = CAT_RETURN_STATE_NEXT;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n") == 0);
assert(strcmp(cmd_results, " write:+CMD write:+CMD") == 0);
assert(var_x == 4);
ret = CAT_RETURN_STATE_OK;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n") == 0);
assert(strcmp(cmd_results, " write:+CMD") == 0);
assert(var_x == 2);
ret_error = false;
ret = CAT_RETURN_STATE_HOLD;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+CMD=2\n\n+CMD=3\n\ntest\n\nOK\n") == 0);
assert(strcmp(cmd_results, " write:+CMD read:+CMD read:+CMD read:+CMD read:+CMD") == 0);
assert(var_x == 6);
ret_error = true;
ret = CAT_RETURN_STATE_HOLD;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+CMD=2\n\n+CMD=3\n\ntest\n\nERROR\n") == 0);
assert(strcmp(cmd_results, " write:+CMD read:+CMD read:+CMD read:+CMD read:+CMD") == 0);
assert(var_x == 6);
ret = CAT_RETURN_STATE_HOLD_EXIT_ERROR;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nERROR\n") == 0);
assert(strcmp(cmd_results, " write:+CMD") == 0);
assert(var_x == 2);
ret = CAT_RETURN_STATE_HOLD_EXIT_OK;
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nERROR\n") == 0);
assert(strcmp(cmd_results, " write:+CMD") == 0);
assert(var_x == 2);
return 0;
}

View File

@@ -0,0 +1,157 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char run_results[256];
static char ack_results[256];
static char const *input_text;
static size_t input_index;
static int a_run(const struct cat_command *cmd)
{
strcat(run_results, " A:");
strcat(run_results, cmd->name);
return 0;
}
static int ap_run(const struct cat_command *cmd)
{
strcat(run_results, " AP:");
strcat(run_results, cmd->name);
return 0;
}
static int test_run(const struct cat_command *cmd)
{
strcat(run_results, " +TEST:");
strcat(run_results, cmd->name);
return 0;
}
static int force_run(const struct cat_command *cmd)
{
strcat(run_results, " FORCE:");
strcat(run_results, cmd->name);
return -1;
}
static struct cat_command cmds[] = {
{
.name = "A",
.run = a_run
},
{
.name = "AP",
.run = ap_run
},
{
.name = "+TEST",
.run = test_run
},
{
.name = "+EMPTY"
},
{
.name = "FORCE",
.run = force_run,
}
};
static char buf[128];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf)
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
memset(run_results, 0, sizeof(run_results));
memset(ack_results, 0, sizeof(ack_results));
}
static const char test_case_1[] = "\nAT\nAT+\nATA\r\nATAP\nATAPA\nAT+TEST\nAT+te\nAT+e\nAT+empTY\naTf\nAtFoRcE\n";
int main(int argc, char **argv)
{
struct cat_object at;
cat_init(&at, &desc, &iface, NULL);
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n\nERROR\n\r\nOK\r\n\nOK\n\nERROR\n\nOK\n\nOK\n\nERROR\n\nERROR\n\nERROR\n\nERROR\n") == 0);
assert(strcmp(run_results, " A:A AP:AP +TEST:+TEST +TEST:+TEST FORCE:FORCE FORCE:FORCE") == 0);
return 0;
}

View File

@@ -0,0 +1,224 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static int ap_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
return 0;
}
static int ap_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num)
{
return 0;
}
static struct cat_variable vars_ap1[] = {
{
.name = "var_ap1_1"
},
{
.name = "var_ap1_2"
},
{
.name = "var_ap1_3"
}
};
static struct cat_variable vars_apx2[] = {
{
.name = "var_apx2_1"
},
{
.name = "var_apx2_2"
},
{
.name = "var_apx2_3"
}
};
static struct cat_command cmds[] = {
{
.name = "AP1",
.write = ap_write,
.only_test = true,
.var = vars_ap1,
.var_num = sizeof(vars_ap1) / sizeof(vars_ap1[0])
},
{
.name = "AP2",
.read = ap_read,
.only_test = false
},
};
static struct cat_command cmds2[] = {
{
.name = "APX1",
.write = ap_write,
.only_test = true
},
{
.name = "APX2",
.read = ap_read,
.only_test = false,
.var = vars_apx2,
.var_num = sizeof(vars_apx2) / sizeof(vars_apx2[0])
},
};
static char buf[128];
static struct cat_command_group cmd_group1 = {
.name = "std",
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group cmd_group2 = {
.name = "ext",
.cmd = cmds2,
.cmd_num = sizeof(cmds2) / sizeof(cmds2[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group1,
&cmd_group2
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf)
};
static int write_char(char ch)
{
return 1;
}
static int read_char(char *ch)
{
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
int main(int argc, char **argv)
{
struct cat_object at;
struct cat_command const *cmd;
struct cat_command_group const *cmd_group;
struct cat_variable const *var;
cat_init(&at, &desc, &iface, NULL);
cmd = cat_search_command_by_name(&at, "A");
assert(cmd == NULL);
cmd = cat_search_command_by_name(&at, "AP");
assert(cmd == NULL);
cmd = cat_search_command_by_name(&at, "AP1");
assert(cmd == &cmds[0]);
cmd = cat_search_command_by_name(&at, "AP2");
assert(cmd == &cmds[1]);
cmd = cat_search_command_by_name(&at, "AP3");
assert(cmd == NULL);
cmd = cat_search_command_by_name(&at, "APX1");
assert(cmd == &cmds2[0]);
cmd = cat_search_command_by_name(&at, "APX2");
assert(cmd == &cmds2[1]);
cmd = cat_search_command_by_name(&at, "APX3");
assert(cmd == NULL);
cmd_group = cat_search_command_group_by_name(&at, "std");
assert(cmd_group == cmd_desc[0]);
cmd_group = cat_search_command_group_by_name(&at, "ext");
assert(cmd_group == cmd_desc[1]);
cmd_group = cat_search_command_group_by_name(&at, "not");
assert(cmd_group == NULL);
var = cat_search_variable_by_name(&at, &cmds[0], "v");
assert(var == NULL);
var = cat_search_variable_by_name(&at, &cmds[0], "var_ap");
assert(var == NULL);
var = cat_search_variable_by_name(&at, &cmds[0], "var_apx2");
assert(var == NULL);
var = cat_search_variable_by_name(&at, &cmds[0], "var_ap1_1");
assert(var == &vars_ap1[0]);
var = cat_search_variable_by_name(&at, &cmds[0], "var_ap1_2");
assert(var == &vars_ap1[1]);
var = cat_search_variable_by_name(&at, &cmds[0], "var_ap1_3");
assert(var == &vars_ap1[2]);
var = cat_search_variable_by_name(&at, &cmds[0], "var_ap1_4");
assert(var == NULL);
var = cat_search_variable_by_name(&at, &cmds[1], "var_ap1_1");
assert(var == NULL);
var = cat_search_variable_by_name(&at, &cmds2[1], "var_apx2_1");
assert(var == &vars_apx2[0]);
var = cat_search_variable_by_name(&at, &cmds2[1], "var_apx2_2");
assert(var == &vars_apx2[1]);
var = cat_search_variable_by_name(&at, &cmds2[1], "var_apx2_3");
assert(var == &vars_apx2[2]);
var = cat_search_variable_by_name(&at, &cmds2[1], "var_apx2_4");
assert(var == NULL);
var = cat_search_variable_by_name(&at, &cmds2[0], "var_apx2_1");
assert(var == NULL);
return 0;
}

View File

@@ -0,0 +1,149 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char run_results[256];
static char ack_results[256];
static char const *input_text;
static size_t input_index;
static int print_name(const struct cat_command *cmd)
{
strcat(run_results, cmd->name);
strcat(run_results, " ");
return 0;
}
static struct cat_command cmds[] = {
{
.name = "+TEST",
.run = print_name
},
{
.name = "+TEST_A",
.run = print_name
},
{
.name = "+TEST_B",
.run = print_name
},
{
.name = "+ONE",
.run = print_name
},
{
.name = "+TWO",
.run = print_name
},
};
static char buf[256];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf)
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
memset(run_results, 0, sizeof(run_results));
memset(ack_results, 0, sizeof(ack_results));
}
static const char test_case_1[] = "\nAT\nAT+\nAT+T\nAT+TE\nAT+TES\nAT+TEST\nAT+TEST_\nAT+TEST_A\nAT+TEST_B\nAT+O\nAT+ON\nAT+ONE\nAT+TW\nAT+TWO\n";
static void print_raw_text(char *p)
{
while (*p != '\0') {
if (*p == '\n') {
printf("\\n");
} else {
putchar(*p);
}
p++;
}
}
int main(int argc, char **argv)
{
struct cat_object at;
cat_init(&at, &desc, &iface, NULL);
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n\nERROR\n\nERROR\n\nERROR\n\nERROR\n\nOK\n\nERROR\n\nOK\n\nOK\n\nOK\n\nOK\n\nOK\n\nOK\n\nOK\n") == 0);
assert(strcmp(run_results, "+TEST +TEST_A +TEST_B +ONE +ONE +ONE +TWO +TWO ") == 0);
return 0;
}

View File

@@ -0,0 +1,183 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char test_results[256];
static char ack_results[256];
static char const *input_text;
static size_t input_index;
static int a_test(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
strcat(test_results, " A:");
strcat(test_results, cmd->name);
snprintf(data, max_data_size, "%s=A-val", cmd->name);
*data_size = strlen(data);
return 0;
}
static int ap_test(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
strcat(test_results, " AP:");
strcat(test_results, cmd->name);
*data_size = 0;
return 0;
}
static int ap_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num)
{
strcat(test_results, " AP_W:");
strcat(test_results, cmd->name);
assert(args_num == 0);
assert(data[0] == 'a');
assert(data_size == 1);
return 0;
}
static int apw_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num)
{
strcat(test_results, " APW:");
strcat(test_results, cmd->name);
assert(args_num == 0);
assert(data[0] == '?');
assert(data_size == 1);
return 0;
}
static int test_test(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
strcat(test_results, " +TEST:");
strcat(test_results, cmd->name);
return -1;
}
static struct cat_command cmds[] = {
{
.name = "A",
.test = a_test
},
{
.name = "AP",
.test = ap_test,
.write = ap_write
},
{
.name = "APW",
.write = apw_write
},
{
.name = "+TEST",
.test = test_test
},
{
.name = "+EMPTY"
}
};
static char buf[128];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf)
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
memset(ack_results, 0, sizeof(ack_results));
memset(test_results, 0, sizeof(test_results));
}
static const char test_case_1[] = "\nAT\r\nAT\nATAP=?\nATAP=?a\nATAP=a\nATAPW=?\nAT+TEST=?\nATA=?\nAT+EMPTY=?\n";
int main(int argc, char **argv)
{
struct cat_object at;
cat_init(&at, &desc, &iface, NULL);
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\r\nOK\r\n\nOK\n\nAP=\n\nOK\n\nERROR\n\nOK\n\nOK\n\nERROR\n\nA=A-val\n\nOK\n\nERROR\n") == 0);
assert(strcmp(test_results, " AP:AP AP_W:AP APW:APW +TEST:+TEST A:A") == 0);
return 0;
}

View File

@@ -0,0 +1,459 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char ack_results[256];
static int8_t var_int8;
static int16_t var_int16;
static int32_t var_int32;
static uint8_t var_uint8;
static uint16_t var_uint16;
static uint32_t var_uint32;
static uint8_t var_hex8;
static uint16_t var_hex16;
static uint32_t var_hex32;
static uint8_t var_buf[4];
static char var_string[16];
static char const *input_text;
static size_t input_index;
static int cmd_override_test(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
strcat(data, "\ntest");
*data_size = strlen(data);
return 0;
}
static int cmd_error_test(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
return -1;
}
static int cmd_ok_test(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
strcpy(data, "test1");
*data_size = strlen(data);
return 0;
}
static int cmd_ok2_test(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
strcat(data, "test2");
*data_size = strlen(data);
return 0;
}
static struct cat_variable vars[] = {
{
.type = CAT_VAR_INT_DEC,
.data = &var_int8,
.data_size = sizeof(var_int8),
.name = "x"
},
{
.type = CAT_VAR_INT_DEC,
.data = &var_int16,
.data_size = sizeof(var_int16),
.name = "y"
},
{
.type = CAT_VAR_INT_DEC,
.data = &var_int32,
.data_size = sizeof(var_int32)
},
{
.type = CAT_VAR_UINT_DEC,
.data = &var_uint8,
.data_size = sizeof(var_uint8)
},
{
.type = CAT_VAR_UINT_DEC,
.data = &var_uint16,
.data_size = sizeof(var_uint16)
},
{
.type = CAT_VAR_UINT_DEC,
.data = &var_uint32,
.data_size = sizeof(var_uint32)
},
{
.type = CAT_VAR_NUM_HEX,
.data = &var_hex8,
.data_size = sizeof(var_hex8)
},
{
.type = CAT_VAR_NUM_HEX,
.data = &var_hex16,
.data_size = sizeof(var_hex16)
},
{
.type = CAT_VAR_NUM_HEX,
.data = &var_hex32,
.data_size = sizeof(var_hex32)
},
{
.type = CAT_VAR_BUF_HEX,
.data = &var_buf,
.data_size = sizeof(var_buf)
},
{
.type = CAT_VAR_BUF_STRING,
.data = &var_string,
.data_size = sizeof(var_string),
.name = "msg"
}
};
static struct cat_variable vars_ro[] = {
{
.type = CAT_VAR_INT_DEC,
.data = &var_int8,
.data_size = sizeof(var_int8),
.name = "x",
.access = CAT_VAR_ACCESS_READ_ONLY
},
{
.type = CAT_VAR_INT_DEC,
.data = &var_int16,
.data_size = sizeof(var_int16),
.name = "y",
.access = CAT_VAR_ACCESS_READ_ONLY
},
{
.type = CAT_VAR_INT_DEC,
.data = &var_int32,
.data_size = sizeof(var_int32),
.access = CAT_VAR_ACCESS_READ_ONLY
},
{
.type = CAT_VAR_UINT_DEC,
.data = &var_uint8,
.data_size = sizeof(var_uint8),
.access = CAT_VAR_ACCESS_READ_ONLY
},
{
.type = CAT_VAR_UINT_DEC,
.data = &var_uint16,
.data_size = sizeof(var_uint16),
.access = CAT_VAR_ACCESS_READ_ONLY
},
{
.type = CAT_VAR_UINT_DEC,
.data = &var_uint32,
.data_size = sizeof(var_uint32),
.access = CAT_VAR_ACCESS_READ_ONLY
},
{
.type = CAT_VAR_NUM_HEX,
.data = &var_hex8,
.data_size = sizeof(var_hex8),
.access = CAT_VAR_ACCESS_READ_ONLY
},
{
.type = CAT_VAR_NUM_HEX,
.data = &var_hex16,
.data_size = sizeof(var_hex16),
.access = CAT_VAR_ACCESS_READ_ONLY
},
{
.type = CAT_VAR_NUM_HEX,
.data = &var_hex32,
.data_size = sizeof(var_hex32),
.access = CAT_VAR_ACCESS_READ_ONLY
},
{
.type = CAT_VAR_BUF_HEX,
.data = &var_buf,
.data_size = sizeof(var_buf),
.access = CAT_VAR_ACCESS_READ_ONLY
},
{
.type = CAT_VAR_BUF_STRING,
.data = &var_string,
.data_size = sizeof(var_string),
.name = "msg",
.access = CAT_VAR_ACCESS_READ_ONLY
}
};
static struct cat_variable vars_wo[] = {
{
.type = CAT_VAR_INT_DEC,
.data = &var_int8,
.data_size = sizeof(var_int8),
.name = "x",
.access = CAT_VAR_ACCESS_WRITE_ONLY
},
{
.type = CAT_VAR_INT_DEC,
.data = &var_int16,
.data_size = sizeof(var_int16),
.name = "y",
.access = CAT_VAR_ACCESS_WRITE_ONLY
},
{
.type = CAT_VAR_INT_DEC,
.data = &var_int32,
.data_size = sizeof(var_int32),
.access = CAT_VAR_ACCESS_WRITE_ONLY
},
{
.type = CAT_VAR_UINT_DEC,
.data = &var_uint8,
.data_size = sizeof(var_uint8),
.access = CAT_VAR_ACCESS_WRITE_ONLY
},
{
.type = CAT_VAR_UINT_DEC,
.data = &var_uint16,
.data_size = sizeof(var_uint16),
.access = CAT_VAR_ACCESS_WRITE_ONLY
},
{
.type = CAT_VAR_UINT_DEC,
.data = &var_uint32,
.data_size = sizeof(var_uint32),
.access = CAT_VAR_ACCESS_WRITE_ONLY
},
{
.type = CAT_VAR_NUM_HEX,
.data = &var_hex8,
.data_size = sizeof(var_hex8),
.access = CAT_VAR_ACCESS_WRITE_ONLY
},
{
.type = CAT_VAR_NUM_HEX,
.data = &var_hex16,
.data_size = sizeof(var_hex16),
.access = CAT_VAR_ACCESS_WRITE_ONLY
},
{
.type = CAT_VAR_NUM_HEX,
.data = &var_hex32,
.data_size = sizeof(var_hex32),
.access = CAT_VAR_ACCESS_WRITE_ONLY
},
{
.type = CAT_VAR_BUF_HEX,
.data = &var_buf,
.data_size = sizeof(var_buf),
.access = CAT_VAR_ACCESS_WRITE_ONLY
},
{
.type = CAT_VAR_BUF_STRING,
.data = &var_string,
.data_size = sizeof(var_string),
.name = "msg",
.access = CAT_VAR_ACCESS_WRITE_ONLY
}
};
static struct cat_variable vars2[] = {
{
.type = CAT_VAR_INT_DEC,
.data = &var_int8,
.data_size = sizeof(var_int8),
.name = "var"
}
};
static struct cat_command cmds[] = {
{
.name = "+SET",
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0])
},
{
.name = "+SETRO",
.var = vars_ro,
.var_num = sizeof(vars_ro) / sizeof(vars_ro[0])
},
{
.name = "+SETWO",
.var = vars_wo,
.var_num = sizeof(vars_wo) / sizeof(vars_wo[0])
},
{
.name = "+TEST",
.description = "test_desc",
.test = cmd_override_test,
.var = vars2,
.var_num = sizeof(vars2) / sizeof(vars2[0])
},
{
.name = "+TEST2",
.description = "test2_desc",
.var = vars2,
.var_num = sizeof(vars2) / sizeof(vars2[0])
},
{
.name = "+AP",
.test = cmd_error_test,
.var = vars2,
.var_num = sizeof(vars2) / sizeof(vars2[0])
},
{
.name = "+ZZ",
.test = cmd_ok_test,
},
{
.name = "+ZZ2",
.description = "zz2_desc",
.test = cmd_ok_test,
},
{
.name = "+ZZ3",
.description = "zz3_desc",
.test = cmd_ok2_test,
}
};
static char buf[256];
static char unsolicited_buf[256];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf),
.unsolicited_buf = unsolicited_buf,
.unsolicited_buf_size = sizeof(unsolicited_buf),
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
var_int8 = -8;
var_int16 = -16;
var_int32 = -32;
var_uint8 = 8;
var_uint8 = 16;
var_uint8 = 32;
var_hex8 = 0x08;
var_hex16 = 0x16;
var_hex32 = 0x32;
var_hex16 = 0x0123;
var_hex32 = 0xFF001234;
var_buf[0] = 0x12;
var_buf[1] = 0x34;
var_buf[2] = 0x56;
var_buf[3] = 0x78;
sprintf(var_string, "TST");
memset(ack_results, 0, sizeof(ack_results));
}
static const char test_case_1[] = "\nAT+SET=?\n";
static const char test_case_1_ro[] = "\nAT+SETRO=?\n";
static const char test_case_1_wo[] = "\nAT+SETWO=?\n";
static const char test_case_2[] = "\nAT+TEST=?\nAT+TEST2=?\r\nAT+AP=?\n";
static const char test_case_3[] = "\nAT+ZZ=?\nAT+ZZ2=?\nAT+ZZ3=?\r\n";
int main(int argc, char **argv)
{
struct cat_object at;
cat_init(&at, &desc, &iface, NULL);
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+SET=<x:INT8[RW]>,<y:INT16[RW]>,<INT32[RW]>,<UINT8[RW]>,<UINT16[RW]>,<UINT32[RW]>,<HEX8[RW]>,<HEX16[RW]>,<HEX32[RW]>,<HEXBUF[RW]>,<msg:STRING[RW]>\n\nOK\n") == 0);
prepare_input(test_case_1_ro);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+SETRO=<x:INT8[RO]>,<y:INT16[RO]>,<INT32[RO]>,<UINT8[RO]>,<UINT16[RO]>,<UINT32[RO]>,<HEX8[RO]>,<HEX16[RO]>,<HEX32[RO]>,<HEXBUF[RO]>,<msg:STRING[RO]>\n\nOK\n") == 0);
prepare_input(test_case_1_wo);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+SETWO=<x:INT8[WO]>,<y:INT16[WO]>,<INT32[WO]>,<UINT8[WO]>,<UINT16[WO]>,<UINT32[WO]>,<HEX8[WO]>,<HEX16[WO]>,<HEX32[WO]>,<HEXBUF[WO]>,<msg:STRING[WO]>\n\nOK\n") == 0);
prepare_input(test_case_2);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+TEST=<var:INT8[RW]>\ntest_desc\ntest\n\nOK\n\r\n+TEST2=<var:INT8[RW]>\r\ntest2_desc\r\n\r\nOK\r\n\nERROR\n") == 0);
prepare_input(test_case_3);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\ntest1\n\nOK\n\ntest1\n\nOK\n\r\n+ZZ3=\r\nzz3_desctest2\r\n\r\nOK\r\n") == 0);
return 0;
}

View File

@@ -0,0 +1,173 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char cmd_results[256];
static char ack_results[256];
static char const *input_text;
static size_t input_index;
static int ap_test(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
strcat(cmd_results, " test:");
strcat(cmd_results, cmd->name);
strcpy(data, "ap_test");
*data_size = strlen(data);
return 0;
}
static int ap_run(const struct cat_command *cmd)
{
strcat(cmd_results, " run:");
strcat(cmd_results, cmd->name);
return 0;
}
static int ap_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
strcat(cmd_results, " read:");
strcat(cmd_results, cmd->name);
strcpy(data, "ap_read");
*data_size = strlen(data);
return 0;
}
static int ap_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num)
{
strcat(cmd_results, " write:");
strcat(cmd_results, cmd->name);
assert(strcmp(data, "1") == 0);
return 0;
}
static struct cat_command cmds[] = {
{
.name = "AP1",
.test = ap_test,
.write = ap_write,
.read = ap_read,
.run = ap_run,
.only_test = true
},
{
.name = "AP2",
.test = ap_test,
.write = ap_write,
.read = ap_read,
.run = ap_run,
.only_test = false
},
};
static char buf[128];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf)
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
memset(ack_results, 0, sizeof(ack_results));
memset(cmd_results, 0, sizeof(cmd_results));
}
static const char test_case_1[] = "\nATAP1=?\n\nATAP1?\n\nATAP1=1\n\nATAP1\n";
static const char test_case_2[] = "\nATAP2=?\n\nATAP2?\n\nATAP2=1\n\nATAP2\n";
int main(int argc, char **argv)
{
struct cat_object at;
cat_init(&at, &desc, &iface, NULL);
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nap_test\n\nOK\n\nERROR\n\nERROR\n\nERROR\n") == 0);
assert(strcmp(cmd_results, " test:AP1") == 0);
prepare_input(test_case_2);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nap_test\n\nOK\n\nap_read\n\nOK\n\nOK\n\nOK\n") == 0);
assert(strcmp(cmd_results, " test:AP2 read:AP2 write:AP2 run:AP2") == 0);
return 0;
}

View File

@@ -0,0 +1,203 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char read_results[256];
static char var_read_results[256];
static char ack_results[256];
static char const *input_text;
static size_t input_index;
static int var_x, var_u1, var_u2;
static struct cat_object at;
static struct cat_command u_cmds[];
static cat_return_state cmd_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
cat_status s;
strcat(read_results, " read:");
strcat(read_results, cmd->name);
if (strcmp(cmd->name, "+CMD") == 0) {
s = cat_trigger_unsolicited_read(&at, &u_cmds[1]);
assert(s == CAT_STATUS_OK);
}
return CAT_RETURN_STATE_DATA_OK;
}
static int var_read(const struct cat_variable *var)
{
strcat(var_read_results, " var_read:");
strcat(var_read_results, var->name);
return 0;
}
static struct cat_variable u_vars[] = {
{
.name = "U1",
.type = CAT_VAR_INT_DEC,
.data = &var_u1,
.data_size = sizeof(var_u1),
.read = var_read
},
{
.name = "U2",
.type = CAT_VAR_INT_DEC,
.data = &var_u2,
.data_size = sizeof(var_u2),
.read = var_read
}
};
static struct cat_variable vars[] = {
{
.name = "X",
.type = CAT_VAR_INT_DEC,
.data = &var_x,
.data_size = sizeof(var_x),
.read = var_read
}
};
static struct cat_command cmds[] = {
{
.name = "+CMD",
.read = cmd_read,
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0]),
}
};
static struct cat_command u_cmds[] = {
{
.name = "+U1CMD",
.read = cmd_read,
.var = &u_vars[0],
.var_num = 1,
},
{
.name = "+U2CMD",
.read = cmd_read,
.var = &u_vars[1],
.var_num = 1,
}
};
static char buf[128];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf),
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
var_x = 1;
var_u1 = 2;
var_u2 = 3;
memset(ack_results, 0, sizeof(ack_results));
memset(read_results, 0, sizeof(read_results));
memset(var_read_results, 0, sizeof(var_read_results));
}
static const char test_case_1[] = "\nAT+CMD?\n";
int main(int argc, char **argv)
{
cat_status s;
cat_init(&at, &desc, &iface, NULL);
prepare_input(test_case_1);
s = cat_is_unsolicited_buffer_full(&at);
assert(s == CAT_STATUS_OK);
s = cat_trigger_unsolicited_event(&at, &u_cmds[0], CAT_CMD_TYPE_READ);
assert(s == CAT_STATUS_OK);
s = cat_is_unsolicited_buffer_full(&at);
assert(s == CAT_STATUS_ERROR_BUFFER_FULL);
s = cat_trigger_unsolicited_read(&at, &u_cmds[1]);
assert(s == CAT_STATUS_ERROR_BUFFER_FULL);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+U1CMD=2\n\n+CMD=1\n\n+U2CMD=3\n\nOK\n") == 0);
assert(strcmp(read_results, " read:+U1CMD read:+CMD read:+U2CMD") == 0);
assert(strcmp(var_read_results, " var_read:U1 var_read:X var_read:U2") == 0);
return 0;
}

View File

@@ -0,0 +1,238 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char read_results[256];
static char var_read_results[256];
static char ack_results[256];
static char const *input_text;
static size_t input_index;
static int var_x, var_u1, var_u2;
static struct cat_object at;
static struct cat_command u_cmds[];
static cat_return_state cmd_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
cat_status s;
strcat(read_results, " read:");
strcat(read_results, cmd->name);
if (strcmp(cmd->name, "+CMD") == 0) {
s = cat_trigger_unsolicited_read(&at, &u_cmds[1]);
assert(s == CAT_STATUS_OK);
}
return CAT_RETURN_STATE_DATA_OK;
}
static int var_read(const struct cat_variable *var)
{
strcat(var_read_results, " var_read:");
strcat(var_read_results, var->name);
return 0;
}
static struct cat_variable u_vars[] = {
{
.name = "U1",
.type = CAT_VAR_INT_DEC,
.data = &var_u1,
.data_size = sizeof(var_u1),
.read = var_read
},
{
.name = "U2",
.type = CAT_VAR_INT_DEC,
.data = &var_u2,
.data_size = sizeof(var_u2),
.read = var_read
}
};
static struct cat_variable vars[] = {
{
.name = "X",
.type = CAT_VAR_INT_DEC,
.data = &var_x,
.data_size = sizeof(var_x),
.read = var_read
}
};
static struct cat_command cmds[] = {
{
.name = "+CMD",
.read = cmd_read,
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0]),
}
};
static struct cat_command u_cmds[] = {
{
.name = "+U1CMD",
.read = cmd_read,
.var = &u_vars[0],
.var_num = 1,
},
{
.name = "+U2CMD",
.read = cmd_read,
.var = &u_vars[1],
.var_num = 1,
}
};
static char buf[128];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf),
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
var_x = 1;
var_u1 = 2;
var_u2 = 3;
memset(ack_results, 0, sizeof(ack_results));
memset(read_results, 0, sizeof(read_results));
memset(var_read_results, 0, sizeof(var_read_results));
}
static const char test_case_1[] = "\nAT+CMD?\n";
int main(int argc, char **argv)
{
cat_status s;
cat_init(&at, &desc, &iface, NULL);
prepare_input(test_case_1);
s = cat_is_unsolicited_buffer_full(&at);
assert(s == CAT_STATUS_OK);
s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_READ);
assert(s == CAT_STATUS_OK);
s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_NONE);
assert(s == CAT_STATUS_OK);
s = cat_trigger_unsolicited_event(&at, &u_cmds[0], CAT_CMD_TYPE_READ);
assert(s == CAT_STATUS_OK);
s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_READ);
assert(s == CAT_STATUS_BUSY);
s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_TEST);
assert(s == CAT_STATUS_OK);
s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_NONE);
assert(s == CAT_STATUS_BUSY);
s = cat_is_unsolicited_buffer_full(&at);
assert(s == CAT_STATUS_OK);
s = cat_trigger_unsolicited_event(&at, &u_cmds[1], CAT_CMD_TYPE_READ);
assert(s == CAT_STATUS_OK);
s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_READ);
assert(s == CAT_STATUS_BUSY);
s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_TEST);
assert(s == CAT_STATUS_OK);
s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_NONE);
assert(s == CAT_STATUS_BUSY);
s = cat_is_unsolicited_event_buffered(&at, &u_cmds[1], CAT_CMD_TYPE_READ);
assert(s == CAT_STATUS_BUSY);
s = cat_is_unsolicited_event_buffered(&at, &u_cmds[1], CAT_CMD_TYPE_TEST);
assert(s == CAT_STATUS_OK);
s = cat_is_unsolicited_event_buffered(&at, &u_cmds[1], CAT_CMD_TYPE_NONE);
assert(s == CAT_STATUS_BUSY);
s = cat_is_unsolicited_buffer_full(&at);
assert(s == CAT_STATUS_ERROR_BUFFER_FULL);
s = cat_trigger_unsolicited_read(&at, &u_cmds[1]);
assert(s == CAT_STATUS_ERROR_BUFFER_FULL);
s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_READ);
assert(s == CAT_STATUS_BUSY);
s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_TEST);
assert(s == CAT_STATUS_OK);
s = cat_is_unsolicited_event_buffered(&at, &u_cmds[1], CAT_CMD_TYPE_NONE);
assert(s == CAT_STATUS_BUSY);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+U1CMD=2\n\n+CMD=1\n\n+U2CMD=3\n\nOK\n\n+U2CMD=3\n") == 0);
assert(strcmp(read_results, " read:+U1CMD read:+CMD read:+U2CMD read:+U2CMD") == 0);
assert(strcmp(var_read_results, " var_read:U1 var_read:X var_read:U2 var_read:U2") == 0);
s = cat_is_unsolicited_buffer_full(&at);
assert(s == CAT_STATUS_OK);
return 0;
}

View File

@@ -0,0 +1,211 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char read_results[256];
static char var_read_results[256];
static char ack_results[256];
static char const *input_text;
static size_t input_index;
static int var_x, var_u1;
static struct cat_object at;
static struct cat_command u_cmds[];
static cat_return_state cmd_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
cat_status s;
strcat(read_results, " read:");
strcat(read_results, cmd->name);
return CAT_RETURN_STATE_DATA_OK;
}
static int var_read(const struct cat_variable *var)
{
strcat(var_read_results, " var_read:");
strcat(var_read_results, var->name);
return 0;
}
static struct cat_variable u_vars[] = {
{
.name = "U1",
.type = CAT_VAR_INT_DEC,
.data = &var_u1,
.data_size = sizeof(var_u1),
.read = var_read
}
};
static struct cat_variable vars[] = {
{
.name = "X",
.type = CAT_VAR_INT_DEC,
.data = &var_x,
.data_size = sizeof(var_x),
.read = var_read
}
};
static struct cat_command cmds[] = {
{
.name = "+CMD",
.read = cmd_read,
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0]),
}
};
static struct cat_command u_cmds[] = {
{
.name = "+UCMD",
.read = cmd_read,
.var = u_vars,
.var_num = sizeof(u_vars) / sizeof(u_vars[0]),
}
};
static char buf[128];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf),
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
var_x = 1;
var_u1 = 2;
memset(ack_results, 0, sizeof(ack_results));
memset(read_results, 0, sizeof(read_results));
memset(var_read_results, 0, sizeof(var_read_results));
}
static const char test_case_1[] = "\nAT+CMD?\n";
int main(int argc, char **argv)
{
cat_status s;
int events = 4;
struct cat_command const *cmd;
cat_init(&at, &desc, &iface, NULL);
prepare_input(test_case_1);
cmd = cat_get_processed_command(&at, CAT_FSM_TYPE_ATCMD);
assert(cmd == NULL);
cmd = cat_get_processed_command(&at, CAT_FSM_TYPE_UNSOLICITED);
assert(cmd == NULL);
s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_READ);
assert(s == CAT_STATUS_OK);
s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_NONE);
assert(s == CAT_STATUS_OK);
while (events > 0) {
s = cat_is_unsolicited_buffer_full(&at);
cmd = cat_get_processed_command(&at, CAT_FSM_TYPE_UNSOLICITED);
if ((s == CAT_STATUS_OK) && (cmd == NULL)) {
var_u1 = events;
s = cat_trigger_unsolicited_event(&at, &u_cmds[0], CAT_CMD_TYPE_READ);
assert(s == CAT_STATUS_OK);
events--;
} else {
assert(cmd == &u_cmds[0]);
s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_READ);
assert(s == CAT_STATUS_BUSY);
s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_TEST);
assert(s == CAT_STATUS_OK);
s = cat_is_unsolicited_event_buffered(&at, &u_cmds[0], CAT_CMD_TYPE_NONE);
assert(s == CAT_STATUS_BUSY);
}
s = cat_service(&at);
assert(s == CAT_STATUS_BUSY);
}
while (cat_service(&at) != 0) {};
cmd = cat_get_processed_command(&at, CAT_FSM_TYPE_ATCMD);
assert(cmd == NULL);
cmd = cat_get_processed_command(&at, CAT_FSM_TYPE_UNSOLICITED);
assert(cmd == NULL);
assert(strcmp(ack_results, "\n+UCMD=4\n\n+CMD=1\n\n+UCMD=3\n\nOK\n\n+UCMD=2\n\n+UCMD=1\n") == 0);
assert(strcmp(read_results, " read:+UCMD read:+CMD read:+UCMD read:+UCMD read:+UCMD") == 0);
assert(strcmp(var_read_results, " var_read:U1 var_read:X var_read:U1 var_read:U1 var_read:U1") == 0);
return 0;
}

View File

@@ -0,0 +1,189 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char read_results[256];
static char ack_results[256];
static char const *input_text;
static size_t input_index;
static int var_x, var_u1, var_u2;
static struct cat_object at;
static struct cat_command u_cmds[];
static cat_return_state cmd_test(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
cat_status s;
strcat(read_results, " test:");
strcat(read_results, cmd->name);
if (strcmp(cmd->name, "+CMD") == 0) {
s = cat_trigger_unsolicited_test(&at, &u_cmds[1]);
assert(s == CAT_STATUS_OK);
}
return CAT_RETURN_STATE_DATA_OK;
}
static struct cat_variable u_vars[] = {
{
.name = "U1",
.type = CAT_VAR_INT_DEC,
.data = &var_u1,
.data_size = sizeof(var_u1)
},
{
.name = "U2",
.type = CAT_VAR_INT_DEC,
.data = &var_u2,
.data_size = sizeof(var_u2)
}
};
static struct cat_variable vars[] = {
{
.name = "X",
.type = CAT_VAR_INT_DEC,
.data = &var_x,
.data_size = sizeof(var_x)
}
};
static struct cat_command cmds[] = {
{
.name = "+CMD",
.test = cmd_test,
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0]),
}
};
static struct cat_command u_cmds[] = {
{
.name = "+U1CMD",
.test = cmd_test,
.var = &u_vars[0],
.var_num = 1,
},
{
.name = "+U2CMD",
.test = cmd_test,
.var = &u_vars[1],
.var_num = 1,
}
};
static char buf[128];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf),
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
var_x = 1;
var_u1 = 2;
var_u2 = 3;
memset(ack_results, 0, sizeof(ack_results));
memset(read_results, 0, sizeof(read_results));
}
static const char test_case_1[] = "\nAT+CMD=?\n";
int main(int argc, char **argv)
{
cat_status s;
cat_init(&at, &desc, &iface, NULL);
prepare_input(test_case_1);
s = cat_is_unsolicited_buffer_full(&at);
assert(s == CAT_STATUS_OK);
s = cat_trigger_unsolicited_event(&at, &u_cmds[0], CAT_CMD_TYPE_TEST);
assert(s == CAT_STATUS_OK);
s = cat_is_unsolicited_buffer_full(&at);
assert(s == CAT_STATUS_ERROR_BUFFER_FULL);
s = cat_trigger_unsolicited_test(&at, &u_cmds[1]);
assert(s == CAT_STATUS_ERROR_BUFFER_FULL);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+U1CMD=<U1:INT32[RW]>\n\n+CMD=<X:INT32[RW]>\n\n+U2CMD=<U2:INT32[RW]>\n\nOK\n") == 0);
assert(strcmp(read_results, " test:+U1CMD test:+CMD test:+U2CMD") == 0);
return 0;
}

View File

@@ -0,0 +1,545 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char ack_results[256];
static int8_t var1;
static int8_t var2;
static int8_t var3;
static char const *input_text;
static size_t input_index;
static int var2_write_cntr;
static int var3_read_cntr;
static int8_t var_int8;
static int16_t var_int16;
static int32_t var_int32;
static uint8_t var_uint8;
static uint16_t var_uint16;
static uint32_t var_uint32;
static uint8_t var_hex8;
static uint16_t var_hex16;
static uint32_t var_hex32;
static uint8_t var_buf[4];
static char var_string[16];
static int cmd_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num)
{
return 0;
}
static int cmd_read(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
return 0;
}
static int cmd_test(const struct cat_command *cmd, uint8_t *data, size_t *data_size, const size_t max_data_size)
{
return 0;
}
static int cmd_run(const struct cat_command *cmd)
{
return 0;
}
static int var1_write(const struct cat_variable *var, size_t write_size)
{
return 0;
}
static int var1_read(const struct cat_variable *var)
{
return 0;
}
static int var2_write(const struct cat_variable *var, size_t write_size)
{
var2_write_cntr++;
return 0;
}
static int var2_read(const struct cat_variable *var)
{
return 0;
}
static int var3_write(const struct cat_variable *var, size_t write_size)
{
return 0;
}
static int var3_read(const struct cat_variable *var)
{
var3_read_cntr++;
return 0;
}
static int print_cmd_list(const struct cat_command *cmd)
{
return CAT_RETURN_STATE_PRINT_CMD_LIST_OK;
}
static struct cat_variable vars_ro[] = {
{
.type = CAT_VAR_INT_DEC,
.data = &var2,
.data_size = sizeof(var2),
.write = var2_write,
.read = var2_read,
.access = CAT_VAR_ACCESS_READ_ONLY
}
};
static struct cat_variable vars_wo[] = {
{
.type = CAT_VAR_INT_DEC,
.data = &var3,
.data_size = sizeof(var3),
.write = var3_write,
.read = var3_read,
.access = CAT_VAR_ACCESS_WRITE_ONLY
}
};
static struct cat_variable vars[] = {
{
.type = CAT_VAR_INT_DEC,
.data = &var1,
.data_size = sizeof(var1),
.write = var1_write,
.read = var1_read,
.access = CAT_VAR_ACCESS_READ_WRITE
},
{
.type = CAT_VAR_INT_DEC,
.data = &var2,
.data_size = sizeof(var2),
.write = var2_write,
.read = var2_read,
.access = CAT_VAR_ACCESS_READ_ONLY
},
{
.type = CAT_VAR_INT_DEC,
.data = &var3,
.data_size = sizeof(var3),
.write = var3_write,
.read = var3_read,
.access = CAT_VAR_ACCESS_WRITE_ONLY
}
};
static struct cat_variable vars_misc_ro[] = {
{
.type = CAT_VAR_INT_DEC,
.data = &var1,
.data_size = sizeof(var1),
.access = CAT_VAR_ACCESS_READ_WRITE
},
{
.type = CAT_VAR_INT_DEC,
.data = &var_int8,
.data_size = sizeof(var_int8),
.name = "x",
.access = CAT_VAR_ACCESS_READ_ONLY
},
{
.type = CAT_VAR_INT_DEC,
.data = &var_int16,
.data_size = sizeof(var_int16),
.name = "y",
.access = CAT_VAR_ACCESS_READ_ONLY
},
{
.type = CAT_VAR_INT_DEC,
.data = &var_int32,
.data_size = sizeof(var_int32),
.access = CAT_VAR_ACCESS_READ_ONLY
},
{
.type = CAT_VAR_UINT_DEC,
.data = &var_uint8,
.data_size = sizeof(var_uint8),
.access = CAT_VAR_ACCESS_READ_ONLY
},
{
.type = CAT_VAR_UINT_DEC,
.data = &var_uint16,
.data_size = sizeof(var_uint16),
.access = CAT_VAR_ACCESS_READ_ONLY
},
{
.type = CAT_VAR_UINT_DEC,
.data = &var_uint32,
.data_size = sizeof(var_uint32),
.access = CAT_VAR_ACCESS_READ_ONLY
},
{
.type = CAT_VAR_NUM_HEX,
.data = &var_hex8,
.data_size = sizeof(var_hex8),
.access = CAT_VAR_ACCESS_READ_ONLY
},
{
.type = CAT_VAR_NUM_HEX,
.data = &var_hex16,
.data_size = sizeof(var_hex16),
.access = CAT_VAR_ACCESS_READ_ONLY
},
{
.type = CAT_VAR_NUM_HEX,
.data = &var_hex32,
.data_size = sizeof(var_hex32),
.access = CAT_VAR_ACCESS_READ_ONLY
},
{
.type = CAT_VAR_BUF_HEX,
.data = &var_buf,
.data_size = sizeof(var_buf),
.access = CAT_VAR_ACCESS_READ_ONLY
},
{
.type = CAT_VAR_BUF_STRING,
.data = &var_string,
.data_size = sizeof(var_string),
.name = "msg",
.access = CAT_VAR_ACCESS_READ_ONLY
}
};
static struct cat_variable vars_misc_wo[] = {
{
.type = CAT_VAR_INT_DEC,
.data = &var1,
.data_size = sizeof(var1),
.access = CAT_VAR_ACCESS_READ_WRITE
},
{
.type = CAT_VAR_INT_DEC,
.data = &var_int8,
.data_size = sizeof(var_int8),
.name = "x",
.access = CAT_VAR_ACCESS_WRITE_ONLY
},
{
.type = CAT_VAR_INT_DEC,
.data = &var_int16,
.data_size = sizeof(var_int16),
.name = "y",
.access = CAT_VAR_ACCESS_WRITE_ONLY
},
{
.type = CAT_VAR_INT_DEC,
.data = &var_int32,
.data_size = sizeof(var_int32),
.access = CAT_VAR_ACCESS_WRITE_ONLY
},
{
.type = CAT_VAR_UINT_DEC,
.data = &var_uint8,
.data_size = sizeof(var_uint8),
.access = CAT_VAR_ACCESS_WRITE_ONLY
},
{
.type = CAT_VAR_UINT_DEC,
.data = &var_uint16,
.data_size = sizeof(var_uint16),
.access = CAT_VAR_ACCESS_WRITE_ONLY
},
{
.type = CAT_VAR_UINT_DEC,
.data = &var_uint32,
.data_size = sizeof(var_uint32),
.access = CAT_VAR_ACCESS_WRITE_ONLY
},
{
.type = CAT_VAR_NUM_HEX,
.data = &var_hex8,
.data_size = sizeof(var_hex8),
.access = CAT_VAR_ACCESS_WRITE_ONLY
},
{
.type = CAT_VAR_NUM_HEX,
.data = &var_hex16,
.data_size = sizeof(var_hex16),
.access = CAT_VAR_ACCESS_WRITE_ONLY
},
{
.type = CAT_VAR_NUM_HEX,
.data = &var_hex32,
.data_size = sizeof(var_hex32),
.access = CAT_VAR_ACCESS_WRITE_ONLY
},
{
.type = CAT_VAR_BUF_HEX,
.data = &var_buf,
.data_size = sizeof(var_buf),
.access = CAT_VAR_ACCESS_WRITE_ONLY
},
{
.type = CAT_VAR_BUF_STRING,
.data = &var_string,
.data_size = sizeof(var_string),
.name = "msg",
.access = CAT_VAR_ACCESS_WRITE_ONLY
}
};
static struct cat_command cmds[] = {
{
.name = "+VRW",
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0])
},
{
.name = "+VRO",
.var = vars_ro,
.var_num = sizeof(vars_ro) / sizeof(vars_ro[0])
},
{
.name = "+VWO",
.var = vars_wo,
.var_num = sizeof(vars_wo) / sizeof(vars_wo[0])
},
{
.name = "+MRO",
.var = vars_misc_ro,
.var_num = sizeof(vars_misc_ro) / sizeof(vars_misc_ro[0])
},
{
.name = "+MWO",
.var = vars_misc_wo,
.var_num = sizeof(vars_misc_wo) / sizeof(vars_misc_wo[0])
},
{
.name = "#HELP",
.run = print_cmd_list,
}
};
static char buf[256];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf),
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
memset(ack_results, 0, sizeof(ack_results));
}
static void print_raw_text(char *p)
{
while (*p != '\0') {
if (*p == '\n') {
printf("\\n");
} else {
putchar(*p);
}
p++;
}
}
int main(int argc, char **argv)
{
struct cat_object at;
cat_init(&at, &desc, &iface, NULL);
prepare_input("\nAT#HELP\n");
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nAT+VRW?\nAT+VRW=\nAT+VRW=?\n\nAT+VRO?\nAT+VRO=?\n\nAT+VWO=\nAT+VWO=?\n\nAT+MRO?\nAT+MRO=\nAT+MRO=?\n\nAT+MWO?\nAT+MWO=\nAT+MWO=?\n\nAT#HELP\n\nOK\n") == 0);
prepare_input("\nAT+VRW=?\n");
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+VRW=<INT8[RW]>,<INT8[RO]>,<INT8[WO]>\n\nOK\n") == 0);
prepare_input("\nAT+VRO=?\n");
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+VRO=<INT8[RO]>\n\nOK\n") == 0);
prepare_input("\nAT+VWO=?\n");
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+VWO=<INT8[WO]>\n\nOK\n") == 0);
var2 = 1;
prepare_input("\nAT+VRO=1\n");
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nERROR\n") == 0);
assert(var2 == 1);
var3 = 3;
prepare_input("\nAT+VWO?\n");
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nERROR\n") == 0);
assert(var3 == 3);
var1 = -1;
var2 = -2;
var3 = -3;
var2_write_cntr = 0;
var3_read_cntr = 0;
prepare_input("\nAT+VRW?\n");
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+VRW=-1,-2,0\n\nOK\n") == 0);
assert(var2_write_cntr == 0);
assert(var3_read_cntr == 1);
prepare_input("\nAT+VRW=1,2,3\n");
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n") == 0);
assert(var2_write_cntr == 1);
assert(var3_read_cntr == 1);
assert(var1 == 1);
assert(var2 == -2);
assert(var3 == 3);
var1 = 100;
var_int8 = 1;
var_int16 = 2;
var_int32 = 3;
var_uint8 = 4;
var_uint16 = 5;
var_uint32 = 6;
var_hex8 = 7;
var_hex16 = 8;
var_hex32 = 9;
var_buf[0] = 0x10;
var_buf[1] = 0x11;
var_buf[2] = 0x12;
var_buf[3] = 0x13;
strcpy(var_string, "test_string");
prepare_input("\nAT+MWO?\n");
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+MWO=100,0,0,0,0,0,0,0x00,0x0000,0x00000000,00000000,\"\"\n\nOK\n") == 0);
prepare_input("\nAT+MWO=1,2,3,4,5,6,7,0x08,0x0009,0x0000000A,01020304,\"abc\"\n");
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n") == 0);
assert(var1 == 1);
assert(var_int8 == 2);
assert(var_int16 == 3);
assert(var_int32 == 4);
assert(var_uint8 == 5);
assert(var_uint16 == 6);
assert(var_uint32 == 7);
assert(var_hex8 == 8);
assert(var_hex16 == 9);
assert(var_hex32 == 10);
assert(var_buf[0] == 0x01);
assert(var_buf[1] == 0x02);
assert(var_buf[2] == 0x03);
assert(var_buf[3] == 0x04);
assert(strcmp(var_string, "abc") == 0);
prepare_input("\nAT+MRO?\n");
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\n+MRO=1,2,3,4,5,6,7,0x08,0x0009,0x0000000A,01020304,\"abc\"\n\nOK\n") == 0);
prepare_input("\nAT+MRO=2,0,0,0,0,0,0,0x00,0x0000,0x00000000,00000000,\"cba\"\n");
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n") == 0);
assert(var1 == 2);
assert(var_int8 == 2);
assert(var_int16 == 3);
assert(var_int32 == 4);
assert(var_uint8 == 5);
assert(var_uint16 == 6);
assert(var_uint32 == 7);
assert(var_hex8 == 8);
assert(var_hex16 == 9);
assert(var_hex32 == 10);
assert(var_buf[0] == 0x01);
assert(var_buf[1] == 0x02);
assert(var_buf[2] == 0x03);
assert(var_buf[3] == 0x04);
assert(strcmp(var_string, "abc") == 0);
return 0;
}

View File

@@ -0,0 +1,166 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char run_results[256];
static char write_results[256];
static char ack_results[256];
static char const *input_text;
static size_t input_index;
static int a_run(const struct cat_command *cmd)
{
strcat(run_results, " A_");
strcat(run_results, cmd->name);
return 0;
}
static int a_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num)
{
strcat(write_results, " A:");
strncat(write_results, data, data_size);
assert(args_num == 0);
return 0;
}
static int ap_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num)
{
strcat(write_results, " AP:");
strncat(write_results, data, data_size);
assert(args_num == 0);
return 0;
}
static int test_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num)
{
strcat(write_results, " +TEST:");
strncat(write_results, data, data_size);
assert(args_num == 0);
return -1;
}
static struct cat_command cmds[] = {
{
.name = "A",
.write = a_write,
.run = a_run
},
{
.name = "AP",
.write = ap_write
},
{
.name = "+TEST",
.write = test_write
},
{
.name = "+EMPTY"
}
};
static char buf[128];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf)
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
memset(run_results, 0, sizeof(run_results));
memset(ack_results, 0, sizeof(ack_results));
memset(write_results, 0, sizeof(write_results));
}
static const char test_case_1[] = "\nAT\nAT+\nAT+?\nATA=123\r\nATA=\nATAP?\nATAP=11\r22\r\nAT+TEST=456\nAT+te=789\nAT+e=1\nAT+empTY=2\r\nATA\n";
int main(int argc, char **argv)
{
struct cat_object at;
cat_init(&at, &desc, &iface, NULL);
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n\nERROR\n\nERROR\n\r\nOK\r\n\nOK\n\nERROR\n\r\nOK\r\n\nERROR\n\nERROR\n\nERROR\n\r\nERROR\r\n\nOK\n") == 0);
assert(strcmp(run_results, " A_A") == 0);
assert(strcmp(write_results, " A:123 A: AP:1122 +TEST:456 +TEST:789") == 0);
return 0;
}

View File

@@ -0,0 +1,174 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char write_results[256];
static char ack_results[256];
static uint8_t var[4];
static size_t var_write_size[4];
static int var_write_size_index;
static char const *input_text;
static size_t input_index;
static int cmd_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num)
{
strcat(write_results, " CMD:");
strncat(write_results, data, data_size);
return 0;
}
static int var_write(const struct cat_variable *var, size_t write_size)
{
var_write_size[var_write_size_index++] = write_size;
return 0;
}
static struct cat_variable vars[] = {
{
.type = CAT_VAR_BUF_HEX,
.data = var,
.data_size = sizeof(var),
.write = var_write
}
};
static struct cat_command cmds[] = {
{
.name = "+SET",
.write = cmd_write,
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0])
}
};
static char buf[128];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf)
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
memset(var, 0, sizeof(var));
memset(var_write_size, 0, sizeof(var_write_size));
var_write_size_index = 0;
memset(ack_results, 0, sizeof(ack_results));
memset(write_results, 0, sizeof(write_results));
}
static const char test_case_1[] = "\nAT+SET=0\nAT+SET=aa\nAT+SET=001\nAT+SET=12345678\nAT+SET=ffAA\n";
static const char test_case_2[] = "\nAT+SET=0x11\nAT+SET=11\nAT+SET=-1\nAT+SET=87654321\nAT+SET=0001\nAT+SET=1122334455\n";
int main(int argc, char **argv)
{
struct cat_object at;
cat_init(&at, &desc, &iface, NULL);
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nERROR\n\nOK\n\nERROR\n\nOK\n\nOK\n") == 0);
assert(strcmp(write_results, " CMD:aa CMD:12345678 CMD:ffAA") == 0);
assert(var[0] == 0xFF);
assert(var[1] == 0xAA);
assert(var[2] == 0x56);
assert(var[3] == 0x78);
assert(var_write_size[0] == 1);
assert(var_write_size[1] == 4);
assert(var_write_size[2] == 2);
assert(var_write_size[3] == 0);
prepare_input(test_case_2);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nERROR\n\nOK\n\nERROR\n\nOK\n\nOK\n\nERROR\n") == 0);
assert(strcmp(write_results, " CMD:11 CMD:87654321 CMD:0001") == 0);
assert(var[0] == 0x11);
assert(var[1] == 0x22);
assert(var[2] == 0x33);
assert(var[3] == 0x44);
assert(var_write_size[0] == 1);
assert(var_write_size[1] == 4);
assert(var_write_size[2] == 2);
assert(var_write_size[3] == 0);
return 0;
}

View File

@@ -0,0 +1,212 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char write_results[256];
static char ack_results[256];
static uint8_t var1, var1b;
static uint16_t var2, var2b;
static uint32_t var3, var3b;
static char const *input_text;
static size_t input_index;
static int cmd_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num)
{
strcat(write_results, " CMD:");
strncat(write_results, data, data_size);
return 0;
}
static int var1_write(const struct cat_variable *var, size_t write_size)
{
assert(write_size == 1);
var1b = *(uint8_t*)(var->data);
return 0;
}
static int var2_write(const struct cat_variable *var, size_t write_size)
{
assert(write_size == 2);
var2b = *(uint16_t*)(var->data);
return 0;
}
static int var3_write(const struct cat_variable *var, size_t write_size)
{
assert(write_size == 4);
var3b = *(uint32_t*)(var->data);
return 0;
}
static struct cat_variable vars[] = {
{
.type = CAT_VAR_NUM_HEX,
.data = &var1,
.data_size = sizeof(var1),
.write = var1_write
},
{
.type = CAT_VAR_NUM_HEX,
.data = &var2,
.data_size = sizeof(var2),
.write = var2_write
},
{
.type = CAT_VAR_NUM_HEX,
.data = &var3,
.data_size = sizeof(var3),
.write = var3_write
}
};
static struct cat_command cmds[] = {
{
.name = "+SET",
.write = cmd_write,
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0])
}
};
static char buf[128];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf)
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
var1 = 1;
var2 = 2;
var3 = 3;
var1b = 10;
var2b = 20;
var3b = 30;
memset(ack_results, 0, sizeof(ack_results));
memset(write_results, 0, sizeof(write_results));
}
static const char test_case_1[] = "\nAT+SET=0\nAT+SET=0x0\nAT+SET=0x01\nAT+SET=0x0ff\nAT+SET=0x100\n";
static const char test_case_2[] = "\nAT+SET=0x,0x00\nAT+SET=0x1,0x00\nAT+SET=0x2,0xFFf\nAT+SET=0x3,0xFFFF\nAT+SET=0x4,0xFFFFF\n";
static const char test_case_3[] = "\nAT+SET=0x0,0x0,0\nAT+SET=0x0,0x0,0x0000000000000\nAT+SET=0x0,0x0,0x1\nAT+SET=0x0,0x0,0xffffFFFF\nAT+SET=0x10,0x20,0x100000000\n";
int main(int argc, char **argv)
{
struct cat_object at;
cat_init(&at, &desc, &iface, NULL);
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nERROR\n\nOK\n\nOK\n\nOK\n\nERROR\n") == 0);
assert(strcmp(write_results, " CMD:0x0 CMD:0x01 CMD:0x0ff") == 0);
assert(var1 == 255);
assert(var1b == var1);
assert(var2 == 2);
assert(var2b == 20);
assert(var3 == 3);
assert(var3b == 30);
prepare_input(test_case_2);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nERROR\n\nOK\n\nOK\n\nOK\n\nERROR\n") == 0);
assert(strcmp(write_results, " CMD:0x1,0x00 CMD:0x2,0xFFf CMD:0x3,0xFFFF") == 0);
assert(var1 == 4);
assert(var1b == var1);
assert(var2 == 0xFFFF);
assert(var2b == var2);
assert(var3 == 3);
assert(var3b == 30);
prepare_input(test_case_3);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nERROR\n\nOK\n\nOK\n\nOK\n\nERROR\n") == 0);
assert(strcmp(write_results, " CMD:0x0,0x0,0x0000000000000 CMD:0x0,0x0,0x1 CMD:0x0,0x0,0xffffFFFF") == 0);
assert(var1 == 0x10);
assert(var1b == var1);
assert(var2 == 0x20);
assert(var2b == var2);
assert(var3 == 0xFFFFFFFF);
assert(var3b == var3);
return 0;
}

View File

@@ -0,0 +1,212 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char write_results[256];
static char ack_results[256];
static int8_t var1, var1b;
static int16_t var2, var2b;
static int32_t var3, var3b;
static char const *input_text;
static size_t input_index;
static int cmd_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num)
{
strcat(write_results, " CMD:");
strncat(write_results, data, data_size);
return 0;
}
static int var1_write(const struct cat_variable *var, size_t write_size)
{
assert(write_size == 1);
var1b = *(int8_t*)(var->data);
return 0;
}
static int var2_write(const struct cat_variable *var, size_t write_size)
{
assert(write_size == 2);
var2b = *(int16_t*)(var->data);
return 0;
}
static int var3_write(const struct cat_variable *var, size_t write_size)
{
assert(write_size == 4);
var3b = *(int32_t*)(var->data);
return 0;
}
static struct cat_variable vars[] = {
{
.type = CAT_VAR_INT_DEC,
.data = &var1,
.data_size = sizeof(var1),
.write = var1_write
},
{
.type = CAT_VAR_INT_DEC,
.data = &var2,
.data_size = sizeof(var2),
.write = var2_write
},
{
.type = CAT_VAR_INT_DEC,
.data = &var3,
.data_size = sizeof(var3),
.write = var3_write
}
};
static struct cat_command cmds[] = {
{
.name = "+SET",
.write = cmd_write,
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0])
}
};
static char buf[128];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf),
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
var1 = 1;
var2 = 2;
var3 = 3;
var1b = -1;
var2b = -2;
var3b = -3;
memset(ack_results, 0, sizeof(ack_results));
memset(write_results, 0, sizeof(write_results));
}
static const char test_case_1[] = "\nAT+SET=-128\nAT+SET=-129\nAT+SET=127\nAT+SET=128\n";
static const char test_case_2[] = "\nAT+SET=-128,-32768\nAT+SET=-128,-40000\nAT+SET=-128,32767\nAT+SET=-100,40000\n";
static const char test_case_3[] = "\nAT+SET=0,0,-2147483648\nAT+SET=0,0,-2147483649\nAT+SET=1,1,2147483647\nAT+SET=2,2,2147483648\n";
int main(int argc, char **argv)
{
struct cat_object at;
cat_init(&at, &desc, &iface, NULL);
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n\nERROR\n\nOK\n\nERROR\n") == 0);
assert(strcmp(write_results, " CMD:-128 CMD:127") == 0);
assert(var1 == 127);
assert(var1b == var1);
assert(var2 == 2);
assert(var2b == -2);
assert(var3 == 3);
assert(var3b == -3);
prepare_input(test_case_2);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n\nERROR\n\nOK\n\nERROR\n") == 0);
assert(strcmp(write_results, " CMD:-128,-32768 CMD:-128,32767") == 0);
assert(var1 == -100);
assert(var1b == var1);
assert(var2 == 32767);
assert(var2b == var2);
assert(var3 == 3);
assert(var3b == -3);
prepare_input(test_case_3);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n\nERROR\n\nOK\n\nERROR\n") == 0);
assert(strcmp(write_results, " CMD:0,0,-2147483648 CMD:1,1,2147483647") == 0);
assert(var1 == 2);
assert(var1b == var1);
assert(var2 == 2);
assert(var2b == var2);
assert(var3 == 2147483647);
assert(var3b == var3);
return 0;
}

View File

@@ -0,0 +1,234 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char write_results[256];
static char ack_results[256];
static int8_t var1, var2, var3;
static int8_t var1b, var2b, var3b;
static char const *input_text;
static size_t input_index;
static int cmd_write1(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num)
{
char tmp[32];
sprintf(tmp, " CMD1_%ld:", args_num);
strcat(write_results, tmp);
strncat(write_results, data, data_size);
return 0;
}
static int cmd_write3(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num)
{
char tmp[32];
sprintf(tmp, " CMD3_%ld:", args_num);
strcat(write_results, tmp);
strncat(write_results, data, data_size);
return 0;
}
static int var1_write(const struct cat_variable *var, size_t write_size)
{
assert(write_size == 1);
var1b = *(int8_t*)(var->data);
return 0;
}
static int var2_write(const struct cat_variable *var, size_t write_size)
{
assert(write_size == 1);
var2b = *(int8_t*)(var->data);
return 0;
}
static int var3_write(const struct cat_variable *var, size_t write_size)
{
assert(write_size == 1);
var3b = *(int8_t*)(var->data);
return 0;
}
static struct cat_variable vars[] = {
{
.type = CAT_VAR_INT_DEC,
.data = &var1,
.data_size = sizeof(var1),
.write = var1_write
},
{
.type = CAT_VAR_INT_DEC,
.data = &var2,
.data_size = sizeof(var2),
.write = var2_write
},
{
.type = CAT_VAR_INT_DEC,
.data = &var3,
.data_size = sizeof(var3),
.write = var3_write
}
};
static struct cat_command cmds[] = {
{
.name = "+SET1",
.write = cmd_write1,
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0])
},
{
.name = "+SET3",
.write = cmd_write3,
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0])
},
{
.name = "+SETALL",
.write = cmd_write3,
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0]),
.need_all_vars = true
}
};
static char buf[128];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf)
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
var1 = 1;
var2 = 2;
var3 = 3;
memset(ack_results, 0, sizeof(ack_results));
memset(write_results, 0, sizeof(write_results));
}
static const char test_case_1[] = "\nAT+SET=-10,-20,-30\r\nAT+SET1=-10,-20,-30\r\nAT+SET1=-1\r\n";
static const char test_case_2[] = "\nAT+SET3=-1,-2,-3,0\nAT+SET3=-1,-2,-3\nAT+SET3=-100\n";
static const char test_case_3[] = "\nAT+SETALL=-11,-22,-33\nAT+SETALL=-1,-2,-3\nAT+SETALL=100\n";
int main(int argc, char **argv)
{
struct cat_object at;
cat_init(&at, &desc, &iface, NULL);
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\r\nERROR\r\n\r\nOK\r\n\r\nOK\r\n") == 0);
assert(strcmp(write_results, " CMD1_3:-10,-20,-30 CMD1_1:-1") == 0);
assert(var1 == -1);
assert(var2 == -20);
assert(var3 == -30);
assert(var1b == -1);
assert(var2b == -20);
assert(var3b == -30);
prepare_input(test_case_2);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nERROR\n\nOK\n\nOK\n") == 0);
assert(strcmp(write_results, " CMD3_3:-1,-2,-3 CMD3_1:-100") == 0);
assert(var1 == -100);
assert(var2 == -2);
assert(var3 == -3);
assert(var1b == -100);
assert(var2b == -2);
assert(var3b == -3);
prepare_input(test_case_3);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nOK\n\nOK\n\nERROR\n") == 0);
assert(strcmp(write_results, " CMD3_3:-11,-22,-33 CMD3_3:-1,-2,-3") == 0);
assert(var1 == 100);
assert(var2 == -2);
assert(var3 == -3);
assert(var1b == 100);
assert(var2b == -2);
assert(var3b == -3);
return 0;
}

View File

@@ -0,0 +1,168 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char write_results[256];
static char ack_results[256];
static uint8_t var[8];
static size_t var_write_size[4];
static int var_write_size_index;
static char const *input_text;
static size_t input_index;
static int cmd_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num)
{
strcat(write_results, " CMD:");
strncat(write_results, data, data_size);
return 0;
}
static int var_write(const struct cat_variable *var, size_t write_size)
{
var_write_size[var_write_size_index++] = write_size;
return 0;
}
static struct cat_variable vars[] = {
{
.type = CAT_VAR_BUF_STRING,
.data = var,
.data_size = sizeof(var),
.write = var_write
}
};
static struct cat_command cmds[] = {
{
.name = "+SET",
.write = cmd_write,
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0])
}
};
static char buf[128];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf)
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
memset(var, 0, sizeof(var));
memset(var_write_size, 0, sizeof(var_write_size));
var_write_size_index = 0;
memset(ack_results, 0, sizeof(ack_results));
memset(write_results, 0, sizeof(write_results));
}
static const char test_case_1[] = "\nAT+SET=0\nAT+SET=\"\\\"abcd\\\"\"\nAT+SET=\"\"a\nAT+SET=\"1122334\"\nAT+SET=\"t\"\r\n";
static const char test_case_2[] = "\nAT+SET=\"12345678\"\nAT+SET=\"\"\nAT+SET=\"\\\\\\\\\"\nAT+SET=\"r1\\nr2\\n\"\n";
int main(int argc, char **argv)
{
struct cat_object at;
cat_init(&at, &desc, &iface, NULL);
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nERROR\n\nOK\n\nERROR\n\nOK\n\r\nOK\r\n") == 0);
assert(strcmp(write_results, " CMD:\"\\\"abcd\\\"\" CMD:\"1122334\" CMD:\"t\"") == 0);
assert(strcmp(var, "t") == 0);
assert(var_write_size[0] == 6);
assert(var_write_size[1] == 7);
assert(var_write_size[2] == 1);
assert(var_write_size[3] == 0);
prepare_input(test_case_2);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nERROR\n\nOK\n\nOK\n\nOK\n") == 0);
assert(strcmp(write_results, " CMD:\"\" CMD:\"\\\\\\\\\" CMD:\"r1\\nr2\\n\"") == 0);
assert(strcmp(var, "r1\nr2\n") == 0);
assert(var_write_size[0] == 0);
assert(var_write_size[1] == 2);
assert(var_write_size[2] == 6);
assert(var_write_size[3] == 0);
return 0;
}

View File

@@ -0,0 +1,212 @@
/*
MIT License
Copyright (c) 2019 Marcin Borowicz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include "../src/cat.h"
static char write_results[256];
static char ack_results[256];
static uint8_t var1, var1b;
static uint16_t var2, var2b;
static uint32_t var3, var3b;
static char const *input_text;
static size_t input_index;
static int cmd_write(const struct cat_command *cmd, const uint8_t *data, const size_t data_size, const size_t args_num)
{
strcat(write_results, " CMD:");
strncat(write_results, data, data_size);
return 0;
}
static int var1_write(const struct cat_variable *var, size_t write_size)
{
assert(write_size == 1);
var1b = *(uint8_t*)(var->data);
return 0;
}
static int var2_write(const struct cat_variable *var, size_t write_size)
{
assert(write_size == 2);
var2b = *(uint16_t*)(var->data);
return 0;
}
static int var3_write(const struct cat_variable *var, size_t write_size)
{
assert(write_size == 4);
var3b = *(uint32_t*)(var->data);
return 0;
}
static struct cat_variable vars[] = {
{
.type = CAT_VAR_UINT_DEC,
.data = &var1,
.data_size = sizeof(var1),
.write = var1_write
},
{
.type = CAT_VAR_UINT_DEC,
.data = &var2,
.data_size = sizeof(var2),
.write = var2_write
},
{
.type = CAT_VAR_UINT_DEC,
.data = &var3,
.data_size = sizeof(var3),
.write = var3_write
}
};
static struct cat_command cmds[] = {
{
.name = "+SET",
.write = cmd_write,
.var = vars,
.var_num = sizeof(vars) / sizeof(vars[0])
}
};
static char buf[128];
static struct cat_command_group cmd_group = {
.cmd = cmds,
.cmd_num = sizeof(cmds) / sizeof(cmds[0]),
};
static struct cat_command_group *cmd_desc[] = {
&cmd_group
};
static struct cat_descriptor desc = {
.cmd_group = cmd_desc,
.cmd_group_num = sizeof(cmd_desc) / sizeof(cmd_desc[0]),
.buf = buf,
.buf_size = sizeof(buf)
};
static int write_char(char ch)
{
char str[2];
str[0] = ch;
str[1] = 0;
strcat(ack_results, str);
return 1;
}
static int read_char(char *ch)
{
if (input_index >= strlen(input_text))
return 0;
*ch = input_text[input_index];
input_index++;
return 1;
}
static struct cat_io_interface iface = {
.read = read_char,
.write = write_char
};
static void prepare_input(const char *text)
{
input_text = text;
input_index = 0;
var1 = 1;
var2 = 2;
var3 = 3;
var1b = 10;
var2b = 20;
var3b = 30;
memset(ack_results, 0, sizeof(ack_results));
memset(write_results, 0, sizeof(write_results));
}
static const char test_case_1[] = "\nAT+SET=-128\nAT+SET=0\nAT+SET=255\nAT+SET=256\n";
static const char test_case_2[] = "\nAT+SET=0,-1\nAT+SET=0,0\nAT+SET=0,65535\nAT+SET=1,65536\n";
static const char test_case_3[] = "\nAT+SET=0,0,-1\nAT+SET=0,0,0\nAT+SET=1,1,4294967295\nAT+SET=2,2,4294967296\n";
int main(int argc, char **argv)
{
struct cat_object at;
cat_init(&at, &desc, &iface, NULL);
prepare_input(test_case_1);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nERROR\n\nOK\n\nOK\n\nERROR\n") == 0);
assert(strcmp(write_results, " CMD:0 CMD:255") == 0);
assert(var1 == 255);
assert(var1b == var1);
assert(var2 == 2);
assert(var2b == 20);
assert(var3 == 3);
assert(var3b == 30);
prepare_input(test_case_2);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nERROR\n\nOK\n\nOK\n\nERROR\n") == 0);
assert(strcmp(write_results, " CMD:0,0 CMD:0,65535") == 0);
assert(var1 == 1);
assert(var1b == var1);
assert(var2 == 65535);
assert(var2b == var2);
assert(var3 == 3);
assert(var3b == 30);
prepare_input(test_case_3);
while (cat_service(&at) != 0) {};
assert(strcmp(ack_results, "\nERROR\n\nOK\n\nOK\n\nERROR\n") == 0);
assert(strcmp(write_results, " CMD:0,0,0 CMD:1,1,4294967295") == 0);
assert(var1 == 2);
assert(var1b == var1);
assert(var2 == 2);
assert(var2b == var2);
assert(var3 == 4294967295);
assert(var3b == var3);
return 0;
}