1、【增加】FreeModbus从机,保持寄存器测试没问题,其余功能有待测试。3个IDE编译运行后,获取的CPU利用率不一致问题,有待进一步解决
2、【修改】IAR、Keil工程中启动文件,及部分CM3相关的文件,解决之前工程配置遗留下来的问题 3、【增加】RTT的CPU利用率更新至Modbus保持寄存器的功能 Signed-off-by: armink <armink.ztl@gmail.com>
This commit is contained in:
parent
f403250713
commit
f16856e34c
21
.cproject
21
.cproject
|
@ -54,6 +54,9 @@
|
||||||
<listOptionValue builtIn="false" value=""${workspace_loc:/FreeModbus_Slaver&Master+RTT+STM32/RT-Thread-1.1.1/include}""/>
|
<listOptionValue builtIn="false" value=""${workspace_loc:/FreeModbus_Slaver&Master+RTT+STM32/RT-Thread-1.1.1/include}""/>
|
||||||
<listOptionValue builtIn="false" value=""${workspace_loc:/FreeModbus_Slaver&Master+RTT+STM32/Libaries/CMSIS_EWARM/Include}""/>
|
<listOptionValue builtIn="false" value=""${workspace_loc:/FreeModbus_Slaver&Master+RTT+STM32/Libaries/CMSIS_EWARM/Include}""/>
|
||||||
<listOptionValue builtIn="false" value=""${workspace_loc:/FreeModbus_Slaver&Master+RTT+STM32/Libaries/CMSIS_EWARM/CM3/DeviceSupport/ST/STM32F10x}""/>
|
<listOptionValue builtIn="false" value=""${workspace_loc:/FreeModbus_Slaver&Master+RTT+STM32/Libaries/CMSIS_EWARM/CM3/DeviceSupport/ST/STM32F10x}""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/FreeModbus_Slaver&Master+RTT+STM32/FreeModbus/modbus/include}""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/FreeModbus_Slaver&Master+RTT+STM32/FreeModbus/modbus/rtu}""/>
|
||||||
|
<listOptionValue builtIn="false" value=""${workspace_loc:/FreeModbus_Slaver&Master+RTT+STM32/FreeModbus/port}""/>
|
||||||
</option>
|
</option>
|
||||||
<option id="iar.arm.toolchain.compiler.option.defines.v5.4.0.1280497388" name="Defined Symbols:" superClass="iar.arm.toolchain.compiler.option.defines.v5.4.0" valueType="definedSymbols">
|
<option id="iar.arm.toolchain.compiler.option.defines.v5.4.0.1280497388" name="Defined Symbols:" superClass="iar.arm.toolchain.compiler.option.defines.v5.4.0" valueType="definedSymbols">
|
||||||
<listOptionValue builtIn="false" value="STM32F10X_MD"/>
|
<listOptionValue builtIn="false" value="STM32F10X_MD"/>
|
||||||
|
@ -132,11 +135,11 @@
|
||||||
<option id="iar.arm.toolchain.option.fpu.v5.4.0.192375987" name="FPU:" superClass="iar.arm.toolchain.option.fpu.v5.4.0"/>
|
<option id="iar.arm.toolchain.option.fpu.v5.4.0.192375987" name="FPU:" superClass="iar.arm.toolchain.option.fpu.v5.4.0"/>
|
||||||
<option id="iar.arm.toolchain.option.deviceName.v5.5.0.2082375792" name="Device (change with Project > Select Device...)" superClass="iar.arm.toolchain.option.deviceName.v5.5.0" value="ST STM32F103xB" valueType="string"/>
|
<option id="iar.arm.toolchain.option.deviceName.v5.5.0.2082375792" name="Device (change with Project > Select Device...)" superClass="iar.arm.toolchain.option.deviceName.v5.5.0" value="ST STM32F103xB" valueType="string"/>
|
||||||
<option id="iar.arm.toolchain.option.deviceTag.v6.3.1.91150151" name="Device tag storage option" superClass="iar.arm.toolchain.option.deviceTag.v6.3.1" value="STM32F103xB" valueType="string"/>
|
<option id="iar.arm.toolchain.option.deviceTag.v6.3.1.91150151" name="Device tag storage option" superClass="iar.arm.toolchain.option.deviceTag.v6.3.1" value="STM32F103xB" valueType="string"/>
|
||||||
<option id="iar.arm.toolchain.option.libraryConfig.v5.4.0.830584140" superClass="iar.arm.toolchain.option.libraryConfig.v5.4.0"/>
|
<option id="iar.arm.toolchain.option.libraryConfig.v5.4.0.830584140" name="Library:" superClass="iar.arm.toolchain.option.libraryConfig.v5.4.0"/>
|
||||||
<option id="iar.arm.toolchain.option.misra-c.enable.246129539" superClass="iar.arm.toolchain.option.misra-c.enable"/>
|
<option id="iar.arm.toolchain.option.misra-c.enable.246129539" name="Enable MISRA-C" superClass="iar.arm.toolchain.option.misra-c.enable"/>
|
||||||
<option id="iar.arm.toolchain.option.semihosted.v5.4.0.604358352" superClass="iar.arm.toolchain.option.semihosted.v5.4.0"/>
|
<option id="iar.arm.toolchain.option.semihosted.v5.4.0.604358352" name="Include semihosting interface" superClass="iar.arm.toolchain.option.semihosted.v5.4.0"/>
|
||||||
<option id="iar.arm.toolchain.option.lowLevelInterfaceCortex.v5.4.0.298557260" superClass="iar.arm.toolchain.option.lowLevelInterfaceCortex.v5.4.0"/>
|
<option id="iar.arm.toolchain.option.lowLevelInterfaceCortex.v5.4.0.298557260" name="Library low-level interface implementation (Cortex-M cores):" superClass="iar.arm.toolchain.option.lowLevelInterfaceCortex.v5.4.0"/>
|
||||||
<option id="iar.arm.toolchain.option.useCMSIS.v6.2.2.1008613098" superClass="iar.arm.toolchain.option.useCMSIS.v6.2.2"/>
|
<option id="iar.arm.toolchain.option.useCMSIS.v6.2.2.1008613098" name="Use CMSIS" superClass="iar.arm.toolchain.option.useCMSIS.v6.2.2"/>
|
||||||
<targetPlatform binaryParser="org.eclipse.cdt.core.ELF" id="iar.arm.toolchain.targetPlatform.v5.4.0.227679239" isAbstract="false" name="IAR Target platform for ARM (ELF)" osList="win32,linux" superClass="iar.arm.toolchain.targetPlatform.v5.4.0"/>
|
<targetPlatform binaryParser="org.eclipse.cdt.core.ELF" id="iar.arm.toolchain.targetPlatform.v5.4.0.227679239" isAbstract="false" name="IAR Target platform for ARM (ELF)" osList="win32,linux" superClass="iar.arm.toolchain.targetPlatform.v5.4.0"/>
|
||||||
<builder buildPath="${workspace_loc:/FreeModbus_Slaver&Master+RTT+STM32/Release}" id="iar.arm.toolchain.builder.2.1632539169" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="CDT Internal Builder" superClass="iar.arm.toolchain.builder.2"/>
|
<builder buildPath="${workspace_loc:/FreeModbus_Slaver&Master+RTT+STM32/Release}" id="iar.arm.toolchain.builder.2.1632539169" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="CDT Internal Builder" superClass="iar.arm.toolchain.builder.2"/>
|
||||||
<tool id="iar.arm.toolchain.compiler.v5.4.1.872171530" name="IAR C/C++ Compiler for ARM" superClass="iar.arm.toolchain.compiler.v5.4.1">
|
<tool id="iar.arm.toolchain.compiler.v5.4.1.872171530" name="IAR C/C++ Compiler for ARM" superClass="iar.arm.toolchain.compiler.v5.4.1">
|
||||||
|
@ -146,8 +149,8 @@
|
||||||
<listOptionValue builtIn="false" value="NDEBUG"/>
|
<listOptionValue builtIn="false" value="NDEBUG"/>
|
||||||
</option>
|
</option>
|
||||||
<option id="iar.arm.toolchain.compiler.option.cpuMode.v5.4.0.1805213262" name="Processor mode:" superClass="iar.arm.toolchain.compiler.option.cpuMode.v5.4.0" value="iar.arm.toolchain.compiler.option.cpuMode.thumb.v5.4.0" valueType="enumerated"/>
|
<option id="iar.arm.toolchain.compiler.option.cpuMode.v5.4.0.1805213262" name="Processor mode:" superClass="iar.arm.toolchain.compiler.option.cpuMode.v5.4.0" value="iar.arm.toolchain.compiler.option.cpuMode.thumb.v5.4.0" valueType="enumerated"/>
|
||||||
<option id="iar.arm.toolchain.compiler.option.language.v6.1.0.2066106927" superClass="iar.arm.toolchain.compiler.option.language.v6.1.0"/>
|
<option id="iar.arm.toolchain.compiler.option.language.v6.1.0.2066106927" name="Language" superClass="iar.arm.toolchain.compiler.option.language.v6.1.0"/>
|
||||||
<option id="iar.arm.toolchain.compiler.option.cppdialect.v6.1.0.244440025" superClass="iar.arm.toolchain.compiler.option.cppdialect.v6.1.0"/>
|
<option id="iar.arm.toolchain.compiler.option.cppdialect.v6.1.0.244440025" name="C++ dialect" superClass="iar.arm.toolchain.compiler.option.cppdialect.v6.1.0"/>
|
||||||
<inputType id="iar.arm.toolchain.compiler.inputType.v5.4.1.309336638" name="IAR C/C++ Compiler Input Type" superClass="iar.arm.toolchain.compiler.inputType.v5.4.1"/>
|
<inputType id="iar.arm.toolchain.compiler.inputType.v5.4.1.309336638" name="IAR C/C++ Compiler Input Type" superClass="iar.arm.toolchain.compiler.inputType.v5.4.1"/>
|
||||||
</tool>
|
</tool>
|
||||||
<tool id="iar.arm.toolchain.assembler.v5.4.0.2110037064" name="IAR Assembler for ARM" superClass="iar.arm.toolchain.assembler.v5.4.0">
|
<tool id="iar.arm.toolchain.assembler.v5.4.0.2110037064" name="IAR Assembler for ARM" superClass="iar.arm.toolchain.assembler.v5.4.0">
|
||||||
|
@ -157,8 +160,8 @@
|
||||||
<tool id="iar.arm.toolchain.linker.v5.4.0.1632119620" name="IAR Linker for ARM" superClass="iar.arm.toolchain.linker.v5.4.0">
|
<tool id="iar.arm.toolchain.linker.v5.4.0.1632119620" name="IAR Linker for ARM" superClass="iar.arm.toolchain.linker.v5.4.0">
|
||||||
<option id="iar.arm.toolchain.linker.option.icfFile.v5.4.0.1844698325" name="Linker configuration file:" superClass="iar.arm.toolchain.linker.option.icfFile.v5.4.0" value="C:/Program Files/IAR Systems/Embedded Workbench 6.5/arm/config/linker/ST/stm32f103xB.icf" valueType="string"/>
|
<option id="iar.arm.toolchain.linker.option.icfFile.v5.4.0.1844698325" name="Linker configuration file:" superClass="iar.arm.toolchain.linker.option.icfFile.v5.4.0" value="C:/Program Files/IAR Systems/Embedded Workbench 6.5/arm/config/linker/ST/stm32f103xB.icf" valueType="string"/>
|
||||||
<option id="iar.arm.toolchain.linker.option.devicePostProcess.v5.5.2.716248815" name="IElfToolPostProcess" superClass="iar.arm.toolchain.linker.option.devicePostProcess.v5.5.2"/>
|
<option id="iar.arm.toolchain.linker.option.devicePostProcess.v5.5.2.716248815" name="IElfToolPostProcess" superClass="iar.arm.toolchain.linker.option.devicePostProcess.v5.5.2"/>
|
||||||
<option id="iar.arm.toolchain.linker.option.performVFE.v6.2.2.52827050" superClass="iar.arm.toolchain.linker.option.performVFE.v6.2.2"/>
|
<option id="iar.arm.toolchain.linker.option.performVFE.v6.2.2.52827050" name="Perform C++ Virtual Function Elimination" superClass="iar.arm.toolchain.linker.option.performVFE.v6.2.2"/>
|
||||||
<option id="iar.arm.toolchain.linker.option.forceVFE.v6.2.2.1472934084" superClass="iar.arm.toolchain.linker.option.forceVFE.v6.2.2"/>
|
<option id="iar.arm.toolchain.linker.option.forceVFE.v6.2.2.1472934084" name="Even if some modules are missing VFE information" superClass="iar.arm.toolchain.linker.option.forceVFE.v6.2.2"/>
|
||||||
<inputType id="iar.arm.toolchain.linker.inputType.object.v5.4.0.545381687" name="IAR Linker Input Type for ARM (o)" superClass="iar.arm.toolchain.linker.inputType.object.v5.4.0">
|
<inputType id="iar.arm.toolchain.linker.inputType.object.v5.4.0.545381687" name="IAR Linker Input Type for ARM (o)" superClass="iar.arm.toolchain.linker.inputType.object.v5.4.0">
|
||||||
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
|
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
|
||||||
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
|
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
org.eclipse.cdt.core.formatter.alignment_for_arguments_in_method_invocation=16
|
||||||
|
org.eclipse.cdt.core.formatter.alignment_for_assignment=16
|
||||||
|
org.eclipse.cdt.core.formatter.alignment_for_base_clause_in_type_declaration=80
|
||||||
|
org.eclipse.cdt.core.formatter.alignment_for_binary_expression=16
|
||||||
|
org.eclipse.cdt.core.formatter.alignment_for_compact_if=16
|
||||||
|
org.eclipse.cdt.core.formatter.alignment_for_conditional_expression=34
|
||||||
|
org.eclipse.cdt.core.formatter.alignment_for_conditional_expression_chain=18
|
||||||
|
org.eclipse.cdt.core.formatter.alignment_for_constructor_initializer_list=0
|
||||||
|
org.eclipse.cdt.core.formatter.alignment_for_declarator_list=16
|
||||||
|
org.eclipse.cdt.core.formatter.alignment_for_enumerator_list=48
|
||||||
|
org.eclipse.cdt.core.formatter.alignment_for_expression_list=0
|
||||||
|
org.eclipse.cdt.core.formatter.alignment_for_expressions_in_array_initializer=16
|
||||||
|
org.eclipse.cdt.core.formatter.alignment_for_member_access=0
|
||||||
|
org.eclipse.cdt.core.formatter.alignment_for_overloaded_left_shift_chain=16
|
||||||
|
org.eclipse.cdt.core.formatter.alignment_for_parameters_in_method_declaration=16
|
||||||
|
org.eclipse.cdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
|
||||||
|
org.eclipse.cdt.core.formatter.brace_position_for_array_initializer=next_line
|
||||||
|
org.eclipse.cdt.core.formatter.brace_position_for_block=next_line
|
||||||
|
org.eclipse.cdt.core.formatter.brace_position_for_block_in_case=next_line
|
||||||
|
org.eclipse.cdt.core.formatter.brace_position_for_method_declaration=next_line
|
||||||
|
org.eclipse.cdt.core.formatter.brace_position_for_namespace_declaration=next_line
|
||||||
|
org.eclipse.cdt.core.formatter.brace_position_for_switch=next_line
|
||||||
|
org.eclipse.cdt.core.formatter.brace_position_for_type_declaration=next_line
|
||||||
|
org.eclipse.cdt.core.formatter.comment.min_distance_between_code_and_line_comment=1
|
||||||
|
org.eclipse.cdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
|
||||||
|
org.eclipse.cdt.core.formatter.compact_else_if=true
|
||||||
|
org.eclipse.cdt.core.formatter.continuation_indentation=2
|
||||||
|
org.eclipse.cdt.core.formatter.continuation_indentation_for_array_initializer=2
|
||||||
|
org.eclipse.cdt.core.formatter.format_guardian_clause_on_one_line=false
|
||||||
|
org.eclipse.cdt.core.formatter.indent_access_specifier_compare_to_type_header=false
|
||||||
|
org.eclipse.cdt.core.formatter.indent_access_specifier_extra_spaces=0
|
||||||
|
org.eclipse.cdt.core.formatter.indent_body_declarations_compare_to_access_specifier=true
|
||||||
|
org.eclipse.cdt.core.formatter.indent_body_declarations_compare_to_namespace_header=false
|
||||||
|
org.eclipse.cdt.core.formatter.indent_breaks_compare_to_cases=true
|
||||||
|
org.eclipse.cdt.core.formatter.indent_declaration_compare_to_template_header=false
|
||||||
|
org.eclipse.cdt.core.formatter.indent_empty_lines=false
|
||||||
|
org.eclipse.cdt.core.formatter.indent_statements_compare_to_block=true
|
||||||
|
org.eclipse.cdt.core.formatter.indent_statements_compare_to_body=true
|
||||||
|
org.eclipse.cdt.core.formatter.indent_switchstatements_compare_to_cases=true
|
||||||
|
org.eclipse.cdt.core.formatter.indent_switchstatements_compare_to_switch=false
|
||||||
|
org.eclipse.cdt.core.formatter.indentation.size=4
|
||||||
|
org.eclipse.cdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_new_line_after_template_declaration=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_new_line_before_colon_in_constructor_initializer_list=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_new_line_before_identifier_in_function_declaration=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_new_line_in_empty_block=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_assignment_operator=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_binary_operator=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_closing_angle_bracket_in_template_arguments=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_closing_angle_bracket_in_template_parameters=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_closing_brace_in_block=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_colon_in_base_clause=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_colon_in_case=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_colon_in_conditional=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_comma_in_base_types=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_comma_in_declarator_list=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_comma_in_expression_list=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_comma_in_template_arguments=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_comma_in_template_parameters=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_opening_angle_bracket_in_template_arguments=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_opening_angle_bracket_in_template_parameters=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_opening_bracket=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_exception_specification=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_postfix_operator=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_prefix_operator=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_question_in_conditional=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_semicolon_in_for=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_after_unary_operator=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_assignment_operator=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_binary_operator=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_closing_angle_bracket_in_template_arguments=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_closing_angle_bracket_in_template_parameters=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_closing_bracket=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_exception_specification=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_colon_in_base_clause=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_colon_in_case=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_colon_in_conditional=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_colon_in_default=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_comma_in_base_types=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_comma_in_declarator_list=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_comma_in_expression_list=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_comma_in_template_arguments=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_comma_in_template_parameters=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_opening_angle_bracket_in_template_arguments=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_opening_angle_bracket_in_template_parameters=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_block=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_namespace_declaration=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_opening_bracket=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_exception_specification=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_for=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_if=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_while=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_postfix_operator=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_prefix_operator=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_question_in_conditional=insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_semicolon=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_before_unary_operator=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_between_empty_brackets=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_exception_specification=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
|
||||||
|
org.eclipse.cdt.core.formatter.join_wrapped_lines=true
|
||||||
|
org.eclipse.cdt.core.formatter.keep_else_statement_on_same_line=false
|
||||||
|
org.eclipse.cdt.core.formatter.keep_empty_array_initializer_on_one_line=false
|
||||||
|
org.eclipse.cdt.core.formatter.keep_imple_if_on_one_line=false
|
||||||
|
org.eclipse.cdt.core.formatter.keep_then_statement_on_same_line=false
|
||||||
|
org.eclipse.cdt.core.formatter.lineSplit=80
|
||||||
|
org.eclipse.cdt.core.formatter.number_of_empty_lines_to_preserve=1
|
||||||
|
org.eclipse.cdt.core.formatter.put_empty_statement_on_new_line=true
|
||||||
|
org.eclipse.cdt.core.formatter.tabulation.char=tab
|
||||||
|
org.eclipse.cdt.core.formatter.tabulation.size=4
|
||||||
|
org.eclipse.cdt.core.formatter.use_tabs_only_for_leading_indentations=false
|
|
@ -0,0 +1,3 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
formatter_profile=org.eclipse.cdt.ui.default.allman_profile
|
||||||
|
formatter_settings_version=1
|
|
@ -0,0 +1,34 @@
|
||||||
|
#ifndef USER_MODBUS_SLAVER_H
|
||||||
|
#define USER_MODBUS_SLAVER_H
|
||||||
|
/* ----------------------- Modbus includes ----------------------------------*/
|
||||||
|
#include "mb.h"
|
||||||
|
#include "mbport.h"
|
||||||
|
/* ----------------------- Defines ------------------------------------------*/
|
||||||
|
#define DISCRETE_INPUT_START 1
|
||||||
|
#define DISCRETE_INPUT_NDISCRETES 16
|
||||||
|
#define COIL_START 1
|
||||||
|
#define COIL_NCOILS 64
|
||||||
|
#define REG_INPUT_START 1
|
||||||
|
#define REG_INPUT_NREGS 100
|
||||||
|
#define REG_HOLDING_START 1
|
||||||
|
#define REG_HOLDING_NREGS 100
|
||||||
|
|
||||||
|
//===========================在保持寄存器中,各个地址对应的功能定义========================
|
||||||
|
#define HD_RESERVE 0 //保留
|
||||||
|
#define HD_CPU_USAGE_MAJOR 1 //当前CPU利用率的整数位
|
||||||
|
#define HD_CPU_USAGE_MINOR 2 //当前CPU利用率的小数位
|
||||||
|
|
||||||
|
//===========================在输入寄存器中,各个地址对应的功能定义========================
|
||||||
|
#define IN_RESERVE 0 //保留
|
||||||
|
|
||||||
|
//===========================在线圈中,各个地址对应的功能定义============================
|
||||||
|
#define CO_RESERVE 2 //保留
|
||||||
|
|
||||||
|
//===========================在离散输入中,各个地址对应的功能定义=========================
|
||||||
|
#define DI_RESERVE 1 //保留
|
||||||
|
|
||||||
|
/*--------------------------Extern Functions------------------------------------*/
|
||||||
|
extern UCHAR xMBUtilGetBits( UCHAR * ucByteBuf, USHORT usBitOffset, UCHAR ucNBits );
|
||||||
|
extern void xMBUtilSetBits( UCHAR * ucByteBuf, USHORT usBitOffset, UCHAR ucNBits,UCHAR ucValue );
|
||||||
|
|
||||||
|
#endif
|
|
@ -12,6 +12,7 @@
|
||||||
#include "bsp.h"
|
#include "bsp.h"
|
||||||
#include "delay_conf.h"
|
#include "delay_conf.h"
|
||||||
#include "cpuusage.h"
|
#include "cpuusage.h"
|
||||||
|
#include "UserModbusSlaver.h"
|
||||||
|
|
||||||
/*******************************************************************************************************/
|
/*******************************************************************************************************/
|
||||||
// DEFINES
|
// DEFINES
|
||||||
|
@ -25,7 +26,10 @@
|
||||||
#define true 1
|
#define true 1
|
||||||
|
|
||||||
|
|
||||||
|
extern uint16_t usDiscreteInputBuf[] ;
|
||||||
|
extern uint16_t usCoilBuf[] ;
|
||||||
|
extern uint16_t usRegInputBuf[] ;
|
||||||
|
extern uint16_t usRegHoldingBuf[] ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
|
|
||||||
#define DELAY_SYS_RUN_LED DELAY_MS(500) //系统指示灯延时500ms
|
#define DELAY_SYS_RUN_LED DELAY_MS(500) //系统指示灯延时500ms
|
||||||
#define DELAY_SYS_SLEEP_LED DELAY_MS(1000) //系统指示灯延时1s
|
#define DELAY_SYS_SLEEP_LED DELAY_MS(1000) //系统指示灯延时1s
|
||||||
|
#define DELAY_MB_SLAVER_POLL DELAY_MS(10) //Modbus从机轮训时间
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -44,8 +44,6 @@ void SVC_Handler(void);
|
||||||
void DebugMon_Handler(void);
|
void DebugMon_Handler(void);
|
||||||
void PendSV_Handler(void);
|
void PendSV_Handler(void);
|
||||||
void SysTick_Handler(void);
|
void SysTick_Handler(void);
|
||||||
void USART1_IRQHandler(void);
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
#include "UserModbusSlaver.h"
|
||||||
|
/* ----------------------- Variables ---------------------------------*/
|
||||||
|
USHORT usDiscreteInputStart = DISCRETE_INPUT_START;
|
||||||
|
UCHAR usDiscreteInputBuf[DISCRETE_INPUT_NDISCRETES/8] ;
|
||||||
|
USHORT usCoilStart = COIL_START;
|
||||||
|
UCHAR usCoilBuf[COIL_NCOILS/8] ;
|
||||||
|
USHORT usRegInputStart = REG_INPUT_START;
|
||||||
|
USHORT usRegInputBuf[REG_INPUT_NREGS] ;
|
||||||
|
USHORT usRegHoldingStart = REG_HOLDING_START;
|
||||||
|
USHORT usRegHoldingBuf[REG_HOLDING_NREGS] ;
|
||||||
|
|
||||||
|
//******************************输入寄存器回调函数**********************************
|
||||||
|
//函数定义: eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
|
||||||
|
//描 述:输入寄存器相关的功能(读、连续读)
|
||||||
|
//入口参数:pucRegBuffer : 回调函数将Modbus寄存器的当前值写入的缓冲区
|
||||||
|
// usAddress : 寄存器的起始地址,输入寄存器的地址范围是1-65535。
|
||||||
|
// usNRegs : 寄存器数量
|
||||||
|
//出口参数:eMBErrorCode : 这个函数将返回的错误码
|
||||||
|
//备 注:Editor:Armink 2010-10-31 Company: BXXJS
|
||||||
|
//**********************************************************************************
|
||||||
|
eMBErrorCode
|
||||||
|
eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
|
||||||
|
{
|
||||||
|
eMBErrorCode eStatus = MB_ENOERR;
|
||||||
|
int iRegIndex;
|
||||||
|
if( ( usAddress >= REG_INPUT_START )
|
||||||
|
&& ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
|
||||||
|
{
|
||||||
|
iRegIndex = ( int )( usAddress - usRegInputStart );
|
||||||
|
while( usNRegs > 0 )
|
||||||
|
{
|
||||||
|
*pucRegBuffer++ = ( unsigned char )( usRegInputBuf[iRegIndex] >> 8 );
|
||||||
|
*pucRegBuffer++ = ( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF );
|
||||||
|
iRegIndex++;
|
||||||
|
usNRegs--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eStatus = MB_ENOREG;
|
||||||
|
}
|
||||||
|
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
//******************************保持寄存器回调函数**********************************
|
||||||
|
//函数定义: eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
|
||||||
|
//描 述:保持寄存器相关的功能(读、连续读、写、连续写)
|
||||||
|
//入口参数:pucRegBuffer : 如果需要更新用户寄存器数值,这个缓冲区必须指向新的寄存器数值。
|
||||||
|
// 如果协议栈想知道当前的数值,回调函数必须将当前值写入这个缓冲区
|
||||||
|
// usAddress : 寄存器的起始地址。
|
||||||
|
// usNRegs : 寄存器数量
|
||||||
|
// eMode : 如果该参数为eMBRegisterMode::MB_REG_WRITE,用户的应用数值将从pucRegBuffer中得到更新。
|
||||||
|
// 如果该参数为eMBRegisterMode::MB_REG_READ,用户需要将当前的应用数据存储在pucRegBuffer中
|
||||||
|
//出口参数:eMBErrorCode : 这个函数将返回的错误码
|
||||||
|
//备 注:Editor:Armink 2010-10-31 Company: BXXJS
|
||||||
|
//**********************************************************************************
|
||||||
|
eMBErrorCode
|
||||||
|
eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
|
||||||
|
{
|
||||||
|
eMBErrorCode eStatus = MB_ENOERR;
|
||||||
|
int iRegIndex;
|
||||||
|
if( ( usAddress >= REG_HOLDING_START ) &&
|
||||||
|
( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) )
|
||||||
|
{
|
||||||
|
iRegIndex = ( int )( usAddress - usRegHoldingStart );
|
||||||
|
switch ( eMode )
|
||||||
|
{
|
||||||
|
/* Pass current register values to the protocol stack. */
|
||||||
|
case MB_REG_READ:
|
||||||
|
while( usNRegs > 0 )
|
||||||
|
{
|
||||||
|
*pucRegBuffer++ = ( unsigned char )( usRegHoldingBuf[iRegIndex] >> 8 );
|
||||||
|
*pucRegBuffer++ = ( unsigned char )( usRegHoldingBuf[iRegIndex] & 0xFF );
|
||||||
|
iRegIndex++;
|
||||||
|
usNRegs--;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Update current register values with new values from the
|
||||||
|
* protocol stack. */
|
||||||
|
case MB_REG_WRITE:
|
||||||
|
while( usNRegs > 0 )
|
||||||
|
{
|
||||||
|
usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
|
||||||
|
usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
|
||||||
|
iRegIndex++;
|
||||||
|
usNRegs--;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eStatus = MB_ENOREG;
|
||||||
|
}
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
//****************************线圈状态寄存器回调函数********************************
|
||||||
|
//函数定义: eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )
|
||||||
|
//描 述:线圈状态寄存器相关的功能(读、连续读、写、连续写)
|
||||||
|
//入口参数:pucRegBuffer : 位组成一个字节,起始寄存器对应的位处于该字节pucRegBuffer的最低位LSB。
|
||||||
|
// 如果回调函数要写这个缓冲区,没有用到的线圈(例如不是8个一组的线圈状态)对应的位的数值必须设置位0。
|
||||||
|
// usAddress : 第一个线圈地址。
|
||||||
|
// usNCoils : 请求的线圈个数
|
||||||
|
// eMode ;如果该参数为eMBRegisterMode::MB_REG_WRITE,用户的应用数值将从pucRegBuffer中得到更新。
|
||||||
|
// 如果该参数为eMBRegisterMode::MB_REG_READ,用户需要将当前的应用数据存储在pucRegBuffer中
|
||||||
|
//出口参数:eMBErrorCode : 这个函数将返回的错误码
|
||||||
|
//备 注:Editor:Armink 2010-10-31 Company: BXXJS
|
||||||
|
//**********************************************************************************
|
||||||
|
eMBErrorCode
|
||||||
|
eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )
|
||||||
|
{
|
||||||
|
eMBErrorCode eStatus = MB_ENOERR;
|
||||||
|
int iRegIndex , iRegBitIndex , iNReg;
|
||||||
|
iNReg = usNCoils / 8 + 1; //占用寄存器数量
|
||||||
|
if( ( usAddress >= COIL_START ) &&
|
||||||
|
( usAddress + usNCoils <= COIL_START + COIL_NCOILS ) )
|
||||||
|
{
|
||||||
|
iRegIndex = ( int )( usAddress - usCoilStart ) / 8 ; //每个寄存器存8个
|
||||||
|
iRegBitIndex = ( int )( usAddress - usCoilStart ) % 8 ; //相对于寄存器内部的位地址
|
||||||
|
switch ( eMode )
|
||||||
|
{
|
||||||
|
/* Pass current coil values to the protocol stack. */
|
||||||
|
case MB_REG_READ:
|
||||||
|
while( iNReg > 0 )
|
||||||
|
{
|
||||||
|
*pucRegBuffer++ = xMBUtilGetBits(&usCoilBuf[iRegIndex++] , iRegBitIndex , 8);
|
||||||
|
iNReg --;
|
||||||
|
}
|
||||||
|
pucRegBuffer --;
|
||||||
|
usNCoils = usNCoils % 8; //余下的线圈数
|
||||||
|
*pucRegBuffer = *pucRegBuffer <<(8 - usNCoils); //高位补零
|
||||||
|
*pucRegBuffer = *pucRegBuffer >>(8 - usNCoils);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Update current coil values with new values from the
|
||||||
|
* protocol stack. */
|
||||||
|
case MB_REG_WRITE:
|
||||||
|
while(iNReg > 1) //最后面余下来的数单独算
|
||||||
|
{
|
||||||
|
xMBUtilSetBits(&usCoilBuf[iRegIndex++] , iRegBitIndex , 8 , *pucRegBuffer++);
|
||||||
|
iNReg--;
|
||||||
|
}
|
||||||
|
usNCoils = usNCoils % 8; //余下的线圈数
|
||||||
|
xMBUtilSetBits(&usCoilBuf[iRegIndex++] , iRegBitIndex , usNCoils , *pucRegBuffer++);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eStatus = MB_ENOREG;
|
||||||
|
}
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
//****************************离散输入寄存器回调函数********************************
|
||||||
|
//函数定义: eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
|
||||||
|
//描 述:离散输入寄存器相关的功能(读、连续读)
|
||||||
|
//入口参数:pucRegBuffer : 用当前的线圈数据更新这个寄存器,起始寄存器对应的位处于该字节pucRegBuffer的最低位LSB。
|
||||||
|
// 如果回调函数要写这个缓冲区,没有用到的线圈(例如不是8个一组的线圈状态)对应的位的数值必须设置为0。
|
||||||
|
// usAddress : 离散输入的起始地址
|
||||||
|
// usNDiscrete : 离散输入点数量
|
||||||
|
//出口参数:eMBErrorCode : 这个函数将返回的错误码
|
||||||
|
//备 注:Editor:Armink 2010-10-31 Company: BXXJS
|
||||||
|
//**********************************************************************************
|
||||||
|
eMBErrorCode
|
||||||
|
eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
|
||||||
|
{
|
||||||
|
eMBErrorCode eStatus = MB_ENOERR;
|
||||||
|
int iRegIndex , iRegBitIndex , iNReg;
|
||||||
|
iNReg = usNDiscrete / 8 + 1; //占用寄存器数量
|
||||||
|
if( ( usAddress >= DISCRETE_INPUT_START )
|
||||||
|
&& ( usAddress + usNDiscrete <= DISCRETE_INPUT_START + DISCRETE_INPUT_NDISCRETES ) )
|
||||||
|
{
|
||||||
|
iRegIndex = ( int )( usAddress - usDiscreteInputStart ) / 8 ; //每个寄存器存8个
|
||||||
|
iRegBitIndex = ( int )( usAddress - usDiscreteInputStart ) % 8 ; //相对于寄存器内部的位地址
|
||||||
|
while( iNReg > 0 )
|
||||||
|
{
|
||||||
|
*pucRegBuffer++ = xMBUtilGetBits(&usDiscreteInputBuf[iRegIndex++] , iRegBitIndex , 8);
|
||||||
|
iNReg --;
|
||||||
|
}
|
||||||
|
pucRegBuffer --;
|
||||||
|
usNDiscrete = usNDiscrete % 8; //余下的线圈数
|
||||||
|
*pucRegBuffer = *pucRegBuffer <<(8 - usNDiscrete); //高位补零
|
||||||
|
*pucRegBuffer = *pucRegBuffer >>(8 - usNDiscrete);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eStatus = MB_ENOREG;
|
||||||
|
}
|
||||||
|
|
||||||
|
return eStatus;
|
||||||
|
}
|
|
@ -1,131 +1,151 @@
|
||||||
#include "app_task.h"
|
#include "app_task.h"
|
||||||
|
|
||||||
#ifdef __CC_ARM
|
|
||||||
extern int Image$$RW_IRAM1$$ZI$$Limit;
|
|
||||||
#elif __ICCARM__
|
|
||||||
#pragma section="HEAP"
|
|
||||||
#else
|
|
||||||
extern int __bss_end;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint8_t CpuUsageMajor , CpuUsageMinor;//CPU使用率
|
|
||||||
|
|
||||||
|
#ifdef __CC_ARM
|
||||||
//====================操作系统各线程优先级==================================
|
extern int Image$$RW_IRAM1$$ZI$$Limit;
|
||||||
#define thread_SysMonitor_Prio 3
|
#elif __ICCARM__
|
||||||
|
#pragma section="HEAP"
|
||||||
|
#else
|
||||||
|
extern int __bss_end;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint8_t CpuUsageMajor, CpuUsageMinor; //CPU使用率
|
||||||
|
|
||||||
|
//====================操作系统各线程优先级==================================
|
||||||
|
#define thread_SysMonitor_Prio 11
|
||||||
|
#define thread_ModbusSlaverPoll_Prio 10
|
||||||
ALIGN(RT_ALIGN_SIZE)
|
ALIGN(RT_ALIGN_SIZE)
|
||||||
//====================操作系统各线程堆栈====================================
|
//====================操作系统各线程堆栈====================================
|
||||||
static rt_uint8_t thread_SysMonitor_stack[512];
|
static rt_uint8_t thread_SysMonitor_stack[256];
|
||||||
|
static rt_uint8_t thread_ModbusSlaverPoll_stack[512];
|
||||||
struct rt_thread thread_SysMonitor;
|
|
||||||
|
struct rt_thread thread_SysMonitor;
|
||||||
//***************************系统监控线程***************************
|
struct rt_thread thread_ModbusSlaverPoll;
|
||||||
//函数定义: void thread_entry_SysRunLed(void* parameter)
|
|
||||||
//入口参数:无
|
//***************************系统监控线程***************************
|
||||||
//出口参数:无
|
//函数定义: void thread_entry_SysRunLed(void* parameter)
|
||||||
//备 注:Editor:Liuqiuhu 2013-1-30 Company: BXXJS
|
//入口参数:无
|
||||||
//******************************************************************
|
//出口参数:无
|
||||||
void thread_entry_SysMonitor(void* parameter)
|
//备 注:Editor:Liuqiuhu 2013-1-30 Company: BXXJS
|
||||||
|
//******************************************************************
|
||||||
|
void thread_entry_SysMonitor(void* parameter)
|
||||||
{
|
{
|
||||||
while(1)
|
while (1)
|
||||||
{
|
{
|
||||||
cpu_usage_get(&CpuUsageMajor , &CpuUsageMinor);
|
cpu_usage_get(&CpuUsageMajor, &CpuUsageMinor);
|
||||||
LED_LED1_ON;
|
usRegHoldingBuf[HD_CPU_USAGE_MAJOR] = CpuUsageMajor;
|
||||||
LED_LED2_ON;
|
usRegHoldingBuf[HD_CPU_USAGE_MINOR] = CpuUsageMinor;
|
||||||
rt_thread_delay(DELAY_SYS_RUN_LED);
|
LED_LED1_ON;
|
||||||
LED_LED1_OFF;
|
LED_LED2_ON;
|
||||||
LED_LED2_OFF;
|
rt_thread_delay(DELAY_SYS_RUN_LED);
|
||||||
rt_thread_delay(DELAY_SYS_RUN_LED);
|
LED_LED1_OFF;
|
||||||
IWDG_Feed();//喂狗
|
LED_LED2_OFF;
|
||||||
}
|
rt_thread_delay(DELAY_SYS_RUN_LED);
|
||||||
}
|
IWDG_Feed(); //喂狗
|
||||||
|
}
|
||||||
|
}
|
||||||
//**********************系统初始化函数********************************
|
|
||||||
//函数定义: int rt_application_init(void)
|
//*************************** Modbus从机线程***************************
|
||||||
//入口参数:无
|
//函数定义: void thread_entry_ModbusSlaverPoll(void* parameter)
|
||||||
//出口参数:无
|
//入口参数:无
|
||||||
//备 注:Editor:Liuqiuhu 2013-1-31 Company: BXXJS
|
//出口参数:无
|
||||||
//********************************************************************
|
//备 注:Editor:Armink 2013-08-02 Company: BXXJS
|
||||||
int rt_application_init(void)
|
//******************************************************************
|
||||||
{
|
void thread_entry_ModbusSlaverPoll(void* parameter)
|
||||||
rt_thread_init(&thread_SysMonitor,
|
{
|
||||||
"SysMonitor",
|
eMBInit(MB_RTU, 0x01, 1, 115200, MB_PAR_NONE);
|
||||||
thread_entry_SysMonitor,
|
eMBEnable();
|
||||||
RT_NULL,
|
while (1)
|
||||||
thread_SysMonitor_stack,
|
{
|
||||||
sizeof(thread_SysMonitor_stack),
|
eMBPoll();
|
||||||
thread_SysMonitor_Prio,20);
|
rt_thread_delay(DELAY_MB_SLAVER_POLL);
|
||||||
rt_thread_startup(&thread_SysMonitor);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
//**********************系统初始化函数********************************
|
||||||
}
|
//函数定义: int rt_application_init(void)
|
||||||
|
//入口参数:无
|
||||||
|
//出口参数:无
|
||||||
//**************************初始化RT-Thread函数*************************************
|
//备 注:Editor:Liuqiuhu 2013-1-31 Company: BXXJS
|
||||||
//函数定义: void rtthread_startup(void)
|
//********************************************************************
|
||||||
//入口参数:无
|
int rt_application_init(void)
|
||||||
//出口参数:无
|
{
|
||||||
//备 注:Editor:Armink 2011-04-04 Company: BXXJS
|
rt_thread_init(&thread_SysMonitor, "SysMonitor", thread_entry_SysMonitor,
|
||||||
//**********************************************************************************
|
RT_NULL, thread_SysMonitor_stack, sizeof(thread_SysMonitor_stack),
|
||||||
void rtthread_startup(void)
|
thread_SysMonitor_Prio, 5);
|
||||||
{
|
rt_thread_startup(&thread_SysMonitor);
|
||||||
/* init board */
|
|
||||||
rt_hw_board_init();
|
rt_thread_init(&thread_ModbusSlaverPoll, "MBSlaverPoll",
|
||||||
|
thread_entry_ModbusSlaverPoll, RT_NULL,
|
||||||
/* show version */
|
thread_ModbusSlaverPoll_stack,
|
||||||
rt_show_version();
|
sizeof(thread_ModbusSlaverPoll_stack), thread_ModbusSlaverPoll_Prio,
|
||||||
|
5);
|
||||||
/* init tick */
|
rt_thread_startup(&thread_ModbusSlaverPoll);
|
||||||
rt_system_tick_init();
|
|
||||||
|
return 0;
|
||||||
/* init kernel object */
|
}
|
||||||
rt_system_object_init();
|
|
||||||
|
//**************************初始化RT-Thread函数*************************************
|
||||||
/* init timer system */
|
//函数定义: void rtthread_startup(void)
|
||||||
rt_system_timer_init();
|
//入口参数:无
|
||||||
|
//出口参数:无
|
||||||
#ifdef RT_USING_HEAP
|
//备 注:Editor:Armink 2011-04-04 Company: BXXJS
|
||||||
#ifdef __CC_ARM
|
//**********************************************************************************
|
||||||
rt_system_heap_init((void*)&Image$$RW_IRAM1$$ZI$$Limit, (void*)STM32_SRAM_END);
|
void rtthread_startup(void)
|
||||||
#elif __ICCARM__
|
{
|
||||||
rt_system_heap_init(__segment_end("HEAP"), (void*)STM32_SRAM_END);
|
/* init board */
|
||||||
#else
|
rt_hw_board_init();
|
||||||
/* init memory system */
|
|
||||||
rt_system_heap_init((void*)&__bss_end, (void*)STM32_SRAM_END);
|
/* show version */
|
||||||
#endif
|
rt_show_version();
|
||||||
#endif
|
|
||||||
|
/* init tick */
|
||||||
/* init scheduler system */
|
rt_system_tick_init();
|
||||||
rt_system_scheduler_init();
|
|
||||||
|
/* init kernel object */
|
||||||
/* init all device */
|
rt_system_object_init();
|
||||||
rt_device_init_all();
|
|
||||||
|
/* init timer system */
|
||||||
/* init application */
|
rt_system_timer_init();
|
||||||
rt_application_init();
|
|
||||||
|
#ifdef RT_USING_HEAP
|
||||||
#ifdef RT_USING_FINSH
|
#ifdef __CC_ARM
|
||||||
/* init finsh */
|
rt_system_heap_init((void*)&Image$$RW_IRAM1$$ZI$$Limit, (void*)STM32_SRAM_END);
|
||||||
finsh_system_init();
|
#elif __ICCARM__
|
||||||
finsh_set_device("uart1");
|
rt_system_heap_init(__segment_end("HEAP"), (void*)STM32_SRAM_END);
|
||||||
#endif
|
#else
|
||||||
|
/* init memory system */
|
||||||
/* init timer thread */
|
rt_system_heap_init((void*)&__bss_end, (void*)STM32_SRAM_END);
|
||||||
rt_system_timer_thread_init();
|
#endif
|
||||||
|
#endif
|
||||||
/* init idle thread */
|
|
||||||
rt_thread_idle_init();
|
/* init scheduler system */
|
||||||
|
rt_system_scheduler_init();
|
||||||
/* Add CPU usage to system */
|
|
||||||
cpu_usage_init();
|
/* init all device */
|
||||||
|
rt_device_init_all();
|
||||||
/* start scheduler */
|
|
||||||
rt_system_scheduler_start();
|
/* init application */
|
||||||
|
rt_application_init();
|
||||||
/* never reach here */
|
|
||||||
return ;
|
#ifdef RT_USING_FINSH
|
||||||
}
|
/* init finsh */
|
||||||
|
finsh_system_init();
|
||||||
|
finsh_set_device("uart1");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* init timer thread */
|
||||||
|
rt_system_timer_thread_init();
|
||||||
|
|
||||||
|
/* init idle thread */
|
||||||
|
rt_thread_idle_init();
|
||||||
|
|
||||||
|
/* Add CPU usage to system */
|
||||||
|
cpu_usage_init();
|
||||||
|
|
||||||
|
/* start scheduler */
|
||||||
|
rt_system_scheduler_start();
|
||||||
|
|
||||||
|
/* never reach here */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -120,27 +120,6 @@ void DebugMon_Handler(void)
|
||||||
rt_hw_timer_handler();
|
rt_hw_timer_handler();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
* Function Name : USART1_IRQHandler
|
|
||||||
* Description : This function handles USART1 global interrupt request.
|
|
||||||
* Input : None
|
|
||||||
* Output : None
|
|
||||||
* Return : None
|
|
||||||
*******************************************************************************/
|
|
||||||
void USART1_IRQHandler(void)
|
|
||||||
{
|
|
||||||
/* enter interrupt */
|
|
||||||
rt_interrupt_enter();
|
|
||||||
|
|
||||||
if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET)
|
|
||||||
{
|
|
||||||
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
|
|
||||||
}
|
|
||||||
|
|
||||||
rt_interrupt_leave();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* STM32F10x Peripherals Interrupt Handlers */
|
/* STM32F10x Peripherals Interrupt Handlers */
|
||||||
/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */
|
/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */
|
||||||
|
|
601
BSP/src/bsp.c
601
BSP/src/bsp.c
|
@ -1,320 +1,295 @@
|
||||||
/*
|
/*
|
||||||
*********************************************************************************************************
|
*********************************************************************************************************
|
||||||
*
|
*
|
||||||
* BOARD SUPPORT PACKAGE
|
* BOARD SUPPORT PACKAGE
|
||||||
*
|
*
|
||||||
* ST Microelectronics STM32
|
* ST Microelectronics STM32
|
||||||
* with the
|
* with the
|
||||||
* STM3210B-EVAL Evaluation Board
|
* STM3210B-EVAL Evaluation Board
|
||||||
*
|
*
|
||||||
* Filename : bsp.c
|
* Filename : bsp.c
|
||||||
* Version : V1.00
|
* Version : V1.00
|
||||||
* Programmer(s) : STM32F103X RT-Thread 0.3.1 USB-CDC
|
* Programmer(s) : STM32F103X RT-Thread 0.3.1 USB-CDC
|
||||||
*********************************************************************************************************
|
*********************************************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*********************************************************************************************************
|
*********************************************************************************************************
|
||||||
* INCLUDE FILES
|
* INCLUDE FILES
|
||||||
*********************************************************************************************************
|
*********************************************************************************************************
|
||||||
*/
|
*/
|
||||||
#define BSP_MODULE
|
#define BSP_MODULE
|
||||||
|
|
||||||
#include <bsp.h>
|
#include <bsp.h>
|
||||||
#include <rthw.h>
|
#include <rthw.h>
|
||||||
#include <rtthread.h>
|
#include <rtthread.h>
|
||||||
/*
|
#include "UserModbusSlaver.h"
|
||||||
*********************************************************************************************************
|
/*
|
||||||
* LOCAL TABLES
|
*********************************************************************************************************
|
||||||
*********************************************************************************************************
|
* LOCAL TABLES
|
||||||
*/
|
*********************************************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
*********************************************************************************************************
|
/*
|
||||||
* LOCAL GLOBAL VARIABLES
|
*********************************************************************************************************
|
||||||
*********************************************************************************************************
|
* LOCAL GLOBAL VARIABLES
|
||||||
*/
|
*********************************************************************************************************
|
||||||
|
*/
|
||||||
/*
|
|
||||||
*********************************************************************************************************
|
/*
|
||||||
* LOCAL FUNCTION PROTOTYPES
|
*********************************************************************************************************
|
||||||
*********************************************************************************************************
|
* LOCAL FUNCTION PROTOTYPES
|
||||||
*/
|
*********************************************************************************************************
|
||||||
|
*/
|
||||||
/** This function will initial STM32 board**/
|
|
||||||
void rt_hw_board_init()
|
/** This function will initial STM32 board**/
|
||||||
{
|
void rt_hw_board_init()
|
||||||
BSP_Init();
|
{
|
||||||
}
|
BSP_Init();
|
||||||
|
}
|
||||||
/*******************************************************************************
|
|
||||||
* Function Name : RCC_Configuration
|
/*******************************************************************************
|
||||||
* Description : Configures the RCC.
|
* Function Name : RCC_Configuration
|
||||||
* Input : None
|
* Description : Configures the RCC.
|
||||||
* Output : None
|
* Input : None
|
||||||
* Return : None
|
* Output : None
|
||||||
*******************************************************************************/
|
* Return : None
|
||||||
static void RCC_Configuration(void)
|
*******************************************************************************/
|
||||||
{
|
static void RCC_Configuration(void)
|
||||||
//下面是给各模块开启时钟
|
{
|
||||||
//启动GPIO
|
//下面是给各模块开启时钟
|
||||||
|
//启动GPIO
|
||||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | \
|
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | \
|
||||||
RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | \
|
RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | \
|
||||||
RCC_APB2Periph_GPIOE ,
|
RCC_APB2Periph_GPIOE ,
|
||||||
ENABLE);
|
ENABLE);
|
||||||
//启动AFIO
|
//启动AFIO
|
||||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
|
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
|
||||||
//配置ADC转换时钟
|
//配置ADC转换时钟
|
||||||
RCC_ADCCLKConfig(RCC_PCLK2_Div8); //9M
|
RCC_ADCCLKConfig(RCC_PCLK2_Div8); //9M
|
||||||
//启动USART1 USART4
|
//启动USART1 USART4
|
||||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
|
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
|
||||||
//启动DMA时钟
|
//启动DMA时钟
|
||||||
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//使能DMA时钟
|
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//使能DMA时钟
|
||||||
/* Enable ADC1 and GPIOC clock */
|
/* Enable ADC1 and GPIOC clock */
|
||||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 , ENABLE);
|
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 , ENABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Function Name : NVIC_Configuration
|
* Function Name : NVIC_Configuration
|
||||||
* Description : Configer NVIC
|
* Description : Configer NVIC
|
||||||
* Input : None
|
* Input : None
|
||||||
* Output : None
|
* Output : None
|
||||||
* Return : None
|
* Return : None
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
static void NVIC_Configuration(void)
|
static void NVIC_Configuration(void)
|
||||||
{
|
{
|
||||||
NVIC_InitTypeDef NVIC_InitStructure;
|
NVIC_InitTypeDef NVIC_InitStructure;
|
||||||
|
|
||||||
#ifdef VECT_TAB_RAM
|
#ifdef VECT_TAB_RAM
|
||||||
// Set the Vector Table base location at 0x20000000
|
// Set the Vector Table base location at 0x20000000
|
||||||
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
|
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
|
||||||
#else // VECT_TAB_FLASH
|
#else // VECT_TAB_FLASH
|
||||||
// Set the Vector Table base location at 0x08000000
|
// Set the Vector Table base location at 0x08000000
|
||||||
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
|
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//设置NVIC优先级分组为Group2:0-3抢占式优先级,0-3的响应式优先级
|
|
||||||
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
|
}
|
||||||
//串口1接收中断打开
|
/*******************************************************************************
|
||||||
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
|
* Function Name : GPIO_Configuration
|
||||||
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
|
* Description : Configures the different GPIO ports.
|
||||||
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
|
* Input : None
|
||||||
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
* Output : None
|
||||||
NVIC_Init(&NVIC_InitStructure);
|
* Return : None
|
||||||
|
*******************************************************************************/
|
||||||
}
|
static void GPIO_Configuration(void)
|
||||||
/*******************************************************************************
|
{
|
||||||
* Function Name : GPIO_Configuration
|
GPIO_InitTypeDef GPIO_InitStructure;
|
||||||
* Description : Configures the different GPIO ports.
|
|
||||||
* Input : None
|
/***************数字输出IO初始化*********************/
|
||||||
* Output : None
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||||
* Return : None
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
*******************************************************************************/
|
|
||||||
static void GPIO_Configuration(void)
|
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_11 | GPIO_Pin_12; //继电器1 LED1 LED2
|
||||||
{
|
|
||||||
GPIO_InitTypeDef GPIO_InitStructure;
|
|
||||||
|
|
||||||
/***************数字输出IO初始化*********************/
|
|
||||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
|
||||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
|
||||||
|
|
||||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12; //蜂鸣器 LED1 LED2
|
|
||||||
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||||
|
|
||||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //蜂鸣器
|
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_14 | GPIO_Pin_15; //蜂鸣器 继电器3 继电器2
|
||||||
GPIO_Init(GPIOB, &GPIO_InitStructure);
|
GPIO_Init(GPIOB, &GPIO_InitStructure);
|
||||||
|
|
||||||
/*************数字输入IO初始化*********************/
|
/*************数字输入IO初始化*********************/
|
||||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
|
||||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
|
||||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_6;
|
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_6;
|
||||||
GPIO_Init(GPIOG, &GPIO_InitStructure);
|
GPIO_Init(GPIOG, &GPIO_InitStructure);
|
||||||
|
|
||||||
|
|
||||||
/****************USART1初始化************************/
|
|
||||||
//USART1_TX
|
}
|
||||||
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
|
||||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
|
|
||||||
|
|
||||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
|
|
||||||
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
/*******************************************************************************
|
||||||
|
* Function Name : USART1_Configuration
|
||||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
|
* Description : NUSART1设置
|
||||||
GPIO_Init(GPIOC, &GPIO_InitStructure);
|
* Input : None
|
||||||
|
* Output : None
|
||||||
//USART1_RX
|
* Return : None
|
||||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
*******************************************************************************/
|
||||||
|
static void USART1_Configuration(void)
|
||||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
|
{
|
||||||
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
USART_InitTypeDef USART_InitStructure;
|
||||||
|
|
||||||
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
|
USART_InitStructure.USART_BaudRate = 115200;
|
||||||
GPIO_Init(GPIOC, &GPIO_InitStructure);
|
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
|
||||||
}
|
USART_InitStructure.USART_StopBits = USART_StopBits_1;
|
||||||
|
USART_InitStructure.USART_Parity = USART_Parity_No;
|
||||||
|
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
|
||||||
|
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
|
||||||
|
USART_Init(USART1, &USART_InitStructure);
|
||||||
/*******************************************************************************
|
|
||||||
* Function Name : USART1_Configuration
|
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//使能串口1的接收中断
|
||||||
* Description : NUSART1设置
|
|
||||||
* Input : None
|
USART_Cmd(USART1, ENABLE);
|
||||||
* Output : None
|
}
|
||||||
* Return : None
|
|
||||||
*******************************************************************************/
|
|
||||||
static void USART1_Configuration(void)
|
//*******************初始化独立看门狗*************************************
|
||||||
{
|
//函数定义: void IWDG_Configuration(void)
|
||||||
USART_InitTypeDef USART_InitStructure;
|
//描 述:初始化独立看门狗
|
||||||
|
//入口参数:无
|
||||||
USART_InitStructure.USART_BaudRate = 115200;
|
//出口参数:无
|
||||||
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
|
//备 注:分频因子=4*2^prer.但最大值只能是256!时间计算(大概):Tout=40K/((4*2^prer)*rlr)值 2S超时
|
||||||
USART_InitStructure.USART_StopBits = USART_StopBits_1;
|
//Editor:liuqh 2013-1-16 Company: BXXJS
|
||||||
USART_InitStructure.USART_Parity = USART_Parity_No;
|
//*******************************************************************
|
||||||
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
|
static void IWDG_Configuration(void)
|
||||||
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
|
{
|
||||||
USART_Init(USART1, &USART_InitStructure);
|
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//使能对IWDG->PR和IWDG->RLR的写
|
||||||
|
IWDG_SetPrescaler(IWDG_Prescaler_64);//64分频
|
||||||
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//使能串口1的接收中断
|
IWDG_SetReload(1300);
|
||||||
|
IWDG_ReloadCounter();
|
||||||
USART_Cmd(USART1, ENABLE);
|
IWDG_Enable();
|
||||||
}
|
}
|
||||||
|
//*******************喂独立看门狗*************************************
|
||||||
|
//函数定义: void IWDG_Feed(void)
|
||||||
//*******************初始化独立看门狗*************************************
|
//描 述:初始化独立看门狗
|
||||||
//函数定义: void IWDG_Configuration(void)
|
//入口参数:无
|
||||||
//描 述:初始化独立看门狗
|
//出口参数:prer:分频数:0~7(只有低3位有效!),rlr:重装载寄存器值:低11位有效.
|
||||||
//入口参数:无
|
//备 注:分频因子=4*2^prer.但最大值只能是256!时间计算(大概):Tout=40K/((4*2^prer)*rlr)值
|
||||||
//出口参数:无
|
//Editor:liuqh 2013-1-16 Company: BXXJS
|
||||||
//备 注:分频因子=4*2^prer.但最大值只能是256!时间计算(大概):Tout=40K/((4*2^prer)*rlr)值 2S超时
|
//*******************************************************************
|
||||||
//Editor:liuqh 2013-1-16 Company: BXXJS
|
|
||||||
//*******************************************************************
|
void IWDG_Feed(void)
|
||||||
static void IWDG_Configuration(void)
|
{
|
||||||
{
|
IWDG_ReloadCounter();//reload
|
||||||
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//使能对IWDG->PR和IWDG->RLR的写
|
}
|
||||||
IWDG_SetPrescaler(IWDG_Prescaler_64);//64分频
|
|
||||||
IWDG_SetReload(1300);
|
|
||||||
IWDG_ReloadCounter();
|
/*******************************************************************************
|
||||||
IWDG_Enable();
|
* Function Name : SysTick_Configuration
|
||||||
}
|
* Description : Configures the SysTick for OS tick.
|
||||||
//*******************喂独立看门狗*************************************
|
* Input : None
|
||||||
//函数定义: void IWDG_Feed(void)
|
* Output : None
|
||||||
//描 述:初始化独立看门狗
|
* Return : None
|
||||||
//入口参数:无
|
*******************************************************************************/
|
||||||
//出口参数:prer:分频数:0~7(只有低3位有效!),rlr:重装载寄存器值:低11位有效.
|
void SysTick_Configuration(void)
|
||||||
//备 注:分频因子=4*2^prer.但最大值只能是256!时间计算(大概):Tout=40K/((4*2^prer)*rlr)值
|
{
|
||||||
//Editor:liuqh 2013-1-16 Company: BXXJS
|
RCC_ClocksTypeDef rcc_clocks;
|
||||||
//*******************************************************************
|
rt_uint32_t cnts;
|
||||||
|
|
||||||
void IWDG_Feed(void)
|
RCC_GetClocksFreq(&rcc_clocks);
|
||||||
{
|
|
||||||
IWDG_ReloadCounter();//reload
|
cnts = (rt_uint32_t)rcc_clocks.HCLK_Frequency / RT_TICK_PER_SECOND;
|
||||||
}
|
|
||||||
|
SysTick_Config(cnts);
|
||||||
|
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
|
||||||
/*******************************************************************************
|
}
|
||||||
* Function Name : SysTick_Configuration
|
/**
|
||||||
* Description : Configures the SysTick for OS tick.
|
* This is the timer interrupt service routine.
|
||||||
* Input : None
|
*
|
||||||
* Output : None
|
*/
|
||||||
* Return : None
|
void rt_hw_timer_handler(void)
|
||||||
*******************************************************************************/
|
{
|
||||||
void SysTick_Configuration(void)
|
/* enter interrupt */
|
||||||
{
|
rt_interrupt_enter();
|
||||||
RCC_ClocksTypeDef rcc_clocks;
|
|
||||||
rt_uint32_t cnts;
|
rt_tick_increase();
|
||||||
|
|
||||||
RCC_GetClocksFreq(&rcc_clocks);
|
/* leave interrupt */
|
||||||
|
rt_interrupt_leave();
|
||||||
cnts = (rt_uint32_t)rcc_clocks.HCLK_Frequency / RT_TICK_PER_SECOND;
|
}
|
||||||
|
|
||||||
SysTick_Config(cnts);
|
/*
|
||||||
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
|
*********************************************************************************************************
|
||||||
}
|
* LOCAL CONFIGURATION ERRORS
|
||||||
/**
|
*********************************************************************************************************
|
||||||
* This is the timer interrupt service routine.
|
*/
|
||||||
*
|
|
||||||
*/
|
|
||||||
void rt_hw_timer_handler(void)
|
/*
|
||||||
{
|
*********************************************************************************************************
|
||||||
/* enter interrupt */
|
* BSP_Init()
|
||||||
rt_interrupt_enter();
|
*
|
||||||
|
* Description : Initialize the Board Support Package (BSP).
|
||||||
rt_tick_increase();
|
*
|
||||||
|
* Argument(s) : none.
|
||||||
/* leave interrupt */
|
*
|
||||||
rt_interrupt_leave();
|
* Return(s) : none.
|
||||||
}
|
*
|
||||||
|
* Caller(s) : Application.
|
||||||
/*
|
*
|
||||||
*********************************************************************************************************
|
* Note(s) : (1) This function SHOULD be called before any other BSP function is called.
|
||||||
* LOCAL CONFIGURATION ERRORS
|
*********************************************************************************************************
|
||||||
*********************************************************************************************************
|
*/
|
||||||
*/
|
|
||||||
|
void BSP_Init (void)
|
||||||
|
{
|
||||||
/*
|
RCC_Configuration();
|
||||||
*********************************************************************************************************
|
NVIC_Configuration();
|
||||||
* BSP_Init()
|
SysTick_Configuration();
|
||||||
*
|
GPIO_Configuration();
|
||||||
* Description : Initialize the Board Support Package (BSP).
|
// TODO 方便调试,暂时注释看门狗,正式发布时需要打开
|
||||||
*
|
// IWDG_Configuration();
|
||||||
* Argument(s) : none.
|
}
|
||||||
*
|
//****************************防超时程序********************************
|
||||||
* Return(s) : none.
|
//函数定义: uint8_t AvoidTimeout(uint32_t TimeOfTimeout,uint32_t Period,uint8_t (*DetectCondition)())
|
||||||
*
|
//描 述:在TimeOfTimeout时间内,每Period时间检测一次DetectCondition()返回的值是否有效
|
||||||
* Caller(s) : Application.
|
//入口参数:TimeOfTimeout:防超时总时间(单位:systick)
|
||||||
*
|
// Period :每Period时间检测一次,即时间因子(单位:systick)
|
||||||
* Note(s) : (1) This function SHOULD be called before any other BSP function is called.
|
// (*DetectCondition)():检测条件,等于ConditionValue则条件满足,检测结束,否则延时Period时间继续检测
|
||||||
*********************************************************************************************************
|
// ConditionValue ;条件成立的值
|
||||||
*/
|
//出口参数:0:在TimeOfTimeout时间内,检测到条件成立
|
||||||
|
// 1:在TimeOfTimeout时间内,没有检测到条件成立
|
||||||
void BSP_Init (void)
|
//备 注:Editor:Armink 2012-03-09 Company: BXXJS
|
||||||
{
|
//**********************************************************************
|
||||||
RCC_Configuration();
|
uint8_t AvoidTimeout(uint32_t TimeOfTimeout,uint32_t Period,uint8_t (*DetectCondition)(),uint8_t ConditionValue)
|
||||||
NVIC_Configuration();
|
{
|
||||||
SysTick_Configuration();
|
uint32_t LastTimeLocal, CurTimeLocal;
|
||||||
GPIO_Configuration();
|
uint8_t ConditionValueLocal;
|
||||||
USART1_Configuration();
|
LastTimeLocal = rt_tick_get();
|
||||||
// IWDG_Configuration();
|
CurTimeLocal = LastTimeLocal;
|
||||||
}
|
while(CurTimeLocal - LastTimeLocal < TimeOfTimeout)
|
||||||
//****************************防超时程序********************************
|
{
|
||||||
//函数定义: uint8_t AvoidTimeout(uint32_t TimeOfTimeout,uint32_t Period,uint8_t (*DetectCondition)())
|
CurTimeLocal = rt_tick_get();
|
||||||
//描 述:在TimeOfTimeout时间内,每Period时间检测一次DetectCondition()返回的值是否有效
|
ConditionValueLocal = DetectCondition();
|
||||||
//入口参数:TimeOfTimeout:防超时总时间(单位:systick)
|
if (ConditionValueLocal == ConditionValue) return 0;
|
||||||
// Period :每Period时间检测一次,即时间因子(单位:systick)
|
rt_thread_delay(Period);
|
||||||
// (*DetectCondition)():检测条件,等于ConditionValue则条件满足,检测结束,否则延时Period时间继续检测
|
}
|
||||||
// ConditionValue ;条件成立的值
|
return 1;
|
||||||
//出口参数:0:在TimeOfTimeout时间内,检测到条件成立
|
}
|
||||||
// 1:在TimeOfTimeout时间内,没有检测到条件成立
|
|
||||||
//备 注:Editor:Armink 2012-03-09 Company: BXXJS
|
|
||||||
//**********************************************************************
|
//************************************延时函数**************************************
|
||||||
uint8_t AvoidTimeout(uint32_t TimeOfTimeout,uint32_t Period,uint8_t (*DetectCondition)(),uint8_t ConditionValue)
|
//函数定义: void Delay(vu32 nCount)
|
||||||
{
|
//入口参数:nCount :延时函数中,循环的次数
|
||||||
uint32_t LastTimeLocal, CurTimeLocal;
|
//出口参数:无
|
||||||
uint8_t ConditionValueLocal;
|
//备 注:Editor:Armink 2011-03-18 Company: BXXJS
|
||||||
LastTimeLocal = rt_tick_get();
|
//**********************************************************************************
|
||||||
CurTimeLocal = LastTimeLocal;
|
void Delay(vu32 nCount)
|
||||||
while(CurTimeLocal - LastTimeLocal < TimeOfTimeout)
|
{
|
||||||
{
|
for(; nCount!= 0;nCount--);
|
||||||
CurTimeLocal = rt_tick_get();
|
}
|
||||||
ConditionValueLocal = DetectCondition();
|
|
||||||
if (ConditionValueLocal == ConditionValue) return 0;
|
|
||||||
rt_thread_delay(Period);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//************************************延时函数**************************************
|
|
||||||
//函数定义: void Delay(vu32 nCount)
|
|
||||||
//入口参数:nCount :延时函数中,循环的次数
|
|
||||||
//出口参数:无
|
|
||||||
//备 注:Editor:Armink 2011-03-18 Company: BXXJS
|
|
||||||
//**********************************************************************************
|
|
||||||
void Delay(vu32 nCount)
|
|
||||||
{
|
|
||||||
for(; nCount!= 0;nCount--);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -300,6 +300,9 @@
|
||||||
<state>$PROJ_DIR$\..\RT-Thread-1.1.1\include</state>
|
<state>$PROJ_DIR$\..\RT-Thread-1.1.1\include</state>
|
||||||
<state>$PROJ_DIR$\..\Libaries\CMSIS_EWARM\Include</state>
|
<state>$PROJ_DIR$\..\Libaries\CMSIS_EWARM\Include</state>
|
||||||
<state>$PROJ_DIR$\..\Libaries\CMSIS_EWARM\CM3\DeviceSupport\ST\STM32F10x</state>
|
<state>$PROJ_DIR$\..\Libaries\CMSIS_EWARM\CM3\DeviceSupport\ST\STM32F10x</state>
|
||||||
|
<state>$PROJ_DIR$\..\FreeModbus\modbus\include</state>
|
||||||
|
<state>$PROJ_DIR$\..\FreeModbus\modbus\rtu</state>
|
||||||
|
<state>$PROJ_DIR$\..\FreeModbus\port</state>
|
||||||
</option>
|
</option>
|
||||||
<option>
|
<option>
|
||||||
<name>CCStdIncCheck</name>
|
<name>CCStdIncCheck</name>
|
||||||
|
@ -1860,9 +1863,15 @@
|
||||||
<file>
|
<file>
|
||||||
<name>$PROJ_DIR$\..\APP\src\stm32f10x_it.c</name>
|
<name>$PROJ_DIR$\..\APP\src\stm32f10x_it.c</name>
|
||||||
</file>
|
</file>
|
||||||
|
<file>
|
||||||
|
<name>$PROJ_DIR$\..\APP\src\UserModbusSlaver.c</name>
|
||||||
|
</file>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<name>BSP</name>
|
<name>BSP</name>
|
||||||
|
<file>
|
||||||
|
<name>$PROJ_DIR$\..\RT-Thread-1.1.1\libcpu\arm\common\backtrace.c</name>
|
||||||
|
</file>
|
||||||
<file>
|
<file>
|
||||||
<name>$PROJ_DIR$\..\BSP\src\bsp.c</name>
|
<name>$PROJ_DIR$\..\BSP\src\bsp.c</name>
|
||||||
</file>
|
</file>
|
||||||
|
@ -1872,6 +1881,9 @@
|
||||||
<file>
|
<file>
|
||||||
<name>$PROJ_DIR$\..\RT-Thread-1.1.1\libcpu\arm\cortex-m3\cpuport.c</name>
|
<name>$PROJ_DIR$\..\RT-Thread-1.1.1\libcpu\arm\cortex-m3\cpuport.c</name>
|
||||||
</file>
|
</file>
|
||||||
|
<file>
|
||||||
|
<name>$PROJ_DIR$\..\RT-Thread-1.1.1\libcpu\arm\common\showmem.c</name>
|
||||||
|
</file>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<name>CMSIS</name>
|
<name>CMSIS</name>
|
||||||
|
@ -1879,6 +1891,54 @@
|
||||||
<name>$PROJ_DIR$\..\Libaries\CMSIS_EWARM\CM3\DeviceSupport\ST\STM32F10x\system_stm32f10x.c</name>
|
<name>$PROJ_DIR$\..\Libaries\CMSIS_EWARM\CM3\DeviceSupport\ST\STM32F10x\system_stm32f10x.c</name>
|
||||||
</file>
|
</file>
|
||||||
</group>
|
</group>
|
||||||
|
<group>
|
||||||
|
<name>FreeModbusSlaver</name>
|
||||||
|
<file>
|
||||||
|
<name>$PROJ_DIR$\..\FreeModbus\modbus\mb.c</name>
|
||||||
|
</file>
|
||||||
|
<file>
|
||||||
|
<name>$PROJ_DIR$\..\FreeModbus\modbus\rtu\mbcrc.c</name>
|
||||||
|
</file>
|
||||||
|
<file>
|
||||||
|
<name>$PROJ_DIR$\..\FreeModbus\modbus\functions\mbfunccoils.c</name>
|
||||||
|
</file>
|
||||||
|
<file>
|
||||||
|
<name>$PROJ_DIR$\..\FreeModbus\modbus\functions\mbfuncdiag.c</name>
|
||||||
|
</file>
|
||||||
|
<file>
|
||||||
|
<name>$PROJ_DIR$\..\FreeModbus\modbus\functions\mbfuncdisc.c</name>
|
||||||
|
</file>
|
||||||
|
<file>
|
||||||
|
<name>$PROJ_DIR$\..\FreeModbus\modbus\functions\mbfuncholding.c</name>
|
||||||
|
</file>
|
||||||
|
<file>
|
||||||
|
<name>$PROJ_DIR$\..\FreeModbus\modbus\functions\mbfuncinput.c</name>
|
||||||
|
</file>
|
||||||
|
<file>
|
||||||
|
<name>$PROJ_DIR$\..\FreeModbus\modbus\functions\mbfuncother.c</name>
|
||||||
|
</file>
|
||||||
|
<file>
|
||||||
|
<name>$PROJ_DIR$\..\FreeModbus\modbus\rtu\mbrtu.c</name>
|
||||||
|
</file>
|
||||||
|
<file>
|
||||||
|
<name>$PROJ_DIR$\..\FreeModbus\modbus\functions\mbutils.c</name>
|
||||||
|
</file>
|
||||||
|
<file>
|
||||||
|
<name>$PROJ_DIR$\..\FreeModbus\port\port.c</name>
|
||||||
|
</file>
|
||||||
|
<file>
|
||||||
|
<name>$PROJ_DIR$\..\FreeModbus\port\port.h</name>
|
||||||
|
</file>
|
||||||
|
<file>
|
||||||
|
<name>$PROJ_DIR$\..\FreeModbus\port\portevent.c</name>
|
||||||
|
</file>
|
||||||
|
<file>
|
||||||
|
<name>$PROJ_DIR$\..\FreeModbus\port\portserial.c</name>
|
||||||
|
</file>
|
||||||
|
<file>
|
||||||
|
<name>$PROJ_DIR$\..\FreeModbus\port\porttimer.c</name>
|
||||||
|
</file>
|
||||||
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<name>RT-Thread Kernel</name>
|
<name>RT-Thread Kernel</name>
|
||||||
<file>
|
<file>
|
||||||
|
@ -1935,6 +1995,9 @@
|
||||||
<file>
|
<file>
|
||||||
<name>$PROJ_DIR$\..\Libaries\STM32F10x_StdPeriph_Driver\src\misc.c</name>
|
<name>$PROJ_DIR$\..\Libaries\STM32F10x_StdPeriph_Driver\src\misc.c</name>
|
||||||
</file>
|
</file>
|
||||||
|
<file>
|
||||||
|
<name>$PROJ_DIR$\..\Libaries\CMSIS_EWARM\CM3\DeviceSupport\ST\STM32F10x\startup\iar\startup_stm32f10x_md.s</name>
|
||||||
|
</file>
|
||||||
<file>
|
<file>
|
||||||
<name>$PROJ_DIR$\..\Libaries\STM32F10x_StdPeriph_Driver\src\stm32f10x_adc.c</name>
|
<name>$PROJ_DIR$\..\Libaries\STM32F10x_StdPeriph_Driver\src\stm32f10x_adc.c</name>
|
||||||
</file>
|
</file>
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<Column0>124</Column0><Column1>27</Column1><Column2>27</Column2><Column3>27</Column3></ColumnWidths>
|
<Column0>87</Column0><Column1>27</Column1><Column2>27</Column2><Column3>27</Column3></ColumnWidths>
|
||||||
</Workspace>
|
</Workspace>
|
||||||
<Disassembly>
|
<Disassembly>
|
||||||
<col-names>
|
<col-names>
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
|
|
||||||
<ShowCodeCoverage>1</ShowCodeCoverage><ShowInstrProfiling>1</ShowInstrProfiling></Disassembly>
|
<ShowCodeCoverage>1</ShowCodeCoverage><ShowInstrProfiling>1</ShowInstrProfiling></Disassembly>
|
||||||
</Static>
|
<Find-All-Declarations><ColumnWidth0>580</ColumnWidth0><ColumnWidth1>82</ColumnWidth1><ColumnWidth2>994</ColumnWidth2></Find-All-Declarations></Static>
|
||||||
<Windows>
|
<Windows>
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@
|
||||||
<Factory>Build</Factory>
|
<Factory>Build</Factory>
|
||||||
<Session/>
|
<Session/>
|
||||||
</Tab>
|
</Tab>
|
||||||
</Tabs>
|
<Tab><Identity>TabID-23458-14555</Identity><TabName>Find All Declarations</TabName><Factory>Find-All-Declarations</Factory><Session/></Tab></Tabs>
|
||||||
|
|
||||||
<SelectedTab>0</SelectedTab></Wnd0><Wnd1>
|
<SelectedTab>0</SelectedTab></Wnd0><Wnd1>
|
||||||
<Tabs>
|
<Tabs>
|
||||||
|
@ -63,7 +63,7 @@
|
||||||
<Factory>Workspace</Factory>
|
<Factory>Workspace</Factory>
|
||||||
<Session>
|
<Session>
|
||||||
|
|
||||||
<NodeDict><ExpandedNode>FreeModbus_Slaver&Master+RTT+STM32</ExpandedNode></NodeDict></Session>
|
<NodeDict><ExpandedNode>FreeModbus_Slaver&Master+RTT+STM32</ExpandedNode><ExpandedNode>FreeModbus_Slaver&Master+RTT+STM32/APP</ExpandedNode><ExpandedNode>FreeModbus_Slaver&Master+RTT+STM32/FreeModbusSlaver</ExpandedNode></NodeDict></Session>
|
||||||
</Tab>
|
</Tab>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
|
@ -83,14 +83,14 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<Pane><Tab><Factory>TextEditor</Factory><Filename>$WS_DIR$\..\APP\src\app_task.c</Filename><XPos>0</XPos><YPos>0</YPos><SelStart>0</SelStart><SelEnd>0</SelEnd><XPos2>0</XPos2><YPos2>9</YPos2><SelStart2>20</SelStart2><SelEnd2>20</SelEnd2></Tab><Tab><Factory>TextEditor</Factory><Filename>$WS_DIR$\..\Libaries\STM32F10x_StdPeriph_Driver\src\stm32f10x_wwdg.c</Filename><XPos>0</XPos><YPos>0</YPos><SelStart>0</SelStart><SelEnd>0</SelEnd><XPos2>0</XPos2><YPos2>0</YPos2><SelStart2>2</SelStart2><SelEnd2>2</SelEnd2></Tab><Tab><Factory>TextEditor</Factory><Filename>$WS_DIR$\..\APP\src\app.c</Filename><XPos>0</XPos><YPos>0</YPos><SelStart>0</SelStart><SelEnd>0</SelEnd><XPos2>0</XPos2><YPos2>0</YPos2><SelStart2>23</SelStart2><SelEnd2>23</SelEnd2></Tab><ActiveTab>2</ActiveTab><Tab><Factory>TextEditor</Factory><Filename>$WS_DIR$\..\Libaries\STM32F10x_StdPeriph_Driver\src\stm32f10x_i2c.c</Filename><XPos>0</XPos><YPos>0</YPos><SelStart>0</SelStart><SelEnd>0</SelEnd><XPos2>0</XPos2><YPos2>0</YPos2><SelStart2>800</SelStart2><SelEnd2>800</SelEnd2></Tab></Pane><ActivePane>0</ActivePane><Sizes><Pane><X>1000000</X><Y>1000000</Y></Pane></Sizes><SplitMode>1</SplitMode></Editor>
|
<Pane><Tab><Factory>TextEditor</Factory><Filename>$WS_DIR$\..\APP\src\app_task.c</Filename><XPos>0</XPos><YPos>0</YPos><SelStart>0</SelStart><SelEnd>0</SelEnd><XPos2>0</XPos2><YPos2>16</YPos2><SelStart2>1666</SelStart2><SelEnd2>1666</SelEnd2></Tab><Tab><Factory>TextEditor</Factory><Filename>$WS_DIR$\..\APP\src\app.c</Filename><XPos>0</XPos><YPos>0</YPos><SelStart>0</SelStart><SelEnd>0</SelEnd><XPos2>0</XPos2><YPos2>0</YPos2><SelStart2>23</SelStart2><SelEnd2>23</SelEnd2></Tab><ActiveTab>1</ActiveTab><Tab><Factory>TextEditor</Factory><Filename>$WS_DIR$\..\FreeModbus\port\portserial.c</Filename><XPos>0</XPos><YPos>0</YPos><SelStart>0</SelStart><SelEnd>0</SelEnd><XPos2>0</XPos2><YPos2>144</YPos2><SelStart2>5425</SelStart2><SelEnd2>5425</SelEnd2></Tab><Tab><Factory>TextEditor</Factory><Filename>$WS_DIR$\..\RT-Thread-1.1.1\libcpu\arm\cortex-m3\cpuport.c</Filename><XPos>0</XPos><YPos>0</YPos><SelStart>0</SelStart><SelEnd>0</SelEnd><XPos2>0</XPos2><YPos2>98</YPos2><SelStart2>4032</SelStart2><SelEnd2>4032</SelEnd2></Tab><Tab><Factory>TextEditor</Factory><Filename>$WS_DIR$\..\Libaries\CMSIS_EWARM\CM3\DeviceSupport\ST\STM32F10x\startup\iar\startup_stm32f10x_md.s</Filename><XPos>0</XPos><YPos>0</YPos><SelStart>0</SelStart><SelEnd>0</SelEnd><XPos2>0</XPos2><YPos2>42</YPos2><SelStart2>3319</SelStart2><SelEnd2>3334</SelEnd2></Tab><Tab><Factory>TextEditor</Factory><Filename>$WS_DIR$\..\BSP\src\bsp.c</Filename><XPos>0</XPos><YPos>0</YPos><SelStart>0</SelStart><SelEnd>0</SelEnd><XPos2>0</XPos2><YPos2>226</YPos2><SelStart2>8652</SelStart2><SelEnd2>8652</SelEnd2></Tab><Tab><Factory>TextEditor</Factory><Filename>$WS_DIR$\..\APP\src\stm32f10x_it.c</Filename><XPos>0</XPos><YPos>0</YPos><SelStart>0</SelStart><SelEnd>0</SelEnd><XPos2>0</XPos2><YPos2>79</YPos2><SelStart2>3317</SelStart2><SelEnd2>3317</SelEnd2></Tab><Tab><Factory>TextEditor</Factory><Filename>$WS_DIR$\..\APP\inc\stm32f10x_it.h</Filename><XPos>0</XPos><YPos>0</YPos><SelStart>0</SelStart><SelEnd>0</SelEnd><XPos2>0</XPos2><YPos2>2</YPos2><SelStart2>821</SelStart2><SelEnd2>821</SelEnd2></Tab></Pane><ActivePane>0</ActivePane><Sizes><Pane><X>1000000</X><Y>1000000</Y></Pane></Sizes><SplitMode>1</SplitMode></Editor>
|
||||||
<Positions>
|
<Positions>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<Top><Row0><Sizes><Toolbar-01c86ca0><key>iaridepm.enu1</key></Toolbar-01c86ca0></Sizes></Row0><Row1><Sizes><Toolbar-17be8430><key>debuggergui.enu1</key></Toolbar-17be8430></Sizes></Row1></Top><Left><Row0><Sizes><Wnd1><Rect><Top>-2</Top><Left>-2</Left><Bottom>701</Bottom><Right>198</Right><x>-2</x><y>-2</y><xscreen>200</xscreen><yscreen>200</yscreen><sizeHorzCX>119048</sizeHorzCX><sizeHorzCY>206612</sizeHorzCY><sizeVertCX>119048</sizeVertCX><sizeVertCY>726240</sizeVertCY></Rect></Wnd1></Sizes></Row0></Left><Right><Row0><Sizes><Wnd2><Rect><Top>-2</Top><Left>-2</Left><Bottom>701</Bottom><Right>198</Right><x>-2</x><y>-2</y><xscreen>200</xscreen><yscreen>200</yscreen><sizeHorzCX>119048</sizeHorzCX><sizeHorzCY>206612</sizeHorzCY><sizeVertCX>119048</sizeVertCX><sizeVertCY>726240</sizeVertCY></Rect></Wnd2></Sizes></Row0></Right><Bottom><Row0><Sizes><Wnd0><Rect><Top>-2</Top><Left>-2</Left><Bottom>198</Bottom><Right>1682</Right><x>-2</x><y>-2</y><xscreen>1684</xscreen><yscreen>200</yscreen><sizeHorzCX>1002381</sizeHorzCX><sizeHorzCY>206612</sizeHorzCY><sizeVertCX>119048</sizeVertCX><sizeVertCY>206612</sizeVertCY></Rect></Wnd0></Sizes></Row0></Bottom><Float><Sizes/></Float></Positions>
|
<Top><Row0><Sizes><Toolbar-00fa4588><key>iaridepm.enu1</key></Toolbar-00fa4588></Sizes></Row0><Row1><Sizes><Toolbar-102550e8><key>debuggergui.enu1</key></Toolbar-102550e8></Sizes></Row1></Top><Left><Row0><Sizes><Wnd1><Rect><Top>-2</Top><Left>-2</Left><Bottom>474</Bottom><Right>178</Right><x>-2</x><y>-2</y><xscreen>73</xscreen><yscreen>138</yscreen><sizeHorzCX>58682</sizeHorzCX><sizeHorzCY>203240</sizeHorzCY><sizeVertCX>144695</sizeVertCX><sizeVertCY>701031</sizeVertCY></Rect></Wnd1></Sizes></Row0></Left><Right><Row0><Sizes><Wnd2><Rect><Top>-2</Top><Left>-2</Left><Bottom>474</Bottom><Right>191</Right><x>-2</x><y>-2</y><xscreen>73</xscreen><yscreen>138</yscreen><sizeHorzCX>58682</sizeHorzCX><sizeHorzCY>203240</sizeHorzCY><sizeVertCX>155145</sizeVertCX><sizeVertCY>701031</sizeVertCY></Rect></Wnd2></Sizes></Row0></Right><Bottom><Row0><Sizes><Wnd0><Rect><Top>-2</Top><Left>-2</Left><Bottom>136</Bottom><Right>1246</Right><x>-2</x><y>-2</y><xscreen>1248</xscreen><yscreen>138</yscreen><sizeHorzCX>1003215</sizeHorzCX><sizeHorzCY>203240</sizeHorzCY><sizeVertCX>58682</sizeVertCX><sizeVertCY>203240</sizeVertCY></Rect></Wnd0></Sizes></Row0></Bottom><Float><Sizes/></Float></Positions>
|
||||||
</Desktop>
|
</Desktop>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ TriggerName=main
|
||||||
LimitSize=0
|
LimitSize=0
|
||||||
ByteLimit=50
|
ByteLimit=50
|
||||||
[DebugChecksum]
|
[DebugChecksum]
|
||||||
Checksum=74914984
|
Checksum=2104484592
|
||||||
[Exceptions]
|
[Exceptions]
|
||||||
StopOnUncaught=_ 0
|
StopOnUncaught=_ 0
|
||||||
StopOnThrow=_ 0
|
StopOnThrow=_ 0
|
||||||
|
|
|
@ -12,12 +12,12 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<Column0>252</Column0><Column1>13</Column1><Column2>27</Column2><Column3>0</Column3></ColumnWidths>
|
<Column0>238</Column0><Column1>13</Column1><Column2>27</Column2><Column3>0</Column3></ColumnWidths>
|
||||||
</Workspace>
|
</Workspace>
|
||||||
<Build><ColumnWidth0>20</ColumnWidth0><ColumnWidth1>1215</ColumnWidth1><ColumnWidth2>324</ColumnWidth2><ColumnWidth3>81</ColumnWidth3></Build><TerminalIO/><Debug-Log><ColumnWidth0>19</ColumnWidth0><ColumnWidth1>1622</ColumnWidth1></Debug-Log></Static>
|
<Build><ColumnWidth0>20</ColumnWidth0><ColumnWidth1>1215</ColumnWidth1><ColumnWidth2>324</ColumnWidth2><ColumnWidth3>81</ColumnWidth3></Build><TerminalIO/><Debug-Log><ColumnWidth0>19</ColumnWidth0><ColumnWidth1>1622</ColumnWidth1></Debug-Log></Static>
|
||||||
<Windows>
|
<Windows>
|
||||||
|
|
||||||
<Wnd2>
|
<Wnd0>
|
||||||
<Tabs>
|
<Tabs>
|
||||||
<Tab>
|
<Tab>
|
||||||
<Identity>TabID-30370-1297</Identity>
|
<Identity>TabID-30370-1297</Identity>
|
||||||
|
@ -25,24 +25,24 @@
|
||||||
<Factory>Workspace</Factory>
|
<Factory>Workspace</Factory>
|
||||||
<Session>
|
<Session>
|
||||||
|
|
||||||
<NodeDict><ExpandedNode>FreeModbus_Slaver&Master+RTT+STM32</ExpandedNode></NodeDict></Session>
|
<NodeDict><ExpandedNode>FreeModbus_Slaver&Master+RTT+STM32</ExpandedNode><ExpandedNode>FreeModbus_Slaver&Master+RTT+STM32/APP</ExpandedNode><ExpandedNode>FreeModbus_Slaver&Master+RTT+STM32/CMSIS</ExpandedNode></NodeDict></Session>
|
||||||
</Tab>
|
</Tab>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
<SelectedTab>0</SelectedTab></Wnd2><Wnd3><Tabs><Tab><Identity>TabID-24390-6730</Identity><TabName>Build</TabName><Factory>Build</Factory><Session/></Tab></Tabs><SelectedTab>0</SelectedTab></Wnd3></Windows>
|
<SelectedTab>0</SelectedTab></Wnd0><Wnd1><Tabs><Tab><Identity>TabID-24390-6730</Identity><TabName>Build</TabName><Factory>Build</Factory><Session/></Tab></Tabs><SelectedTab>0</SelectedTab></Wnd1></Windows>
|
||||||
<Editor>
|
<Editor>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<Pane><Tab><Factory>TextEditor</Factory><Filename>$WS_DIR$\..\APP\src\app_task.c</Filename><XPos>0</XPos><YPos>0</YPos><SelStart>0</SelStart><SelEnd>0</SelEnd><XPos2>0</XPos2><YPos2>9</YPos2><SelStart2>744</SelStart2><SelEnd2>744</SelEnd2></Tab><ActiveTab>0</ActiveTab></Pane><ActivePane>0</ActivePane><Sizes><Pane><X>1000000</X><Y>1000000</Y></Pane></Sizes><SplitMode>1</SplitMode></Editor>
|
<Pane><Tab><Factory>TextEditor</Factory><Filename>$WS_DIR$\..\APP\src\app_task.c</Filename><XPos>0</XPos><YPos>0</YPos><SelStart>0</SelStart><SelEnd>0</SelEnd><XPos2>0</XPos2><YPos2>16</YPos2><SelStart2>1666</SelStart2><SelEnd2>1666</SelEnd2></Tab><Tab><Factory>TextEditor</Factory><Filename>$WS_DIR$\..\APP\src\app.c</Filename><XPos>0</XPos><YPos>0</YPos><SelStart>0</SelStart><SelEnd>0</SelEnd><XPos2>0</XPos2><YPos2>0</YPos2><SelStart2>152</SelStart2><SelEnd2>152</SelEnd2></Tab><ActiveTab>1</ActiveTab><Tab><Factory>TextEditor</Factory><Filename>$WS_DIR$\..\FreeModbus\port\portserial.c</Filename><XPos>0</XPos><YPos>0</YPos><SelStart>0</SelStart><SelEnd>0</SelEnd><XPos2>0</XPos2><YPos2>144</YPos2><SelStart2>5425</SelStart2><SelEnd2>5425</SelEnd2></Tab><Tab><Factory>TextEditor</Factory><Filename>$WS_DIR$\..\RT-Thread-1.1.1\libcpu\arm\cortex-m3\cpuport.c</Filename><XPos>0</XPos><YPos>0</YPos><SelStart>0</SelStart><SelEnd>0</SelEnd><XPos2>0</XPos2><YPos2>98</YPos2><SelStart2>4032</SelStart2><SelEnd2>4032</SelEnd2></Tab><Tab><Factory>TextEditor</Factory><Filename>$WS_DIR$\..\Libaries\CMSIS_EWARM\CM3\DeviceSupport\ST\STM32F10x\startup\iar\startup_stm32f10x_md.s</Filename><XPos>0</XPos><YPos>0</YPos><SelStart>0</SelStart><SelEnd>0</SelEnd><XPos2>0</XPos2><YPos2>42</YPos2><SelStart2>3319</SelStart2><SelEnd2>3334</SelEnd2></Tab><Tab><Factory>TextEditor</Factory><Filename>$WS_DIR$\..\BSP\src\bsp.c</Filename><XPos>0</XPos><YPos>0</YPos><SelStart>0</SelStart><SelEnd>0</SelEnd><XPos2>0</XPos2><YPos2>226</YPos2><SelStart2>8652</SelStart2><SelEnd2>8652</SelEnd2></Tab><Tab><Factory>TextEditor</Factory><Filename>$WS_DIR$\..\APP\src\stm32f10x_it.c</Filename><XPos>0</XPos><YPos>0</YPos><SelStart>0</SelStart><SelEnd>0</SelEnd><XPos2>0</XPos2><YPos2>79</YPos2><SelStart2>3317</SelStart2><SelEnd2>3317</SelEnd2></Tab><Tab><Factory>TextEditor</Factory><Filename>$WS_DIR$\..\APP\inc\stm32f10x_it.h</Filename><XPos>0</XPos><YPos>0</YPos><SelStart>0</SelStart><SelEnd>0</SelEnd><XPos2>0</XPos2><YPos2>2</YPos2><SelStart2>821</SelStart2><SelEnd2>821</SelEnd2></Tab></Pane><ActivePane>0</ActivePane><Sizes><Pane><X>1000000</X><Y>1000000</Y></Pane></Sizes><SplitMode>1</SplitMode></Editor>
|
||||||
<Positions>
|
<Positions>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<Top><Row0><Sizes><Toolbar-00ec6ca0><key>iaridepm.enu1</key></Toolbar-00ec6ca0></Sizes></Row0></Top><Left><Row0><Sizes><Wnd2><Rect><Top>-2</Top><Left>-2</Left><Bottom>623</Bottom><Right>312</Right><x>-2</x><y>-2</y><xscreen>200</xscreen><yscreen>200</yscreen><sizeHorzCX>119048</sizeHorzCX><sizeHorzCY>206612</sizeHorzCY><sizeVertCX>186905</sizeVertCX><sizeVertCY>645661</sizeVertCY></Rect></Wnd2></Sizes></Row0></Left><Right><Row0><Sizes/></Row0></Right><Bottom><Row0><Sizes><Wnd3><Rect><Top>-2</Top><Left>-2</Left><Bottom>300</Bottom><Right>1682</Right><x>-2</x><y>-2</y><xscreen>1684</xscreen><yscreen>302</yscreen><sizeHorzCX>1002381</sizeHorzCX><sizeHorzCY>311983</sizeHorzCY><sizeVertCX>119048</sizeVertCX><sizeVertCY>206612</sizeVertCY></Rect></Wnd3></Sizes></Row0></Bottom><Float><Sizes/></Float></Positions>
|
<Top><Row0><Sizes><Toolbar-00fa4588><key>iaridepm.enu1</key></Toolbar-00fa4588></Sizes></Row0><Row1><Sizes/></Row1></Top><Left><Row0><Sizes><Wnd0><Rect><Top>-2</Top><Left>-2</Left><Bottom>421</Bottom><Right>298</Right><x>-2</x><y>-2</y><xscreen>302</xscreen><yscreen>142</yscreen><sizeHorzCX>242765</sizeHorzCX><sizeHorzCY>209131</sizeHorzCY><sizeVertCX>241158</sizeVertCX><sizeVertCY>622975</sizeVertCY></Rect></Wnd0></Sizes></Row0></Left><Right><Row0><Sizes/></Row0></Right><Bottom><Row0><Sizes><Wnd1><Rect><Top>-2</Top><Left>-2</Left><Bottom>213</Bottom><Right>1246</Right><x>-2</x><y>-2</y><xscreen>1248</xscreen><yscreen>215</yscreen><sizeHorzCX>1003215</sizeHorzCX><sizeHorzCY>316642</sizeHorzCY><sizeVertCX>242765</sizeVertCX><sizeVertCY>209131</sizeVertCY></Rect></Wnd1></Sizes></Row0></Bottom><Float><Sizes/></Float></Positions>
|
||||||
</Desktop>
|
</Desktop>
|
||||||
</Workspace>
|
</Workspace>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,485 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||||
|
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* File: $Id: mbascii.c,v 1.15 2007/02/18 23:46:48 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ----------------------- System includes ----------------------------------*/
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
/* ----------------------- Platform includes --------------------------------*/
|
||||||
|
#include "port.h"
|
||||||
|
|
||||||
|
/* ----------------------- Modbus includes ----------------------------------*/
|
||||||
|
#include "mb.h"
|
||||||
|
#include "mbconfig.h"
|
||||||
|
#include "mbascii.h"
|
||||||
|
#include "mbframe.h"
|
||||||
|
|
||||||
|
#include "mbcrc.h"
|
||||||
|
#include "mbport.h"
|
||||||
|
|
||||||
|
#if MB_ASCII_ENABLED > 0
|
||||||
|
|
||||||
|
/* ----------------------- Defines ------------------------------------------*/
|
||||||
|
#define MB_ASCII_DEFAULT_CR '\r' /*!< Default CR character for Modbus ASCII. */
|
||||||
|
#define MB_ASCII_DEFAULT_LF '\n' /*!< Default LF character for Modbus ASCII. */
|
||||||
|
#define MB_SER_PDU_SIZE_MIN 3 /*!< Minimum size of a Modbus ASCII frame. */
|
||||||
|
#define MB_SER_PDU_SIZE_MAX 256 /*!< Maximum size of a Modbus ASCII frame. */
|
||||||
|
#define MB_SER_PDU_SIZE_LRC 1 /*!< Size of LRC field in PDU. */
|
||||||
|
#define MB_SER_PDU_ADDR_OFF 0 /*!< Offset of slave address in Ser-PDU. */
|
||||||
|
#define MB_SER_PDU_PDU_OFF 1 /*!< Offset of Modbus-PDU in Ser-PDU. */
|
||||||
|
|
||||||
|
/* ----------------------- Type definitions ---------------------------------*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
STATE_RX_IDLE, /*!< Receiver is in idle state. */
|
||||||
|
STATE_RX_RCV, /*!< Frame is beeing received. */
|
||||||
|
STATE_RX_WAIT_EOF /*!< Wait for End of Frame. */
|
||||||
|
} eMBRcvState;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
STATE_TX_IDLE, /*!< Transmitter is in idle state. */
|
||||||
|
STATE_TX_START, /*!< Starting transmission (':' sent). */
|
||||||
|
STATE_TX_DATA, /*!< Sending of data (Address, Data, LRC). */
|
||||||
|
STATE_TX_END, /*!< End of transmission. */
|
||||||
|
STATE_TX_NOTIFY /*!< Notify sender that the frame has been sent. */
|
||||||
|
} eMBSndState;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
BYTE_HIGH_NIBBLE, /*!< Character for high nibble of byte. */
|
||||||
|
BYTE_LOW_NIBBLE /*!< Character for low nibble of byte. */
|
||||||
|
} eMBBytePos;
|
||||||
|
|
||||||
|
/* ----------------------- Static functions ---------------------------------*/
|
||||||
|
static UCHAR prvucMBCHAR2BIN( UCHAR ucCharacter );
|
||||||
|
|
||||||
|
static UCHAR prvucMBBIN2CHAR( UCHAR ucByte );
|
||||||
|
|
||||||
|
static UCHAR prvucMBLRC( UCHAR * pucFrame, USHORT usLen );
|
||||||
|
|
||||||
|
/* ----------------------- Static variables ---------------------------------*/
|
||||||
|
static volatile eMBSndState eSndState;
|
||||||
|
static volatile eMBRcvState eRcvState;
|
||||||
|
|
||||||
|
/* We reuse the Modbus RTU buffer because only one buffer is needed and the
|
||||||
|
* RTU buffer is bigger. */
|
||||||
|
extern volatile UCHAR ucRTUBuf[];
|
||||||
|
static volatile UCHAR *ucASCIIBuf = ucRTUBuf;
|
||||||
|
|
||||||
|
static volatile USHORT usRcvBufferPos;
|
||||||
|
static volatile eMBBytePos eBytePos;
|
||||||
|
|
||||||
|
static volatile UCHAR *pucSndBufferCur;
|
||||||
|
static volatile USHORT usSndBufferCount;
|
||||||
|
|
||||||
|
static volatile UCHAR ucLRC;
|
||||||
|
static volatile UCHAR ucMBLFCharacter;
|
||||||
|
|
||||||
|
/* ----------------------- Start implementation -----------------------------*/
|
||||||
|
eMBErrorCode
|
||||||
|
eMBASCIIInit( UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity )
|
||||||
|
{
|
||||||
|
eMBErrorCode eStatus = MB_ENOERR;
|
||||||
|
( void )ucSlaveAddress;
|
||||||
|
|
||||||
|
ENTER_CRITICAL_SECTION( );
|
||||||
|
ucMBLFCharacter = MB_ASCII_DEFAULT_LF;
|
||||||
|
|
||||||
|
if( xMBPortSerialInit( ucPort, ulBaudRate, 7, eParity ) != TRUE )
|
||||||
|
{
|
||||||
|
eStatus = MB_EPORTERR;
|
||||||
|
}
|
||||||
|
else if( xMBPortTimersInit( MB_ASCII_TIMEOUT_SEC * 20000UL ) != TRUE )
|
||||||
|
{
|
||||||
|
eStatus = MB_EPORTERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXIT_CRITICAL_SECTION( );
|
||||||
|
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
eMBASCIIStart( void )
|
||||||
|
{
|
||||||
|
ENTER_CRITICAL_SECTION( );
|
||||||
|
vMBPortSerialEnable( TRUE, FALSE );
|
||||||
|
eRcvState = STATE_RX_IDLE;
|
||||||
|
EXIT_CRITICAL_SECTION( );
|
||||||
|
|
||||||
|
/* No special startup required for ASCII. */
|
||||||
|
( void )xMBPortEventPost( EV_READY );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
eMBASCIIStop( void )
|
||||||
|
{
|
||||||
|
ENTER_CRITICAL_SECTION( );
|
||||||
|
vMBPortSerialEnable( FALSE, FALSE );
|
||||||
|
vMBPortTimersDisable( );
|
||||||
|
EXIT_CRITICAL_SECTION( );
|
||||||
|
}
|
||||||
|
|
||||||
|
eMBErrorCode
|
||||||
|
eMBASCIIReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength )
|
||||||
|
{
|
||||||
|
eMBErrorCode eStatus = MB_ENOERR;
|
||||||
|
|
||||||
|
ENTER_CRITICAL_SECTION( );
|
||||||
|
assert( usRcvBufferPos < MB_SER_PDU_SIZE_MAX );
|
||||||
|
|
||||||
|
/* Length and CRC check */
|
||||||
|
if( ( usRcvBufferPos >= MB_SER_PDU_SIZE_MIN )
|
||||||
|
&& ( prvucMBLRC( ( UCHAR * ) ucASCIIBuf, usRcvBufferPos ) == 0 ) )
|
||||||
|
{
|
||||||
|
/* Save the address field. All frames are passed to the upper layed
|
||||||
|
* and the decision if a frame is used is done there.
|
||||||
|
*/
|
||||||
|
*pucRcvAddress = ucASCIIBuf[MB_SER_PDU_ADDR_OFF];
|
||||||
|
|
||||||
|
/* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus
|
||||||
|
* size of address field and CRC checksum.
|
||||||
|
*/
|
||||||
|
*pusLength = ( USHORT )( usRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_LRC );
|
||||||
|
|
||||||
|
/* Return the start of the Modbus PDU to the caller. */
|
||||||
|
*pucFrame = ( UCHAR * ) & ucASCIIBuf[MB_SER_PDU_PDU_OFF];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eStatus = MB_EIO;
|
||||||
|
}
|
||||||
|
EXIT_CRITICAL_SECTION( );
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
eMBErrorCode
|
||||||
|
eMBASCIISend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength )
|
||||||
|
{
|
||||||
|
eMBErrorCode eStatus = MB_ENOERR;
|
||||||
|
UCHAR usLRC;
|
||||||
|
|
||||||
|
ENTER_CRITICAL_SECTION( );
|
||||||
|
/* Check if the receiver is still in idle state. If not we where to
|
||||||
|
* slow with processing the received frame and the master sent another
|
||||||
|
* frame on the network. We have to abort sending the frame.
|
||||||
|
*/
|
||||||
|
if( eRcvState == STATE_RX_IDLE )
|
||||||
|
{
|
||||||
|
/* First byte before the Modbus-PDU is the slave address. */
|
||||||
|
pucSndBufferCur = ( UCHAR * ) pucFrame - 1;
|
||||||
|
usSndBufferCount = 1;
|
||||||
|
|
||||||
|
/* Now copy the Modbus-PDU into the Modbus-Serial-Line-PDU. */
|
||||||
|
pucSndBufferCur[MB_SER_PDU_ADDR_OFF] = ucSlaveAddress;
|
||||||
|
usSndBufferCount += usLength;
|
||||||
|
|
||||||
|
/* Calculate LRC checksum for Modbus-Serial-Line-PDU. */
|
||||||
|
usLRC = prvucMBLRC( ( UCHAR * ) pucSndBufferCur, usSndBufferCount );
|
||||||
|
ucASCIIBuf[usSndBufferCount++] = usLRC;
|
||||||
|
|
||||||
|
/* Activate the transmitter. */
|
||||||
|
eSndState = STATE_TX_START;
|
||||||
|
vMBPortSerialEnable( FALSE, TRUE );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eStatus = MB_EIO;
|
||||||
|
}
|
||||||
|
EXIT_CRITICAL_SECTION( );
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
xMBASCIIReceiveFSM( void )
|
||||||
|
{
|
||||||
|
BOOL xNeedPoll = FALSE;
|
||||||
|
UCHAR ucByte;
|
||||||
|
UCHAR ucResult;
|
||||||
|
|
||||||
|
assert( eSndState == STATE_TX_IDLE );
|
||||||
|
|
||||||
|
( void )xMBPortSerialGetByte( ( CHAR * ) & ucByte );
|
||||||
|
switch ( eRcvState )
|
||||||
|
{
|
||||||
|
/* A new character is received. If the character is a ':' the input
|
||||||
|
* buffer is cleared. A CR-character signals the end of the data
|
||||||
|
* block. Other characters are part of the data block and their
|
||||||
|
* ASCII value is converted back to a binary representation.
|
||||||
|
*/
|
||||||
|
case STATE_RX_RCV:
|
||||||
|
/* Enable timer for character timeout. */
|
||||||
|
vMBPortTimersEnable( );
|
||||||
|
if( ucByte == ':' )
|
||||||
|
{
|
||||||
|
/* Empty receive buffer. */
|
||||||
|
eBytePos = BYTE_HIGH_NIBBLE;
|
||||||
|
usRcvBufferPos = 0;
|
||||||
|
}
|
||||||
|
else if( ucByte == MB_ASCII_DEFAULT_CR )
|
||||||
|
{
|
||||||
|
eRcvState = STATE_RX_WAIT_EOF;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ucResult = prvucMBCHAR2BIN( ucByte );
|
||||||
|
switch ( eBytePos )
|
||||||
|
{
|
||||||
|
/* High nibble of the byte comes first. We check for
|
||||||
|
* a buffer overflow here. */
|
||||||
|
case BYTE_HIGH_NIBBLE:
|
||||||
|
if( usRcvBufferPos < MB_SER_PDU_SIZE_MAX )
|
||||||
|
{
|
||||||
|
ucASCIIBuf[usRcvBufferPos] = ( UCHAR )( ucResult << 4 );
|
||||||
|
eBytePos = BYTE_LOW_NIBBLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* not handled in Modbus specification but seems
|
||||||
|
* a resonable implementation. */
|
||||||
|
eRcvState = STATE_RX_IDLE;
|
||||||
|
/* Disable previously activated timer because of error state. */
|
||||||
|
vMBPortTimersDisable( );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BYTE_LOW_NIBBLE:
|
||||||
|
ucASCIIBuf[usRcvBufferPos++] |= ucResult;
|
||||||
|
eBytePos = BYTE_HIGH_NIBBLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATE_RX_WAIT_EOF:
|
||||||
|
if( ucByte == ucMBLFCharacter )
|
||||||
|
{
|
||||||
|
/* Disable character timeout timer because all characters are
|
||||||
|
* received. */
|
||||||
|
vMBPortTimersDisable( );
|
||||||
|
/* Receiver is again in idle state. */
|
||||||
|
eRcvState = STATE_RX_IDLE;
|
||||||
|
|
||||||
|
/* Notify the caller of eMBASCIIReceive that a new frame
|
||||||
|
* was received. */
|
||||||
|
xNeedPoll = xMBPortEventPost( EV_FRAME_RECEIVED );
|
||||||
|
}
|
||||||
|
else if( ucByte == ':' )
|
||||||
|
{
|
||||||
|
/* Empty receive buffer and back to receive state. */
|
||||||
|
eBytePos = BYTE_HIGH_NIBBLE;
|
||||||
|
usRcvBufferPos = 0;
|
||||||
|
eRcvState = STATE_RX_RCV;
|
||||||
|
|
||||||
|
/* Enable timer for character timeout. */
|
||||||
|
vMBPortTimersEnable( );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Frame is not okay. Delete entire frame. */
|
||||||
|
eRcvState = STATE_RX_IDLE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATE_RX_IDLE:
|
||||||
|
if( ucByte == ':' )
|
||||||
|
{
|
||||||
|
/* Enable timer for character timeout. */
|
||||||
|
vMBPortTimersEnable( );
|
||||||
|
/* Reset the input buffers to store the frame. */
|
||||||
|
usRcvBufferPos = 0;;
|
||||||
|
eBytePos = BYTE_HIGH_NIBBLE;
|
||||||
|
eRcvState = STATE_RX_RCV;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return xNeedPoll;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
xMBASCIITransmitFSM( void )
|
||||||
|
{
|
||||||
|
BOOL xNeedPoll = FALSE;
|
||||||
|
UCHAR ucByte;
|
||||||
|
|
||||||
|
assert( eRcvState == STATE_RX_IDLE );
|
||||||
|
switch ( eSndState )
|
||||||
|
{
|
||||||
|
/* Start of transmission. The start of a frame is defined by sending
|
||||||
|
* the character ':'. */
|
||||||
|
case STATE_TX_START:
|
||||||
|
ucByte = ':';
|
||||||
|
xMBPortSerialPutByte( ( CHAR )ucByte );
|
||||||
|
eSndState = STATE_TX_DATA;
|
||||||
|
eBytePos = BYTE_HIGH_NIBBLE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Send the data block. Each data byte is encoded as a character hex
|
||||||
|
* stream with the high nibble sent first and the low nibble sent
|
||||||
|
* last. If all data bytes are exhausted we send a '\r' character
|
||||||
|
* to end the transmission. */
|
||||||
|
case STATE_TX_DATA:
|
||||||
|
if( usSndBufferCount > 0 )
|
||||||
|
{
|
||||||
|
switch ( eBytePos )
|
||||||
|
{
|
||||||
|
case BYTE_HIGH_NIBBLE:
|
||||||
|
ucByte = prvucMBBIN2CHAR( ( UCHAR )( *pucSndBufferCur >> 4 ) );
|
||||||
|
xMBPortSerialPutByte( ( CHAR ) ucByte );
|
||||||
|
eBytePos = BYTE_LOW_NIBBLE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BYTE_LOW_NIBBLE:
|
||||||
|
ucByte = prvucMBBIN2CHAR( ( UCHAR )( *pucSndBufferCur & 0x0F ) );
|
||||||
|
xMBPortSerialPutByte( ( CHAR )ucByte );
|
||||||
|
pucSndBufferCur++;
|
||||||
|
eBytePos = BYTE_HIGH_NIBBLE;
|
||||||
|
usSndBufferCount--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xMBPortSerialPutByte( MB_ASCII_DEFAULT_CR );
|
||||||
|
eSndState = STATE_TX_END;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Finish the frame by sending a LF character. */
|
||||||
|
case STATE_TX_END:
|
||||||
|
xMBPortSerialPutByte( ( CHAR )ucMBLFCharacter );
|
||||||
|
/* We need another state to make sure that the CR character has
|
||||||
|
* been sent. */
|
||||||
|
eSndState = STATE_TX_NOTIFY;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Notify the task which called eMBASCIISend that the frame has
|
||||||
|
* been sent. */
|
||||||
|
case STATE_TX_NOTIFY:
|
||||||
|
eSndState = STATE_TX_IDLE;
|
||||||
|
xNeedPoll = xMBPortEventPost( EV_FRAME_SENT );
|
||||||
|
|
||||||
|
/* Disable transmitter. This prevents another transmit buffer
|
||||||
|
* empty interrupt. */
|
||||||
|
vMBPortSerialEnable( TRUE, FALSE );
|
||||||
|
eSndState = STATE_TX_IDLE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* We should not get a transmitter event if the transmitter is in
|
||||||
|
* idle state. */
|
||||||
|
case STATE_TX_IDLE:
|
||||||
|
/* enable receiver/disable transmitter. */
|
||||||
|
vMBPortSerialEnable( TRUE, FALSE );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return xNeedPoll;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
xMBASCIITimerT1SExpired( void )
|
||||||
|
{
|
||||||
|
switch ( eRcvState )
|
||||||
|
{
|
||||||
|
/* If we have a timeout we go back to the idle state and wait for
|
||||||
|
* the next frame.
|
||||||
|
*/
|
||||||
|
case STATE_RX_RCV:
|
||||||
|
case STATE_RX_WAIT_EOF:
|
||||||
|
eRcvState = STATE_RX_IDLE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert( ( eRcvState == STATE_RX_RCV ) || ( eRcvState == STATE_RX_WAIT_EOF ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
vMBPortTimersDisable( );
|
||||||
|
|
||||||
|
/* no context switch required. */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static UCHAR
|
||||||
|
prvucMBCHAR2BIN( UCHAR ucCharacter )
|
||||||
|
{
|
||||||
|
if( ( ucCharacter >= '0' ) && ( ucCharacter <= '9' ) )
|
||||||
|
{
|
||||||
|
return ( UCHAR )( ucCharacter - '0' );
|
||||||
|
}
|
||||||
|
else if( ( ucCharacter >= 'A' ) && ( ucCharacter <= 'F' ) )
|
||||||
|
{
|
||||||
|
return ( UCHAR )( ucCharacter - 'A' + 0x0A );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static UCHAR
|
||||||
|
prvucMBBIN2CHAR( UCHAR ucByte )
|
||||||
|
{
|
||||||
|
if( ucByte <= 0x09 )
|
||||||
|
{
|
||||||
|
return ( UCHAR )( '0' + ucByte );
|
||||||
|
}
|
||||||
|
else if( ( ucByte >= 0x0A ) && ( ucByte <= 0x0F ) )
|
||||||
|
{
|
||||||
|
return ( UCHAR )( ucByte - 0x0A + 'A' );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Programming error. */
|
||||||
|
assert( 0 );
|
||||||
|
}
|
||||||
|
return '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static UCHAR
|
||||||
|
prvucMBLRC( UCHAR * pucFrame, USHORT usLen )
|
||||||
|
{
|
||||||
|
UCHAR ucLRC = 0; /* LRC char initialized */
|
||||||
|
|
||||||
|
while( usLen-- )
|
||||||
|
{
|
||||||
|
ucLRC += *pucFrame++; /* Add buffer byte without carry */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return twos complement */
|
||||||
|
ucLRC = ( UCHAR ) ( -( ( CHAR ) ucLRC ) );
|
||||||
|
return ucLRC;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||||
|
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* File: $Id: mbascii.h,v 1.8 2006/12/07 22:10:34 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MB_ASCII_H
|
||||||
|
#define _MB_ASCII_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
PR_BEGIN_EXTERN_C
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MB_ASCII_ENABLED > 0
|
||||||
|
eMBErrorCode eMBASCIIInit( UCHAR slaveAddress, UCHAR ucPort,
|
||||||
|
ULONG ulBaudRate, eMBParity eParity );
|
||||||
|
void eMBASCIIStart( void );
|
||||||
|
void eMBASCIIStop( void );
|
||||||
|
|
||||||
|
eMBErrorCode eMBASCIIReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame,
|
||||||
|
USHORT * pusLength );
|
||||||
|
eMBErrorCode eMBASCIISend( UCHAR slaveAddress, const UCHAR * pucFrame,
|
||||||
|
USHORT usLength );
|
||||||
|
BOOL xMBASCIIReceiveFSM( void );
|
||||||
|
BOOL xMBASCIITransmitFSM( void );
|
||||||
|
BOOL xMBASCIITimerT1SExpired( void );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
PR_END_EXTERN_C
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,270 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||||
|
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* File: $Id: mbfunccoils.c,v 1.8 2007/02/18 23:47:16 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ----------------------- System includes ----------------------------------*/
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
/* ----------------------- Platform includes --------------------------------*/
|
||||||
|
#include "port.h"
|
||||||
|
|
||||||
|
/* ----------------------- Modbus includes ----------------------------------*/
|
||||||
|
#include "mb.h"
|
||||||
|
#include "mbframe.h"
|
||||||
|
#include "mbproto.h"
|
||||||
|
#include "mbconfig.h"
|
||||||
|
|
||||||
|
/* ----------------------- Defines ------------------------------------------*/
|
||||||
|
#define MB_PDU_FUNC_READ_ADDR_OFF ( MB_PDU_DATA_OFF )
|
||||||
|
#define MB_PDU_FUNC_READ_COILCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||||
|
#define MB_PDU_FUNC_READ_SIZE ( 4 )
|
||||||
|
#define MB_PDU_FUNC_READ_COILCNT_MAX ( 0x07D0 )
|
||||||
|
|
||||||
|
#define MB_PDU_FUNC_WRITE_ADDR_OFF ( MB_PDU_DATA_OFF )
|
||||||
|
#define MB_PDU_FUNC_WRITE_VALUE_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||||
|
#define MB_PDU_FUNC_WRITE_SIZE ( 4 )
|
||||||
|
|
||||||
|
#define MB_PDU_FUNC_WRITE_MUL_ADDR_OFF ( MB_PDU_DATA_OFF )
|
||||||
|
#define MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||||
|
#define MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF ( MB_PDU_DATA_OFF + 4 )
|
||||||
|
#define MB_PDU_FUNC_WRITE_MUL_VALUES_OFF ( MB_PDU_DATA_OFF + 5 )
|
||||||
|
#define MB_PDU_FUNC_WRITE_MUL_SIZE_MIN ( 5 )
|
||||||
|
#define MB_PDU_FUNC_WRITE_MUL_COILCNT_MAX ( 0x07B0 )
|
||||||
|
|
||||||
|
/* ----------------------- Static functions ---------------------------------*/
|
||||||
|
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
|
||||||
|
|
||||||
|
/* ----------------------- Start implementation -----------------------------*/
|
||||||
|
|
||||||
|
#if MB_FUNC_READ_COILS_ENABLED > 0
|
||||||
|
|
||||||
|
eMBException
|
||||||
|
eMBFuncReadCoils( UCHAR * pucFrame, USHORT * usLen )
|
||||||
|
{
|
||||||
|
USHORT usRegAddress;
|
||||||
|
USHORT usCoilCount;
|
||||||
|
UCHAR ucNBytes;
|
||||||
|
UCHAR *pucFrameCur;
|
||||||
|
|
||||||
|
eMBException eStatus = MB_EX_NONE;
|
||||||
|
eMBErrorCode eRegStatus;
|
||||||
|
|
||||||
|
if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
|
||||||
|
{
|
||||||
|
usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
|
||||||
|
usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
|
||||||
|
usRegAddress++;
|
||||||
|
|
||||||
|
usCoilCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_COILCNT_OFF] << 8 );
|
||||||
|
usCoilCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_COILCNT_OFF + 1] );
|
||||||
|
|
||||||
|
/* Check if the number of registers to read is valid. If not
|
||||||
|
* return Modbus illegal data value exception.
|
||||||
|
*/
|
||||||
|
if( ( usCoilCount >= 1 ) &&
|
||||||
|
( usCoilCount < MB_PDU_FUNC_READ_COILCNT_MAX ) )
|
||||||
|
{
|
||||||
|
/* Set the current PDU data pointer to the beginning. */
|
||||||
|
pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
|
||||||
|
*usLen = MB_PDU_FUNC_OFF;
|
||||||
|
|
||||||
|
/* First byte contains the function code. */
|
||||||
|
*pucFrameCur++ = MB_FUNC_READ_COILS;
|
||||||
|
*usLen += 1;
|
||||||
|
|
||||||
|
/* Test if the quantity of coils is a multiple of 8. If not last
|
||||||
|
* byte is only partially field with unused coils set to zero. */
|
||||||
|
if( ( usCoilCount & 0x0007 ) != 0 )
|
||||||
|
{
|
||||||
|
ucNBytes = ( UCHAR )( usCoilCount / 8 + 1 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ucNBytes = ( UCHAR )( usCoilCount / 8 );
|
||||||
|
}
|
||||||
|
*pucFrameCur++ = ucNBytes;
|
||||||
|
*usLen += 1;
|
||||||
|
|
||||||
|
eRegStatus =
|
||||||
|
eMBRegCoilsCB( pucFrameCur, usRegAddress, usCoilCount,
|
||||||
|
MB_REG_READ );
|
||||||
|
|
||||||
|
/* If an error occured convert it into a Modbus exception. */
|
||||||
|
if( eRegStatus != MB_ENOERR )
|
||||||
|
{
|
||||||
|
eStatus = prveMBError2Exception( eRegStatus );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* The response contains the function code, the starting address
|
||||||
|
* and the quantity of registers. We reuse the old values in the
|
||||||
|
* buffer because they are still valid. */
|
||||||
|
*usLen += ucNBytes;;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Can't be a valid read coil register request because the length
|
||||||
|
* is incorrect. */
|
||||||
|
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||||
|
}
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MB_FUNC_WRITE_COIL_ENABLED > 0
|
||||||
|
eMBException
|
||||||
|
eMBFuncWriteCoil( UCHAR * pucFrame, USHORT * usLen )
|
||||||
|
{
|
||||||
|
USHORT usRegAddress;
|
||||||
|
UCHAR ucBuf[2];
|
||||||
|
|
||||||
|
eMBException eStatus = MB_EX_NONE;
|
||||||
|
eMBErrorCode eRegStatus;
|
||||||
|
|
||||||
|
if( *usLen == ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) )
|
||||||
|
{
|
||||||
|
usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8 );
|
||||||
|
usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF + 1] );
|
||||||
|
usRegAddress++;
|
||||||
|
|
||||||
|
if( ( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF + 1] == 0x00 ) &&
|
||||||
|
( ( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0xFF ) ||
|
||||||
|
( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0x00 ) ) )
|
||||||
|
{
|
||||||
|
ucBuf[1] = 0;
|
||||||
|
if( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0xFF )
|
||||||
|
{
|
||||||
|
ucBuf[0] = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ucBuf[0] = 0;
|
||||||
|
}
|
||||||
|
eRegStatus =
|
||||||
|
eMBRegCoilsCB( &ucBuf[0], usRegAddress, 1, MB_REG_WRITE );
|
||||||
|
|
||||||
|
/* If an error occured convert it into a Modbus exception. */
|
||||||
|
if( eRegStatus != MB_ENOERR )
|
||||||
|
{
|
||||||
|
eStatus = prveMBError2Exception( eRegStatus );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Can't be a valid write coil register request because the length
|
||||||
|
* is incorrect. */
|
||||||
|
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||||
|
}
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED > 0
|
||||||
|
eMBException
|
||||||
|
eMBFuncWriteMultipleCoils( UCHAR * pucFrame, USHORT * usLen )
|
||||||
|
{
|
||||||
|
USHORT usRegAddress;
|
||||||
|
USHORT usCoilCnt;
|
||||||
|
UCHAR ucByteCount;
|
||||||
|
UCHAR ucByteCountVerify;
|
||||||
|
|
||||||
|
eMBException eStatus = MB_EX_NONE;
|
||||||
|
eMBErrorCode eRegStatus;
|
||||||
|
|
||||||
|
if( *usLen > ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) )
|
||||||
|
{
|
||||||
|
usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF] << 8 );
|
||||||
|
usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF + 1] );
|
||||||
|
usRegAddress++;
|
||||||
|
|
||||||
|
usCoilCnt = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF] << 8 );
|
||||||
|
usCoilCnt |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF + 1] );
|
||||||
|
|
||||||
|
ucByteCount = pucFrame[MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF];
|
||||||
|
|
||||||
|
/* Compute the number of expected bytes in the request. */
|
||||||
|
if( ( usCoilCnt & 0x0007 ) != 0 )
|
||||||
|
{
|
||||||
|
ucByteCountVerify = ( UCHAR )( usCoilCnt / 8 + 1 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ucByteCountVerify = ( UCHAR )( usCoilCnt / 8 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ( usCoilCnt >= 1 ) &&
|
||||||
|
( usCoilCnt <= MB_PDU_FUNC_WRITE_MUL_COILCNT_MAX ) &&
|
||||||
|
( ucByteCountVerify == ucByteCount ) )
|
||||||
|
{
|
||||||
|
eRegStatus =
|
||||||
|
eMBRegCoilsCB( &pucFrame[MB_PDU_FUNC_WRITE_MUL_VALUES_OFF],
|
||||||
|
usRegAddress, usCoilCnt, MB_REG_WRITE );
|
||||||
|
|
||||||
|
/* If an error occured convert it into a Modbus exception. */
|
||||||
|
if( eRegStatus != MB_ENOERR )
|
||||||
|
{
|
||||||
|
eStatus = prveMBError2Exception( eRegStatus );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* The response contains the function code, the starting address
|
||||||
|
* and the quantity of registers. We reuse the old values in the
|
||||||
|
* buffer because they are still valid. */
|
||||||
|
*usLen = MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Can't be a valid write coil register request because the length
|
||||||
|
* is incorrect. */
|
||||||
|
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||||
|
}
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||||
|
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* File: $Id: mbfuncdiag.c,v 1.3 2006/12/07 22:10:34 wolti Exp $
|
||||||
|
*/
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* FreeRTOS Modbus Libary: A Modbus serial implementation for FreeRTOS
|
||||||
|
* Copyright (C) 2006 Christian Walter <wolti@sil.at>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------------------- System includes ----------------------------------*/
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
/* ----------------------- Platform includes --------------------------------*/
|
||||||
|
#include "port.h"
|
||||||
|
|
||||||
|
/* ----------------------- Modbus includes ----------------------------------*/
|
||||||
|
#include "mb.h"
|
||||||
|
#include "mbframe.h"
|
||||||
|
#include "mbproto.h"
|
||||||
|
#include "mbconfig.h"
|
||||||
|
|
||||||
|
/* ----------------------- Defines ------------------------------------------*/
|
||||||
|
#define MB_PDU_FUNC_READ_ADDR_OFF ( MB_PDU_DATA_OFF )
|
||||||
|
#define MB_PDU_FUNC_READ_DISCCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||||
|
#define MB_PDU_FUNC_READ_SIZE ( 4 )
|
||||||
|
#define MB_PDU_FUNC_READ_DISCCNT_MAX ( 0x07D0 )
|
||||||
|
|
||||||
|
/* ----------------------- Static functions ---------------------------------*/
|
||||||
|
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
|
||||||
|
|
||||||
|
/* ----------------------- Start implementation -----------------------------*/
|
||||||
|
|
||||||
|
#if MB_FUNC_READ_COILS_ENABLED > 0
|
||||||
|
|
||||||
|
eMBException
|
||||||
|
eMBFuncReadDiscreteInputs( UCHAR * pucFrame, USHORT * usLen )
|
||||||
|
{
|
||||||
|
USHORT usRegAddress;
|
||||||
|
USHORT usDiscreteCnt;
|
||||||
|
UCHAR ucNBytes;
|
||||||
|
UCHAR *pucFrameCur;
|
||||||
|
|
||||||
|
eMBException eStatus = MB_EX_NONE;
|
||||||
|
eMBErrorCode eRegStatus;
|
||||||
|
|
||||||
|
if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
|
||||||
|
{
|
||||||
|
usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
|
||||||
|
usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
|
||||||
|
usRegAddress++;
|
||||||
|
|
||||||
|
usDiscreteCnt = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_DISCCNT_OFF] << 8 );
|
||||||
|
usDiscreteCnt |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_DISCCNT_OFF + 1] );
|
||||||
|
|
||||||
|
/* Check if the number of registers to read is valid. If not
|
||||||
|
* return Modbus illegal data value exception.
|
||||||
|
*/
|
||||||
|
if( ( usDiscreteCnt >= 1 ) &&
|
||||||
|
( usDiscreteCnt < MB_PDU_FUNC_READ_DISCCNT_MAX ) )
|
||||||
|
{
|
||||||
|
/* Set the current PDU data pointer to the beginning. */
|
||||||
|
pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
|
||||||
|
*usLen = MB_PDU_FUNC_OFF;
|
||||||
|
|
||||||
|
/* First byte contains the function code. */
|
||||||
|
*pucFrameCur++ = MB_FUNC_READ_DISCRETE_INPUTS;
|
||||||
|
*usLen += 1;
|
||||||
|
|
||||||
|
/* Test if the quantity of coils is a multiple of 8. If not last
|
||||||
|
* byte is only partially field with unused coils set to zero. */
|
||||||
|
if( ( usDiscreteCnt & 0x0007 ) != 0 )
|
||||||
|
{
|
||||||
|
ucNBytes = ( UCHAR ) ( usDiscreteCnt / 8 + 1 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ucNBytes = ( UCHAR ) ( usDiscreteCnt / 8 );
|
||||||
|
}
|
||||||
|
*pucFrameCur++ = ucNBytes;
|
||||||
|
*usLen += 1;
|
||||||
|
|
||||||
|
eRegStatus =
|
||||||
|
eMBRegDiscreteCB( pucFrameCur, usRegAddress, usDiscreteCnt );
|
||||||
|
|
||||||
|
/* If an error occured convert it into a Modbus exception. */
|
||||||
|
if( eRegStatus != MB_ENOERR )
|
||||||
|
{
|
||||||
|
eStatus = prveMBError2Exception( eRegStatus );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* The response contains the function code, the starting address
|
||||||
|
* and the quantity of registers. We reuse the old values in the
|
||||||
|
* buffer because they are still valid. */
|
||||||
|
*usLen += ucNBytes;;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Can't be a valid read coil register request because the length
|
||||||
|
* is incorrect. */
|
||||||
|
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||||
|
}
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,308 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||||
|
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* File: $Id: mbfuncholding.c,v 1.12 2007/02/18 23:48:22 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ----------------------- System includes ----------------------------------*/
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
/* ----------------------- Platform includes --------------------------------*/
|
||||||
|
#include "port.h"
|
||||||
|
|
||||||
|
/* ----------------------- Modbus includes ----------------------------------*/
|
||||||
|
#include "mb.h"
|
||||||
|
#include "mbframe.h"
|
||||||
|
#include "mbproto.h"
|
||||||
|
#include "mbconfig.h"
|
||||||
|
|
||||||
|
/* ----------------------- Defines ------------------------------------------*/
|
||||||
|
#define MB_PDU_FUNC_READ_ADDR_OFF ( MB_PDU_DATA_OFF + 0)
|
||||||
|
#define MB_PDU_FUNC_READ_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||||
|
#define MB_PDU_FUNC_READ_SIZE ( 4 )
|
||||||
|
#define MB_PDU_FUNC_READ_REGCNT_MAX ( 0x007D )
|
||||||
|
|
||||||
|
#define MB_PDU_FUNC_WRITE_ADDR_OFF ( MB_PDU_DATA_OFF + 0)
|
||||||
|
#define MB_PDU_FUNC_WRITE_VALUE_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||||
|
#define MB_PDU_FUNC_WRITE_SIZE ( 4 )
|
||||||
|
|
||||||
|
#define MB_PDU_FUNC_WRITE_MUL_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||||
|
#define MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||||
|
#define MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF ( MB_PDU_DATA_OFF + 4 )
|
||||||
|
#define MB_PDU_FUNC_WRITE_MUL_VALUES_OFF ( MB_PDU_DATA_OFF + 5 )
|
||||||
|
#define MB_PDU_FUNC_WRITE_MUL_SIZE_MIN ( 5 )
|
||||||
|
#define MB_PDU_FUNC_WRITE_MUL_REGCNT_MAX ( 0x0078 )
|
||||||
|
|
||||||
|
#define MB_PDU_FUNC_READWRITE_READ_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||||
|
#define MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||||
|
#define MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF ( MB_PDU_DATA_OFF + 4 )
|
||||||
|
#define MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF ( MB_PDU_DATA_OFF + 6 )
|
||||||
|
#define MB_PDU_FUNC_READWRITE_BYTECNT_OFF ( MB_PDU_DATA_OFF + 8 )
|
||||||
|
#define MB_PDU_FUNC_READWRITE_WRITE_VALUES_OFF ( MB_PDU_DATA_OFF + 9 )
|
||||||
|
#define MB_PDU_FUNC_READWRITE_SIZE_MIN ( 9 )
|
||||||
|
|
||||||
|
/* ----------------------- Static functions ---------------------------------*/
|
||||||
|
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
|
||||||
|
|
||||||
|
/* ----------------------- Start implementation -----------------------------*/
|
||||||
|
|
||||||
|
#if MB_FUNC_WRITE_HOLDING_ENABLED > 0
|
||||||
|
|
||||||
|
eMBException
|
||||||
|
eMBFuncWriteHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||||
|
{
|
||||||
|
USHORT usRegAddress;
|
||||||
|
eMBException eStatus = MB_EX_NONE;
|
||||||
|
eMBErrorCode eRegStatus;
|
||||||
|
|
||||||
|
if( *usLen == ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) )
|
||||||
|
{
|
||||||
|
usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8 );
|
||||||
|
usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF + 1] );
|
||||||
|
usRegAddress++;
|
||||||
|
|
||||||
|
/* Make callback to update the value. */
|
||||||
|
eRegStatus = eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF],
|
||||||
|
usRegAddress, 1, MB_REG_WRITE );
|
||||||
|
|
||||||
|
/* If an error occured convert it into a Modbus exception. */
|
||||||
|
if( eRegStatus != MB_ENOERR )
|
||||||
|
{
|
||||||
|
eStatus = prveMBError2Exception( eRegStatus );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Can't be a valid request because the length is incorrect. */
|
||||||
|
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||||
|
}
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0
|
||||||
|
eMBException
|
||||||
|
eMBFuncWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||||
|
{
|
||||||
|
USHORT usRegAddress;
|
||||||
|
USHORT usRegCount;
|
||||||
|
UCHAR ucRegByteCount;
|
||||||
|
|
||||||
|
eMBException eStatus = MB_EX_NONE;
|
||||||
|
eMBErrorCode eRegStatus;
|
||||||
|
|
||||||
|
if( *usLen >= ( MB_PDU_FUNC_WRITE_MUL_SIZE_MIN + MB_PDU_SIZE_MIN ) )
|
||||||
|
{
|
||||||
|
usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF] << 8 );
|
||||||
|
usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF + 1] );
|
||||||
|
usRegAddress++;
|
||||||
|
|
||||||
|
usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF] << 8 );
|
||||||
|
usRegCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF + 1] );
|
||||||
|
|
||||||
|
ucRegByteCount = pucFrame[MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF];
|
||||||
|
|
||||||
|
if( ( usRegCount >= 1 ) &&
|
||||||
|
( usRegCount <= MB_PDU_FUNC_WRITE_MUL_REGCNT_MAX ) &&
|
||||||
|
( ucRegByteCount == ( UCHAR ) ( 2 * usRegCount ) ) )
|
||||||
|
{
|
||||||
|
/* Make callback to update the register values. */
|
||||||
|
eRegStatus =
|
||||||
|
eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_WRITE_MUL_VALUES_OFF],
|
||||||
|
usRegAddress, usRegCount, MB_REG_WRITE );
|
||||||
|
|
||||||
|
/* If an error occured convert it into a Modbus exception. */
|
||||||
|
if( eRegStatus != MB_ENOERR )
|
||||||
|
{
|
||||||
|
eStatus = prveMBError2Exception( eRegStatus );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* The response contains the function code, the starting
|
||||||
|
* address and the quantity of registers. We reuse the
|
||||||
|
* old values in the buffer because they are still valid.
|
||||||
|
*/
|
||||||
|
*usLen = MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Can't be a valid request because the length is incorrect. */
|
||||||
|
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||||
|
}
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MB_FUNC_READ_HOLDING_ENABLED > 0
|
||||||
|
|
||||||
|
eMBException
|
||||||
|
eMBFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||||
|
{
|
||||||
|
USHORT usRegAddress;
|
||||||
|
USHORT usRegCount;
|
||||||
|
UCHAR *pucFrameCur;
|
||||||
|
|
||||||
|
eMBException eStatus = MB_EX_NONE;
|
||||||
|
eMBErrorCode eRegStatus;
|
||||||
|
|
||||||
|
if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
|
||||||
|
{
|
||||||
|
usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
|
||||||
|
usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
|
||||||
|
usRegAddress++;
|
||||||
|
|
||||||
|
usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8 );
|
||||||
|
usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );
|
||||||
|
|
||||||
|
/* Check if the number of registers to read is valid. If not
|
||||||
|
* return Modbus illegal data value exception.
|
||||||
|
*/
|
||||||
|
if( ( usRegCount >= 1 ) && ( usRegCount <= MB_PDU_FUNC_READ_REGCNT_MAX ) )
|
||||||
|
{
|
||||||
|
/* Set the current PDU data pointer to the beginning. */
|
||||||
|
pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
|
||||||
|
*usLen = MB_PDU_FUNC_OFF;
|
||||||
|
|
||||||
|
/* First byte contains the function code. */
|
||||||
|
*pucFrameCur++ = MB_FUNC_READ_HOLDING_REGISTER;
|
||||||
|
*usLen += 1;
|
||||||
|
|
||||||
|
/* Second byte in the response contain the number of bytes. */
|
||||||
|
*pucFrameCur++ = ( UCHAR ) ( usRegCount * 2 );
|
||||||
|
*usLen += 1;
|
||||||
|
|
||||||
|
/* Make callback to fill the buffer. */
|
||||||
|
eRegStatus = eMBRegHoldingCB( pucFrameCur, usRegAddress, usRegCount, MB_REG_READ );
|
||||||
|
/* If an error occured convert it into a Modbus exception. */
|
||||||
|
if( eRegStatus != MB_ENOERR )
|
||||||
|
{
|
||||||
|
eStatus = prveMBError2Exception( eRegStatus );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*usLen += usRegCount * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Can't be a valid request because the length is incorrect. */
|
||||||
|
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||||
|
}
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MB_FUNC_READWRITE_HOLDING_ENABLED > 0
|
||||||
|
|
||||||
|
eMBException
|
||||||
|
eMBFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||||
|
{
|
||||||
|
USHORT usRegReadAddress;
|
||||||
|
USHORT usRegReadCount;
|
||||||
|
USHORT usRegWriteAddress;
|
||||||
|
USHORT usRegWriteCount;
|
||||||
|
UCHAR ucRegWriteByteCount;
|
||||||
|
UCHAR *pucFrameCur;
|
||||||
|
|
||||||
|
eMBException eStatus = MB_EX_NONE;
|
||||||
|
eMBErrorCode eRegStatus;
|
||||||
|
|
||||||
|
if( *usLen >= ( MB_PDU_FUNC_READWRITE_SIZE_MIN + MB_PDU_SIZE_MIN ) )
|
||||||
|
{
|
||||||
|
usRegReadAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_READ_ADDR_OFF] << 8U );
|
||||||
|
usRegReadAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_READ_ADDR_OFF + 1] );
|
||||||
|
usRegReadAddress++;
|
||||||
|
|
||||||
|
usRegReadCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF] << 8U );
|
||||||
|
usRegReadCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF + 1] );
|
||||||
|
|
||||||
|
usRegWriteAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF] << 8U );
|
||||||
|
usRegWriteAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF + 1] );
|
||||||
|
usRegWriteAddress++;
|
||||||
|
|
||||||
|
usRegWriteCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF] << 8U );
|
||||||
|
usRegWriteCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF + 1] );
|
||||||
|
|
||||||
|
ucRegWriteByteCount = pucFrame[MB_PDU_FUNC_READWRITE_BYTECNT_OFF];
|
||||||
|
|
||||||
|
if( ( usRegReadCount >= 1 ) && ( usRegReadCount <= 0x7D ) &&
|
||||||
|
( usRegWriteCount >= 1 ) && ( usRegWriteCount <= 0x79 ) &&
|
||||||
|
( ( 2 * usRegWriteCount ) == ucRegWriteByteCount ) )
|
||||||
|
{
|
||||||
|
/* Make callback to update the register values. */
|
||||||
|
eRegStatus = eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_READWRITE_WRITE_VALUES_OFF],
|
||||||
|
usRegWriteAddress, usRegWriteCount, MB_REG_WRITE );
|
||||||
|
|
||||||
|
if( eRegStatus == MB_ENOERR )
|
||||||
|
{
|
||||||
|
/* Set the current PDU data pointer to the beginning. */
|
||||||
|
pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
|
||||||
|
*usLen = MB_PDU_FUNC_OFF;
|
||||||
|
|
||||||
|
/* First byte contains the function code. */
|
||||||
|
*pucFrameCur++ = MB_FUNC_READWRITE_MULTIPLE_REGISTERS;
|
||||||
|
*usLen += 1;
|
||||||
|
|
||||||
|
/* Second byte in the response contain the number of bytes. */
|
||||||
|
*pucFrameCur++ = ( UCHAR ) ( usRegReadCount * 2 );
|
||||||
|
*usLen += 1;
|
||||||
|
|
||||||
|
/* Make the read callback. */
|
||||||
|
eRegStatus =
|
||||||
|
eMBRegHoldingCB( pucFrameCur, usRegReadAddress, usRegReadCount, MB_REG_READ );
|
||||||
|
if( eRegStatus == MB_ENOERR )
|
||||||
|
{
|
||||||
|
*usLen += 2 * usRegReadCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( eRegStatus != MB_ENOERR )
|
||||||
|
{
|
||||||
|
eStatus = prveMBError2Exception( eRegStatus );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||||
|
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* File: $Id: mbfuncinput.c,v 1.10 2007/09/12 10:15:56 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ----------------------- System includes ----------------------------------*/
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
/* ----------------------- Platform includes --------------------------------*/
|
||||||
|
#include "port.h"
|
||||||
|
|
||||||
|
/* ----------------------- Modbus includes ----------------------------------*/
|
||||||
|
#include "mb.h"
|
||||||
|
#include "mbframe.h"
|
||||||
|
#include "mbproto.h"
|
||||||
|
#include "mbconfig.h"
|
||||||
|
|
||||||
|
/* ----------------------- Defines ------------------------------------------*/
|
||||||
|
#define MB_PDU_FUNC_READ_ADDR_OFF ( MB_PDU_DATA_OFF )
|
||||||
|
#define MB_PDU_FUNC_READ_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||||
|
#define MB_PDU_FUNC_READ_SIZE ( 4 )
|
||||||
|
#define MB_PDU_FUNC_READ_REGCNT_MAX ( 0x007D )
|
||||||
|
|
||||||
|
#define MB_PDU_FUNC_READ_RSP_BYTECNT_OFF ( MB_PDU_DATA_OFF )
|
||||||
|
|
||||||
|
/* ----------------------- Static functions ---------------------------------*/
|
||||||
|
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
|
||||||
|
|
||||||
|
/* ----------------------- Start implementation -----------------------------*/
|
||||||
|
#if MB_FUNC_READ_INPUT_ENABLED > 0
|
||||||
|
|
||||||
|
eMBException
|
||||||
|
eMBFuncReadInputRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||||
|
{
|
||||||
|
USHORT usRegAddress;
|
||||||
|
USHORT usRegCount;
|
||||||
|
UCHAR *pucFrameCur;
|
||||||
|
|
||||||
|
eMBException eStatus = MB_EX_NONE;
|
||||||
|
eMBErrorCode eRegStatus;
|
||||||
|
|
||||||
|
if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
|
||||||
|
{
|
||||||
|
usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
|
||||||
|
usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
|
||||||
|
usRegAddress++;
|
||||||
|
|
||||||
|
usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8 );
|
||||||
|
usRegCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );
|
||||||
|
|
||||||
|
/* Check if the number of registers to read is valid. If not
|
||||||
|
* return Modbus illegal data value exception.
|
||||||
|
*/
|
||||||
|
if( ( usRegCount >= 1 )
|
||||||
|
&& ( usRegCount < MB_PDU_FUNC_READ_REGCNT_MAX ) )
|
||||||
|
{
|
||||||
|
/* Set the current PDU data pointer to the beginning. */
|
||||||
|
pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
|
||||||
|
*usLen = MB_PDU_FUNC_OFF;
|
||||||
|
|
||||||
|
/* First byte contains the function code. */
|
||||||
|
*pucFrameCur++ = MB_FUNC_READ_INPUT_REGISTER;
|
||||||
|
*usLen += 1;
|
||||||
|
|
||||||
|
/* Second byte in the response contain the number of bytes. */
|
||||||
|
*pucFrameCur++ = ( UCHAR )( usRegCount * 2 );
|
||||||
|
*usLen += 1;
|
||||||
|
|
||||||
|
eRegStatus =
|
||||||
|
eMBRegInputCB( pucFrameCur, usRegAddress, usRegCount );
|
||||||
|
|
||||||
|
/* If an error occured convert it into a Modbus exception. */
|
||||||
|
if( eRegStatus != MB_ENOERR )
|
||||||
|
{
|
||||||
|
eStatus = prveMBError2Exception( eRegStatus );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*usLen += usRegCount * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Can't be a valid read input register request because the length
|
||||||
|
* is incorrect. */
|
||||||
|
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||||
|
}
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||||
|
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* File: $Id: mbfuncother.c,v 1.8 2006/12/07 22:10:34 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ----------------------- System includes ----------------------------------*/
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
/* ----------------------- Platform includes --------------------------------*/
|
||||||
|
#include "port.h"
|
||||||
|
|
||||||
|
/* ----------------------- Modbus includes ----------------------------------*/
|
||||||
|
#include "mb.h"
|
||||||
|
#include "mbframe.h"
|
||||||
|
#include "mbproto.h"
|
||||||
|
#include "mbconfig.h"
|
||||||
|
|
||||||
|
#if MB_FUNC_OTHER_REP_SLAVEID_ENABLED > 0
|
||||||
|
|
||||||
|
/* ----------------------- Static variables ---------------------------------*/
|
||||||
|
static UCHAR ucMBSlaveID[MB_FUNC_OTHER_REP_SLAVEID_BUF];
|
||||||
|
static USHORT usMBSlaveIDLen;
|
||||||
|
|
||||||
|
/* ----------------------- Start implementation -----------------------------*/
|
||||||
|
|
||||||
|
eMBErrorCode
|
||||||
|
eMBSetSlaveID( UCHAR ucSlaveID, BOOL xIsRunning,
|
||||||
|
UCHAR const *pucAdditional, USHORT usAdditionalLen )
|
||||||
|
{
|
||||||
|
eMBErrorCode eStatus = MB_ENOERR;
|
||||||
|
|
||||||
|
/* the first byte and second byte in the buffer is reserved for
|
||||||
|
* the parameter ucSlaveID and the running flag. The rest of
|
||||||
|
* the buffer is available for additional data. */
|
||||||
|
if( usAdditionalLen + 2 < MB_FUNC_OTHER_REP_SLAVEID_BUF )
|
||||||
|
{
|
||||||
|
usMBSlaveIDLen = 0;
|
||||||
|
ucMBSlaveID[usMBSlaveIDLen++] = ucSlaveID;
|
||||||
|
ucMBSlaveID[usMBSlaveIDLen++] = ( UCHAR )( xIsRunning ? 0xFF : 0x00 );
|
||||||
|
if( usAdditionalLen > 0 )
|
||||||
|
{
|
||||||
|
memcpy( &ucMBSlaveID[usMBSlaveIDLen], pucAdditional,
|
||||||
|
( size_t )usAdditionalLen );
|
||||||
|
usMBSlaveIDLen += usAdditionalLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eStatus = MB_ENORES;
|
||||||
|
}
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
eMBException
|
||||||
|
eMBFuncReportSlaveID( UCHAR * pucFrame, USHORT * usLen )
|
||||||
|
{
|
||||||
|
memcpy( &pucFrame[MB_PDU_DATA_OFF], &ucMBSlaveID[0], ( size_t )usMBSlaveIDLen );
|
||||||
|
*usLen = ( USHORT )( MB_PDU_DATA_OFF + usMBSlaveIDLen );
|
||||||
|
return MB_EX_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,141 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||||
|
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* File: $Id: mbutils.c,v 1.6 2007/02/18 23:49:07 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ----------------------- System includes ----------------------------------*/
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
/* ----------------------- Platform includes --------------------------------*/
|
||||||
|
#include "port.h"
|
||||||
|
|
||||||
|
/* ----------------------- Modbus includes ----------------------------------*/
|
||||||
|
#include "mb.h"
|
||||||
|
#include "mbproto.h"
|
||||||
|
|
||||||
|
/* ----------------------- Defines ------------------------------------------*/
|
||||||
|
#define BITS_UCHAR 8U
|
||||||
|
|
||||||
|
/* ----------------------- Start implementation -----------------------------*/
|
||||||
|
void
|
||||||
|
xMBUtilSetBits( UCHAR * ucByteBuf, USHORT usBitOffset, UCHAR ucNBits,
|
||||||
|
UCHAR ucValue )
|
||||||
|
{
|
||||||
|
USHORT usWordBuf;
|
||||||
|
USHORT usMask;
|
||||||
|
USHORT usByteOffset;
|
||||||
|
USHORT usNPreBits;
|
||||||
|
USHORT usValue = ucValue;
|
||||||
|
|
||||||
|
assert_param( ucNBits <= 8 );
|
||||||
|
assert_param( ( size_t )BITS_UCHAR == sizeof( UCHAR ) * 8 );
|
||||||
|
|
||||||
|
/* Calculate byte offset for first byte containing the bit values starting
|
||||||
|
* at usBitOffset. */
|
||||||
|
usByteOffset = ( USHORT )( ( usBitOffset ) / BITS_UCHAR );
|
||||||
|
|
||||||
|
/* How many bits precede our bits to set. */
|
||||||
|
usNPreBits = ( USHORT )( usBitOffset - usByteOffset * BITS_UCHAR );
|
||||||
|
|
||||||
|
/* Move bit field into position over bits to set */
|
||||||
|
usValue <<= usNPreBits;
|
||||||
|
|
||||||
|
/* Prepare a mask for setting the new bits. */
|
||||||
|
usMask = ( USHORT )( ( 1 << ( USHORT ) ucNBits ) - 1 );
|
||||||
|
usMask <<= usBitOffset - usByteOffset * BITS_UCHAR;
|
||||||
|
|
||||||
|
/* copy bits into temporary storage. */
|
||||||
|
usWordBuf = ucByteBuf[usByteOffset];
|
||||||
|
usWordBuf |= ucByteBuf[usByteOffset + 1] << BITS_UCHAR;
|
||||||
|
|
||||||
|
/* Zero out bit field bits and then or value bits into them. */
|
||||||
|
usWordBuf = ( USHORT )( ( usWordBuf & ( ~usMask ) ) | usValue );
|
||||||
|
|
||||||
|
/* move bits back into storage */
|
||||||
|
ucByteBuf[usByteOffset] = ( UCHAR )( usWordBuf & 0xFF );
|
||||||
|
ucByteBuf[usByteOffset + 1] = ( UCHAR )( usWordBuf >> BITS_UCHAR );
|
||||||
|
}
|
||||||
|
|
||||||
|
UCHAR
|
||||||
|
xMBUtilGetBits( UCHAR * ucByteBuf, USHORT usBitOffset, UCHAR ucNBits )
|
||||||
|
{
|
||||||
|
USHORT usWordBuf;
|
||||||
|
USHORT usMask;
|
||||||
|
USHORT usByteOffset;
|
||||||
|
USHORT usNPreBits;
|
||||||
|
|
||||||
|
/* Calculate byte offset for first byte containing the bit values starting
|
||||||
|
* at usBitOffset. */
|
||||||
|
usByteOffset = ( USHORT )( ( usBitOffset ) / BITS_UCHAR );
|
||||||
|
|
||||||
|
/* How many bits precede our bits to set. */
|
||||||
|
usNPreBits = ( USHORT )( usBitOffset - usByteOffset * BITS_UCHAR );
|
||||||
|
|
||||||
|
/* Prepare a mask for setting the new bits. */
|
||||||
|
usMask = ( USHORT )( ( 1 << ( USHORT ) ucNBits ) - 1 );
|
||||||
|
|
||||||
|
/* copy bits into temporary storage. */
|
||||||
|
usWordBuf = ucByteBuf[usByteOffset];
|
||||||
|
usWordBuf |= ucByteBuf[usByteOffset + 1] << BITS_UCHAR;
|
||||||
|
|
||||||
|
/* throw away unneeded bits. */
|
||||||
|
usWordBuf >>= usNPreBits;
|
||||||
|
|
||||||
|
/* mask away bits above the requested bitfield. */
|
||||||
|
usWordBuf &= usMask;
|
||||||
|
|
||||||
|
return ( UCHAR ) usWordBuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
eMBException
|
||||||
|
prveMBError2Exception( eMBErrorCode eErrorCode )
|
||||||
|
{
|
||||||
|
eMBException eStatus;
|
||||||
|
|
||||||
|
switch ( eErrorCode )
|
||||||
|
{
|
||||||
|
case MB_ENOERR:
|
||||||
|
eStatus = MB_EX_NONE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MB_ENOREG:
|
||||||
|
eStatus = MB_EX_ILLEGAL_DATA_ADDRESS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MB_ETIMEDOUT:
|
||||||
|
eStatus = MB_EX_SLAVE_BUSY;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
eStatus = MB_EX_SLAVE_DEVICE_FAILURE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return eStatus;
|
||||||
|
}
|
|
@ -0,0 +1,417 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||||
|
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* File: $Id: mb.h,v 1.17 2006/12/07 22:10:34 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MB_H
|
||||||
|
#define _MB_H
|
||||||
|
|
||||||
|
#include "port.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
PR_BEGIN_EXTERN_C
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "mbport.h"
|
||||||
|
#include "mbproto.h"
|
||||||
|
|
||||||
|
/*! \defgroup modbus Modbus
|
||||||
|
* \code #include "mb.h" \endcode
|
||||||
|
*
|
||||||
|
* This module defines the interface for the application. It contains
|
||||||
|
* the basic functions and types required to use the Modbus protocol stack.
|
||||||
|
* A typical application will want to call eMBInit() first. If the device
|
||||||
|
* is ready to answer network requests it must then call eMBEnable() to activate
|
||||||
|
* the protocol stack. In the main loop the function eMBPoll() must be called
|
||||||
|
* periodically. The time interval between pooling depends on the configured
|
||||||
|
* Modbus timeout. If an RTOS is available a separate task should be created
|
||||||
|
* and the task should always call the function eMBPoll().
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
* // Initialize protocol stack in RTU mode for a slave with address 10 = 0x0A
|
||||||
|
* eMBInit( MB_RTU, 0x0A, 38400, MB_PAR_EVEN );
|
||||||
|
* // Enable the Modbus Protocol Stack.
|
||||||
|
* eMBEnable( );
|
||||||
|
* for( ;; )
|
||||||
|
* {
|
||||||
|
* // Call the main polling loop of the Modbus protocol stack.
|
||||||
|
* eMBPoll( );
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
* \endcode
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ----------------------- Defines ------------------------------------------*/
|
||||||
|
|
||||||
|
/*! \ingroup modbus
|
||||||
|
* \brief Use the default Modbus TCP port (502)
|
||||||
|
*/
|
||||||
|
#define MB_TCP_PORT_USE_DEFAULT 0
|
||||||
|
|
||||||
|
/* ----------------------- Type definitions ---------------------------------*/
|
||||||
|
|
||||||
|
/*! \ingroup modbus
|
||||||
|
* \brief Modbus serial transmission modes (RTU/ASCII).
|
||||||
|
*
|
||||||
|
* Modbus serial supports two transmission modes. Either ASCII or RTU. RTU
|
||||||
|
* is faster but has more hardware requirements and requires a network with
|
||||||
|
* a low jitter. ASCII is slower and more reliable on slower links (E.g. modems)
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
MB_RTU, /*!< RTU transmission mode. */
|
||||||
|
MB_ASCII, /*!< ASCII transmission mode. */
|
||||||
|
MB_TCP /*!< TCP mode. */
|
||||||
|
} eMBMode;
|
||||||
|
|
||||||
|
/*! \ingroup modbus
|
||||||
|
* \brief If register should be written or read.
|
||||||
|
*
|
||||||
|
* This value is passed to the callback functions which support either
|
||||||
|
* reading or writing register values. Writing means that the application
|
||||||
|
* registers should be updated and reading means that the modbus protocol
|
||||||
|
* stack needs to know the current register values.
|
||||||
|
*
|
||||||
|
* \see eMBRegHoldingCB( ), eMBRegCoilsCB( ), eMBRegDiscreteCB( ) and
|
||||||
|
* eMBRegInputCB( ).
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
MB_REG_READ, /*!< Read register values and pass to protocol stack. */
|
||||||
|
MB_REG_WRITE /*!< Update register values. */
|
||||||
|
} eMBRegisterMode;
|
||||||
|
|
||||||
|
/*! \ingroup modbus
|
||||||
|
* \brief Errorcodes used by all function in the protocol stack.
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
MB_ENOERR, /*!< no error. */
|
||||||
|
MB_ENOREG, /*!< illegal register address. */
|
||||||
|
MB_EINVAL, /*!< illegal argument. */
|
||||||
|
MB_EPORTERR, /*!< porting layer error. */
|
||||||
|
MB_ENORES, /*!< insufficient resources. */
|
||||||
|
MB_EIO, /*!< I/O error. */
|
||||||
|
MB_EILLSTATE, /*!< protocol stack in illegal state. */
|
||||||
|
MB_ETIMEDOUT /*!< timeout error occurred. */
|
||||||
|
} eMBErrorCode;
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------------------- Function prototypes ------------------------------*/
|
||||||
|
/*! \ingroup modbus
|
||||||
|
* \brief Initialize the Modbus protocol stack.
|
||||||
|
*
|
||||||
|
* This functions initializes the ASCII or RTU module and calls the
|
||||||
|
* init functions of the porting layer to prepare the hardware. Please
|
||||||
|
* note that the receiver is still disabled and no Modbus frames are
|
||||||
|
* processed until eMBEnable( ) has been called.
|
||||||
|
*
|
||||||
|
* \param eMode If ASCII or RTU mode should be used.
|
||||||
|
* \param ucSlaveAddress The slave address. Only frames sent to this
|
||||||
|
* address or to the broadcast address are processed.
|
||||||
|
* \param ucPort The port to use. E.g. 1 for COM1 on windows. This value
|
||||||
|
* is platform dependent and some ports simply choose to ignore it.
|
||||||
|
* \param ulBaudRate The baudrate. E.g. 19200. Supported baudrates depend
|
||||||
|
* on the porting layer.
|
||||||
|
* \param eParity Parity used for serial transmission.
|
||||||
|
*
|
||||||
|
* \return If no error occurs the function returns eMBErrorCode::MB_ENOERR.
|
||||||
|
* The protocol is then in the disabled state and ready for activation
|
||||||
|
* by calling eMBEnable( ). Otherwise one of the following error codes
|
||||||
|
* is returned:
|
||||||
|
* - eMBErrorCode::MB_EINVAL If the slave address was not valid. Valid
|
||||||
|
* slave addresses are in the range 1 - 247.
|
||||||
|
* - eMBErrorCode::MB_EPORTERR IF the porting layer returned an error.
|
||||||
|
*/
|
||||||
|
eMBErrorCode eMBInit( eMBMode eMode, UCHAR ucSlaveAddress,
|
||||||
|
UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity );
|
||||||
|
|
||||||
|
/*! \ingroup modbus
|
||||||
|
* \brief Initialize the Modbus protocol stack for Modbus TCP.
|
||||||
|
*
|
||||||
|
* This function initializes the Modbus TCP Module. Please note that
|
||||||
|
* frame processing is still disabled until eMBEnable( ) is called.
|
||||||
|
*
|
||||||
|
* \param usTCPPort The TCP port to listen on.
|
||||||
|
* \return If the protocol stack has been initialized correctly the function
|
||||||
|
* returns eMBErrorCode::MB_ENOERR. Otherwise one of the following error
|
||||||
|
* codes is returned:
|
||||||
|
* - eMBErrorCode::MB_EINVAL If the slave address was not valid. Valid
|
||||||
|
* slave addresses are in the range 1 - 247.
|
||||||
|
* - eMBErrorCode::MB_EPORTERR IF the porting layer returned an error.
|
||||||
|
*/
|
||||||
|
eMBErrorCode eMBTCPInit( USHORT usTCPPort );
|
||||||
|
|
||||||
|
/*! \ingroup modbus
|
||||||
|
* \brief Release resources used by the protocol stack.
|
||||||
|
*
|
||||||
|
* This function disables the Modbus protocol stack and release all
|
||||||
|
* hardware resources. It must only be called when the protocol stack
|
||||||
|
* is disabled.
|
||||||
|
*
|
||||||
|
* \note Note all ports implement this function. A port which wants to
|
||||||
|
* get an callback must define the macro MB_PORT_HAS_CLOSE to 1.
|
||||||
|
*
|
||||||
|
* \return If the resources where released it return eMBErrorCode::MB_ENOERR.
|
||||||
|
* If the protocol stack is not in the disabled state it returns
|
||||||
|
* eMBErrorCode::MB_EILLSTATE.
|
||||||
|
*/
|
||||||
|
eMBErrorCode eMBClose( void );
|
||||||
|
|
||||||
|
/*! \ingroup modbus
|
||||||
|
* \brief Enable the Modbus protocol stack.
|
||||||
|
*
|
||||||
|
* This function enables processing of Modbus frames. Enabling the protocol
|
||||||
|
* stack is only possible if it is in the disabled state.
|
||||||
|
*
|
||||||
|
* \return If the protocol stack is now in the state enabled it returns
|
||||||
|
* eMBErrorCode::MB_ENOERR. If it was not in the disabled state it
|
||||||
|
* return eMBErrorCode::MB_EILLSTATE.
|
||||||
|
*/
|
||||||
|
eMBErrorCode eMBEnable( void );
|
||||||
|
|
||||||
|
/*! \ingroup modbus
|
||||||
|
* \brief Disable the Modbus protocol stack.
|
||||||
|
*
|
||||||
|
* This function disables processing of Modbus frames.
|
||||||
|
*
|
||||||
|
* \return If the protocol stack has been disabled it returns
|
||||||
|
* eMBErrorCode::MB_ENOERR. If it was not in the enabled state it returns
|
||||||
|
* eMBErrorCode::MB_EILLSTATE.
|
||||||
|
*/
|
||||||
|
eMBErrorCode eMBDisable( void );
|
||||||
|
|
||||||
|
/*! \ingroup modbus
|
||||||
|
* \brief The main pooling loop of the Modbus protocol stack.
|
||||||
|
*
|
||||||
|
* This function must be called periodically. The timer interval required
|
||||||
|
* is given by the application dependent Modbus slave timeout. Internally the
|
||||||
|
* function calls xMBPortEventGet() and waits for an event from the receiver or
|
||||||
|
* transmitter state machines.
|
||||||
|
*
|
||||||
|
* \return If the protocol stack is not in the enabled state the function
|
||||||
|
* returns eMBErrorCode::MB_EILLSTATE. Otherwise it returns
|
||||||
|
* eMBErrorCode::MB_ENOERR.
|
||||||
|
*/
|
||||||
|
eMBErrorCode eMBPoll( void );
|
||||||
|
|
||||||
|
/*! \ingroup modbus
|
||||||
|
* \brief Configure the slave id of the device.
|
||||||
|
*
|
||||||
|
* This function should be called when the Modbus function <em>Report Slave ID</em>
|
||||||
|
* is enabled ( By defining MB_FUNC_OTHER_REP_SLAVEID_ENABLED in mbconfig.h ).
|
||||||
|
*
|
||||||
|
* \param ucSlaveID Values is returned in the <em>Slave ID</em> byte of the
|
||||||
|
* <em>Report Slave ID</em> response.
|
||||||
|
* \param xIsRunning If TRUE the <em>Run Indicator Status</em> byte is set to 0xFF.
|
||||||
|
* otherwise the <em>Run Indicator Status</em> is 0x00.
|
||||||
|
* \param pucAdditional Values which should be returned in the <em>Additional</em>
|
||||||
|
* bytes of the <em> Report Slave ID</em> response.
|
||||||
|
* \param usAdditionalLen Length of the buffer <code>pucAdditonal</code>.
|
||||||
|
*
|
||||||
|
* \return If the static buffer defined by MB_FUNC_OTHER_REP_SLAVEID_BUF in
|
||||||
|
* mbconfig.h is to small it returns eMBErrorCode::MB_ENORES. Otherwise
|
||||||
|
* it returns eMBErrorCode::MB_ENOERR.
|
||||||
|
*/
|
||||||
|
eMBErrorCode eMBSetSlaveID( UCHAR ucSlaveID, BOOL xIsRunning,
|
||||||
|
UCHAR const *pucAdditional,
|
||||||
|
USHORT usAdditionalLen );
|
||||||
|
|
||||||
|
/*! \ingroup modbus
|
||||||
|
* \brief Registers a callback handler for a given function code.
|
||||||
|
*
|
||||||
|
* This function registers a new callback handler for a given function code.
|
||||||
|
* The callback handler supplied is responsible for interpreting the Modbus PDU and
|
||||||
|
* the creation of an appropriate response. In case of an error it should return
|
||||||
|
* one of the possible Modbus exceptions which results in a Modbus exception frame
|
||||||
|
* sent by the protocol stack.
|
||||||
|
*
|
||||||
|
* \param ucFunctionCode The Modbus function code for which this handler should
|
||||||
|
* be registers. Valid function codes are in the range 1 to 127.
|
||||||
|
* \param pxHandler The function handler which should be called in case
|
||||||
|
* such a frame is received. If \c NULL a previously registered function handler
|
||||||
|
* for this function code is removed.
|
||||||
|
*
|
||||||
|
* \return eMBErrorCode::MB_ENOERR if the handler has been installed. If no
|
||||||
|
* more resources are available it returns eMBErrorCode::MB_ENORES. In this
|
||||||
|
* case the values in mbconfig.h should be adjusted. If the argument was not
|
||||||
|
* valid it returns eMBErrorCode::MB_EINVAL.
|
||||||
|
*/
|
||||||
|
eMBErrorCode eMBRegisterCB( UCHAR ucFunctionCode,
|
||||||
|
pxMBFunctionHandler pxHandler );
|
||||||
|
|
||||||
|
/* ----------------------- Callback -----------------------------------------*/
|
||||||
|
|
||||||
|
/*! \defgroup modbus_registers Modbus Registers
|
||||||
|
* \code #include "mb.h" \endcode
|
||||||
|
* The protocol stack does not internally allocate any memory for the
|
||||||
|
* registers. This makes the protocol stack very small and also usable on
|
||||||
|
* low end targets. In addition the values don't have to be in the memory
|
||||||
|
* and could for example be stored in a flash.<br>
|
||||||
|
* Whenever the protocol stack requires a value it calls one of the callback
|
||||||
|
* function with the register address and the number of registers to read
|
||||||
|
* as an argument. The application should then read the actual register values
|
||||||
|
* (for example the ADC voltage) and should store the result in the supplied
|
||||||
|
* buffer.<br>
|
||||||
|
* If the protocol stack wants to update a register value because a write
|
||||||
|
* register function was received a buffer with the new register values is
|
||||||
|
* passed to the callback function. The function should then use these values
|
||||||
|
* to update the application register values.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! \ingroup modbus_registers
|
||||||
|
* \brief Callback function used if the value of a <em>Input Register</em>
|
||||||
|
* is required by the protocol stack. The starting register address is given
|
||||||
|
* by \c usAddress and the last register is given by <tt>usAddress +
|
||||||
|
* usNRegs - 1</tt>.
|
||||||
|
*
|
||||||
|
* \param pucRegBuffer A buffer where the callback function should write
|
||||||
|
* the current value of the modbus registers to.
|
||||||
|
* \param usAddress The starting address of the register. Input registers
|
||||||
|
* are in the range 1 - 65535.
|
||||||
|
* \param usNRegs Number of registers the callback function must supply.
|
||||||
|
*
|
||||||
|
* \return The function must return one of the following error codes:
|
||||||
|
* - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
|
||||||
|
* Modbus response is sent.
|
||||||
|
* - eMBErrorCode::MB_ENOREG If the application can not supply values
|
||||||
|
* for registers within this range. In this case a
|
||||||
|
* <b>ILLEGAL DATA ADDRESS</b> exception frame is sent as a response.
|
||||||
|
* - eMBErrorCode::MB_ETIMEDOUT If the requested register block is
|
||||||
|
* currently not available and the application dependent response
|
||||||
|
* timeout would be violated. In this case a <b>SLAVE DEVICE BUSY</b>
|
||||||
|
* exception is sent as a response.
|
||||||
|
* - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case
|
||||||
|
* a <b>SLAVE DEVICE FAILURE</b> exception is sent as a response.
|
||||||
|
*/
|
||||||
|
eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress,
|
||||||
|
USHORT usNRegs );
|
||||||
|
|
||||||
|
/*! \ingroup modbus_registers
|
||||||
|
* \brief Callback function used if a <em>Holding Register</em> value is
|
||||||
|
* read or written by the protocol stack. The starting register address
|
||||||
|
* is given by \c usAddress and the last register is given by
|
||||||
|
* <tt>usAddress + usNRegs - 1</tt>.
|
||||||
|
*
|
||||||
|
* \param pucRegBuffer If the application registers values should be updated the
|
||||||
|
* buffer points to the new registers values. If the protocol stack needs
|
||||||
|
* to now the current values the callback function should write them into
|
||||||
|
* this buffer.
|
||||||
|
* \param usAddress The starting address of the register.
|
||||||
|
* \param usNRegs Number of registers to read or write.
|
||||||
|
* \param eMode If eMBRegisterMode::MB_REG_WRITE the application register
|
||||||
|
* values should be updated from the values in the buffer. For example
|
||||||
|
* this would be the case when the Modbus master has issued an
|
||||||
|
* <b>WRITE SINGLE REGISTER</b> command.
|
||||||
|
* If the value eMBRegisterMode::MB_REG_READ the application should copy
|
||||||
|
* the current values into the buffer \c pucRegBuffer.
|
||||||
|
*
|
||||||
|
* \return The function must return one of the following error codes:
|
||||||
|
* - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
|
||||||
|
* Modbus response is sent.
|
||||||
|
* - eMBErrorCode::MB_ENOREG If the application can not supply values
|
||||||
|
* for registers within this range. In this case a
|
||||||
|
* <b>ILLEGAL DATA ADDRESS</b> exception frame is sent as a response.
|
||||||
|
* - eMBErrorCode::MB_ETIMEDOUT If the requested register block is
|
||||||
|
* currently not available and the application dependent response
|
||||||
|
* timeout would be violated. In this case a <b>SLAVE DEVICE BUSY</b>
|
||||||
|
* exception is sent as a response.
|
||||||
|
* - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case
|
||||||
|
* a <b>SLAVE DEVICE FAILURE</b> exception is sent as a response.
|
||||||
|
*/
|
||||||
|
eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress,
|
||||||
|
USHORT usNRegs, eMBRegisterMode eMode );
|
||||||
|
|
||||||
|
/*! \ingroup modbus_registers
|
||||||
|
* \brief Callback function used if a <em>Coil Register</em> value is
|
||||||
|
* read or written by the protocol stack. If you are going to use
|
||||||
|
* this function you might use the functions xMBUtilSetBits( ) and
|
||||||
|
* xMBUtilGetBits( ) for working with bitfields.
|
||||||
|
*
|
||||||
|
* \param pucRegBuffer The bits are packed in bytes where the first coil
|
||||||
|
* starting at address \c usAddress is stored in the LSB of the
|
||||||
|
* first byte in the buffer <code>pucRegBuffer</code>.
|
||||||
|
* If the buffer should be written by the callback function unused
|
||||||
|
* coil values (I.e. if not a multiple of eight coils is used) should be set
|
||||||
|
* to zero.
|
||||||
|
* \param usAddress The first coil number.
|
||||||
|
* \param usNCoils Number of coil values requested.
|
||||||
|
* \param eMode If eMBRegisterMode::MB_REG_WRITE the application values should
|
||||||
|
* be updated from the values supplied in the buffer \c pucRegBuffer.
|
||||||
|
* If eMBRegisterMode::MB_REG_READ the application should store the current
|
||||||
|
* values in the buffer \c pucRegBuffer.
|
||||||
|
*
|
||||||
|
* \return The function must return one of the following error codes:
|
||||||
|
* - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
|
||||||
|
* Modbus response is sent.
|
||||||
|
* - eMBErrorCode::MB_ENOREG If the application does not map an coils
|
||||||
|
* within the requested address range. In this case a
|
||||||
|
* <b>ILLEGAL DATA ADDRESS</b> is sent as a response.
|
||||||
|
* - eMBErrorCode::MB_ETIMEDOUT If the requested register block is
|
||||||
|
* currently not available and the application dependent response
|
||||||
|
* timeout would be violated. In this case a <b>SLAVE DEVICE BUSY</b>
|
||||||
|
* exception is sent as a response.
|
||||||
|
* - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case
|
||||||
|
* a <b>SLAVE DEVICE FAILURE</b> exception is sent as a response.
|
||||||
|
*/
|
||||||
|
eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress,
|
||||||
|
USHORT usNCoils, eMBRegisterMode eMode );
|
||||||
|
|
||||||
|
/*! \ingroup modbus_registers
|
||||||
|
* \brief Callback function used if a <em>Input Discrete Register</em> value is
|
||||||
|
* read by the protocol stack.
|
||||||
|
*
|
||||||
|
* If you are going to use his function you might use the functions
|
||||||
|
* xMBUtilSetBits( ) and xMBUtilGetBits( ) for working with bitfields.
|
||||||
|
*
|
||||||
|
* \param pucRegBuffer The buffer should be updated with the current
|
||||||
|
* coil values. The first discrete input starting at \c usAddress must be
|
||||||
|
* stored at the LSB of the first byte in the buffer. If the requested number
|
||||||
|
* is not a multiple of eight the remaining bits should be set to zero.
|
||||||
|
* \param usAddress The starting address of the first discrete input.
|
||||||
|
* \param usNDiscrete Number of discrete input values.
|
||||||
|
* \return The function must return one of the following error codes:
|
||||||
|
* - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
|
||||||
|
* Modbus response is sent.
|
||||||
|
* - eMBErrorCode::MB_ENOREG If no such discrete inputs exists.
|
||||||
|
* In this case a <b>ILLEGAL DATA ADDRESS</b> exception frame is sent
|
||||||
|
* as a response.
|
||||||
|
* - eMBErrorCode::MB_ETIMEDOUT If the requested register block is
|
||||||
|
* currently not available and the application dependent response
|
||||||
|
* timeout would be violated. In this case a <b>SLAVE DEVICE BUSY</b>
|
||||||
|
* exception is sent as a response.
|
||||||
|
* - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case
|
||||||
|
* a <b>SLAVE DEVICE FAILURE</b> exception is sent as a response.
|
||||||
|
*/
|
||||||
|
eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress,
|
||||||
|
USHORT usNDiscrete );
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
PR_END_EXTERN_C
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||||
|
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* File: $Id: mbconfig.h,v 1.14 2006/12/07 22:10:34 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MB_CONFIG_H
|
||||||
|
#define _MB_CONFIG_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
PR_BEGIN_EXTERN_C
|
||||||
|
#endif
|
||||||
|
/* ----------------------- Defines ------------------------------------------*/
|
||||||
|
/*! \defgroup modbus_cfg Modbus Configuration
|
||||||
|
*
|
||||||
|
* Most modules in the protocol stack are completly optional and can be
|
||||||
|
* excluded. This is specially important if target resources are very small
|
||||||
|
* and program memory space should be saved.<br>
|
||||||
|
*
|
||||||
|
* All of these settings are available in the file <code>mbconfig.h</code>
|
||||||
|
*/
|
||||||
|
/*! \addtogroup modbus_cfg
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/*! \brief If Modbus ASCII support is enabled. */
|
||||||
|
#define MB_ASCII_ENABLED ( 0 )
|
||||||
|
/*! \brief If Modbus RTU support is enabled. */
|
||||||
|
#define MB_RTU_ENABLED ( 1 )
|
||||||
|
/*! \brief If Modbus TCP support is enabled. */
|
||||||
|
#define MB_TCP_ENABLED ( 0 )
|
||||||
|
/*! \brief The character timeout value for Modbus ASCII.
|
||||||
|
*
|
||||||
|
* The character timeout value is not fixed for Modbus ASCII and is therefore
|
||||||
|
* a configuration option. It should be set to the maximum expected delay
|
||||||
|
* time of the network.
|
||||||
|
*/
|
||||||
|
#define MB_ASCII_TIMEOUT_SEC ( 1 )
|
||||||
|
/*! \brief Maximum number of Modbus functions codes the protocol stack
|
||||||
|
* should support.
|
||||||
|
*
|
||||||
|
* The maximum number of supported Modbus functions must be greater than
|
||||||
|
* the sum of all enabled functions in this file and custom function
|
||||||
|
* handlers. If set to small adding more functions will fail.
|
||||||
|
*/
|
||||||
|
#define MB_FUNC_HANDLERS_MAX ( 16 )
|
||||||
|
/*! \brief Number of bytes which should be allocated for the <em>Report Slave ID
|
||||||
|
* </em>command.
|
||||||
|
*
|
||||||
|
* This number limits the maximum size of the additional segment in the
|
||||||
|
* report slave id function. See eMBSetSlaveID( ) for more information on
|
||||||
|
* how to set this value. It is only used if MB_FUNC_OTHER_REP_SLAVEID_ENABLED
|
||||||
|
* is set to <code>1</code>.
|
||||||
|
*/
|
||||||
|
#define MB_FUNC_OTHER_REP_SLAVEID_BUF ( 32 )
|
||||||
|
/*! \brief If the <em>Report Slave ID</em> function should be enabled. */
|
||||||
|
#define MB_FUNC_OTHER_REP_SLAVEID_ENABLED ( 1 )
|
||||||
|
/*! \brief If the <em>Read Input Registers</em> function should be enabled. */
|
||||||
|
#define MB_FUNC_READ_INPUT_ENABLED ( 1 )
|
||||||
|
/*! \brief If the <em>Read Holding Registers</em> function should be enabled. */
|
||||||
|
#define MB_FUNC_READ_HOLDING_ENABLED ( 1 )
|
||||||
|
/*! \brief If the <em>Write Single Register</em> function should be enabled. */
|
||||||
|
#define MB_FUNC_WRITE_HOLDING_ENABLED ( 1 )
|
||||||
|
/*! \brief If the <em>Write Multiple registers</em> function should be enabled. */
|
||||||
|
#define MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED ( 1 )
|
||||||
|
/*! \brief If the <em>Read Coils</em> function should be enabled. */
|
||||||
|
#define MB_FUNC_READ_COILS_ENABLED ( 1 )
|
||||||
|
/*! \brief If the <em>Write Coils</em> function should be enabled. */
|
||||||
|
#define MB_FUNC_WRITE_COIL_ENABLED ( 1 )
|
||||||
|
/*! \brief If the <em>Write Multiple Coils</em> function should be enabled. */
|
||||||
|
#define MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED ( 1 )
|
||||||
|
/*! \brief If the <em>Read Discrete Inputs</em> function should be enabled. */
|
||||||
|
#define MB_FUNC_READ_DISCRETE_INPUTS_ENABLED ( 1 )
|
||||||
|
/*! \brief If the <em>Read/Write Multiple Registers</em> function should be enabled. */
|
||||||
|
#define MB_FUNC_READWRITE_HOLDING_ENABLED ( 1 )
|
||||||
|
/*! @} */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
PR_END_EXTERN_C
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||||
|
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* File: $Id: mbframe.h,v 1.9 2006/12/07 22:10:34 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MB_FRAME_H
|
||||||
|
#define _MB_FRAME_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
PR_BEGIN_EXTERN_C
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constants which defines the format of a modbus frame. The example is
|
||||||
|
* shown for a Modbus RTU/ASCII frame. Note that the Modbus PDU is not
|
||||||
|
* dependent on the underlying transport.
|
||||||
|
*
|
||||||
|
* <code>
|
||||||
|
* <------------------------ MODBUS SERIAL LINE PDU (1) ------------------->
|
||||||
|
* <----------- MODBUS PDU (1') ---------------->
|
||||||
|
* +-----------+---------------+----------------------------+-------------+
|
||||||
|
* | Address | Function Code | Data | CRC/LRC |
|
||||||
|
* +-----------+---------------+----------------------------+-------------+
|
||||||
|
* | | | |
|
||||||
|
* (2) (3/2') (3') (4)
|
||||||
|
*
|
||||||
|
* (1) ... MB_SER_PDU_SIZE_MAX = 256
|
||||||
|
* (2) ... MB_SER_PDU_ADDR_OFF = 0
|
||||||
|
* (3) ... MB_SER_PDU_PDU_OFF = 1
|
||||||
|
* (4) ... MB_SER_PDU_SIZE_CRC = 2
|
||||||
|
*
|
||||||
|
* (1') ... MB_PDU_SIZE_MAX = 253
|
||||||
|
* (2') ... MB_PDU_FUNC_OFF = 0
|
||||||
|
* (3') ... MB_PDU_DATA_OFF = 1
|
||||||
|
* </code>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ----------------------- Defines ------------------------------------------*/
|
||||||
|
#define MB_PDU_SIZE_MAX 253 /*!< Maximum size of a PDU. */
|
||||||
|
#define MB_PDU_SIZE_MIN 1 /*!< Function Code */
|
||||||
|
#define MB_PDU_FUNC_OFF 0 /*!< Offset of function code in PDU. */
|
||||||
|
#define MB_PDU_DATA_OFF 1 /*!< Offset for response data in PDU. */
|
||||||
|
|
||||||
|
/* ----------------------- Prototypes 0-------------------------------------*/
|
||||||
|
typedef void ( *pvMBFrameStart ) ( void );
|
||||||
|
|
||||||
|
typedef void ( *pvMBFrameStop ) ( void );
|
||||||
|
|
||||||
|
typedef eMBErrorCode( *peMBFrameReceive ) ( UCHAR * pucRcvAddress,
|
||||||
|
UCHAR ** pucFrame,
|
||||||
|
USHORT * pusLength );
|
||||||
|
|
||||||
|
typedef eMBErrorCode( *peMBFrameSend ) ( UCHAR slaveAddress,
|
||||||
|
const UCHAR * pucFrame,
|
||||||
|
USHORT usLength );
|
||||||
|
|
||||||
|
typedef void( *pvMBFrameClose ) ( void );
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
PR_END_EXTERN_C
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||||
|
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* File: $Id: mbfunc.h,v 1.12 2006/12/07 22:10:34 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MB_FUNC_H
|
||||||
|
#define _MB_FUNC_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
PR_BEGIN_EXTERN_C
|
||||||
|
#endif
|
||||||
|
#if MB_FUNC_OTHER_REP_SLAVEID_BUF > 0
|
||||||
|
eMBException eMBFuncReportSlaveID( UCHAR * pucFrame, USHORT * usLen );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MB_FUNC_READ_INPUT_ENABLED > 0
|
||||||
|
eMBException eMBFuncReadInputRegister( UCHAR * pucFrame, USHORT * usLen );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MB_FUNC_READ_HOLDING_ENABLED > 0
|
||||||
|
eMBException eMBFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MB_FUNC_WRITE_HOLDING_ENABLED > 0
|
||||||
|
eMBException eMBFuncWriteHoldingRegister( UCHAR * pucFrame, USHORT * usLen );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0
|
||||||
|
eMBException eMBFuncWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MB_FUNC_READ_COILS_ENABLED > 0
|
||||||
|
eMBException eMBFuncReadCoils( UCHAR * pucFrame, USHORT * usLen );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MB_FUNC_WRITE_COIL_ENABLED > 0
|
||||||
|
eMBException eMBFuncWriteCoil( UCHAR * pucFrame, USHORT * usLen );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED > 0
|
||||||
|
eMBException eMBFuncWriteMultipleCoils( UCHAR * pucFrame, USHORT * usLen );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MB_FUNC_READ_DISCRETE_INPUTS_ENABLED > 0
|
||||||
|
eMBException eMBFuncReadDiscreteInputs( UCHAR * pucFrame, USHORT * usLen );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MB_FUNC_READWRITE_HOLDING_ENABLED > 0
|
||||||
|
eMBException eMBFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
PR_END_EXTERN_C
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,127 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||||
|
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* File: $Id: mbport.h,v 1.17 2006/12/07 22:10:34 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MB_PORT_H
|
||||||
|
#define _MB_PORT_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
PR_BEGIN_EXTERN_C
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ----------------------- Type definitions ---------------------------------*/
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
EV_READY, /*!< Startup finished. */
|
||||||
|
EV_FRAME_RECEIVED, /*!< Frame received. */
|
||||||
|
EV_EXECUTE, /*!< Execute function. */
|
||||||
|
EV_FRAME_SENT /*!< Frame sent. */
|
||||||
|
} eMBEventType;
|
||||||
|
|
||||||
|
/*! \ingroup modbus
|
||||||
|
* \brief Parity used for characters in serial mode.
|
||||||
|
*
|
||||||
|
* The parity which should be applied to the characters sent over the serial
|
||||||
|
* link. Please note that this values are actually passed to the porting
|
||||||
|
* layer and therefore not all parity modes might be available.
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
MB_PAR_NONE, /*!< No parity. */
|
||||||
|
MB_PAR_ODD, /*!< Odd parity. */
|
||||||
|
MB_PAR_EVEN /*!< Even parity. */
|
||||||
|
} eMBParity;
|
||||||
|
|
||||||
|
/* ----------------------- Supporting functions -----------------------------*/
|
||||||
|
BOOL xMBPortEventInit( void );
|
||||||
|
|
||||||
|
BOOL xMBPortEventPost( eMBEventType eEvent );
|
||||||
|
|
||||||
|
BOOL xMBPortEventGet( /*@out@ */ eMBEventType * eEvent );
|
||||||
|
|
||||||
|
/* ----------------------- Serial port functions ----------------------------*/
|
||||||
|
|
||||||
|
BOOL xMBPortSerialInit( UCHAR ucPort, ULONG ulBaudRate,
|
||||||
|
UCHAR ucDataBits, eMBParity eParity );
|
||||||
|
|
||||||
|
void vMBPortClose( void );
|
||||||
|
|
||||||
|
void xMBPortSerialClose( void );
|
||||||
|
|
||||||
|
void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable );
|
||||||
|
|
||||||
|
INLINE BOOL xMBPortSerialGetByte( CHAR * pucByte );
|
||||||
|
|
||||||
|
INLINE BOOL xMBPortSerialPutByte( CHAR ucByte );
|
||||||
|
|
||||||
|
/* ----------------------- Timers functions ---------------------------------*/
|
||||||
|
BOOL xMBPortTimersInit( USHORT usTimeOut50us );
|
||||||
|
|
||||||
|
void xMBPortTimersClose( void );
|
||||||
|
|
||||||
|
INLINE void vMBPortTimersEnable( void );
|
||||||
|
|
||||||
|
INLINE void vMBPortTimersDisable( void );
|
||||||
|
|
||||||
|
/* ----------------------- Callback for the protocol stack ------------------*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Callback function for the porting layer when a new byte is
|
||||||
|
* available.
|
||||||
|
*
|
||||||
|
* Depending upon the mode this callback function is used by the RTU or
|
||||||
|
* ASCII transmission layers. In any case a call to xMBPortSerialGetByte()
|
||||||
|
* must immediately return a new character.
|
||||||
|
*
|
||||||
|
* \return <code>TRUE</code> if a event was posted to the queue because
|
||||||
|
* a new byte was received. The port implementation should wake up the
|
||||||
|
* tasks which are currently blocked on the eventqueue.
|
||||||
|
*/
|
||||||
|
extern BOOL( *pxMBFrameCBByteReceived ) ( void );
|
||||||
|
|
||||||
|
extern BOOL( *pxMBFrameCBTransmitterEmpty ) ( void );
|
||||||
|
|
||||||
|
extern BOOL( *pxMBPortCBTimerExpired ) ( void );
|
||||||
|
|
||||||
|
/* ----------------------- TCP port functions -------------------------------*/
|
||||||
|
BOOL xMBTCPPortInit( USHORT usTCPPort );
|
||||||
|
|
||||||
|
void vMBTCPPortClose( void );
|
||||||
|
|
||||||
|
void vMBTCPPortDisable( void );
|
||||||
|
|
||||||
|
BOOL xMBTCPPortGetRequest( UCHAR **ppucMBTCPFrame, USHORT * usTCPLength );
|
||||||
|
|
||||||
|
BOOL xMBTCPPortSendResponse( const UCHAR *pucMBTCPFrame, USHORT usTCPLength );
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
PR_END_EXTERN_C
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||||
|
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* File: $Id: mbproto.h,v 1.14 2006/12/07 22:10:34 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MB_PROTO_H
|
||||||
|
#define _MB_PROTO_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
PR_BEGIN_EXTERN_C
|
||||||
|
#endif
|
||||||
|
/* ----------------------- Defines ------------------------------------------*/
|
||||||
|
#define MB_ADDRESS_BROADCAST ( 0 ) /*! Modbus broadcast address. */
|
||||||
|
#define MB_ADDRESS_MIN ( 1 ) /*! Smallest possible slave address. */
|
||||||
|
#define MB_ADDRESS_MAX ( 247 ) /*! Biggest possible slave address. */
|
||||||
|
#define MB_FUNC_NONE ( 0 )
|
||||||
|
#define MB_FUNC_READ_COILS ( 1 )
|
||||||
|
#define MB_FUNC_READ_DISCRETE_INPUTS ( 2 )
|
||||||
|
#define MB_FUNC_WRITE_SINGLE_COIL ( 5 )
|
||||||
|
#define MB_FUNC_WRITE_MULTIPLE_COILS ( 15 )
|
||||||
|
#define MB_FUNC_READ_HOLDING_REGISTER ( 3 )
|
||||||
|
#define MB_FUNC_READ_INPUT_REGISTER ( 4 )
|
||||||
|
#define MB_FUNC_WRITE_REGISTER ( 6 )
|
||||||
|
#define MB_FUNC_WRITE_MULTIPLE_REGISTERS ( 16 )
|
||||||
|
#define MB_FUNC_READWRITE_MULTIPLE_REGISTERS ( 23 )
|
||||||
|
#define MB_FUNC_DIAG_READ_EXCEPTION ( 7 )
|
||||||
|
#define MB_FUNC_DIAG_DIAGNOSTIC ( 8 )
|
||||||
|
#define MB_FUNC_DIAG_GET_COM_EVENT_CNT ( 11 )
|
||||||
|
#define MB_FUNC_DIAG_GET_COM_EVENT_LOG ( 12 )
|
||||||
|
#define MB_FUNC_OTHER_REPORT_SLAVEID ( 17 )
|
||||||
|
#define MB_FUNC_ERROR ( 128 )
|
||||||
|
/* ----------------------- Type definitions ---------------------------------*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
MB_EX_NONE = 0x00,
|
||||||
|
MB_EX_ILLEGAL_FUNCTION = 0x01,
|
||||||
|
MB_EX_ILLEGAL_DATA_ADDRESS = 0x02,
|
||||||
|
MB_EX_ILLEGAL_DATA_VALUE = 0x03,
|
||||||
|
MB_EX_SLAVE_DEVICE_FAILURE = 0x04,
|
||||||
|
MB_EX_ACKNOWLEDGE = 0x05,
|
||||||
|
MB_EX_SLAVE_BUSY = 0x06,
|
||||||
|
MB_EX_MEMORY_PARITY_ERROR = 0x08,
|
||||||
|
MB_EX_GATEWAY_PATH_FAILED = 0x0A,
|
||||||
|
MB_EX_GATEWAY_TGT_FAILED = 0x0B
|
||||||
|
} eMBException;
|
||||||
|
|
||||||
|
typedef eMBException( *pxMBFunctionHandler ) ( UCHAR * pucFrame, USHORT * pusLength );
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
UCHAR ucFunctionCode;
|
||||||
|
pxMBFunctionHandler pxHandler;
|
||||||
|
} xMBFunctionHandler;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
PR_END_EXTERN_C
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||||
|
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* File: $Id: mbutils.h,v 1.5 2006/12/07 22:10:34 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MB_UTILS_H
|
||||||
|
#define _MB_UTILS_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
PR_BEGIN_EXTERN_C
|
||||||
|
#endif
|
||||||
|
/*! \defgroup modbus_utils Utilities
|
||||||
|
*
|
||||||
|
* This module contains some utility functions which can be used by
|
||||||
|
* the application. It includes some special functions for working with
|
||||||
|
* bitfields backed by a character array buffer.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/*! \addtogroup modbus_utils
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/*! \brief Function to set bits in a byte buffer.
|
||||||
|
*
|
||||||
|
* This function allows the efficient use of an array to implement bitfields.
|
||||||
|
* The array used for storing the bits must always be a multiple of two
|
||||||
|
* bytes. Up to eight bits can be set or cleared in one operation.
|
||||||
|
*
|
||||||
|
* \param ucByteBuf A buffer where the bit values are stored. Must be a
|
||||||
|
* multiple of 2 bytes. No length checking is performed and if
|
||||||
|
* usBitOffset / 8 is greater than the size of the buffer memory contents
|
||||||
|
* is overwritten.
|
||||||
|
* \param usBitOffset The starting address of the bits to set. The first
|
||||||
|
* bit has the offset 0.
|
||||||
|
* \param ucNBits Number of bits to modify. The value must always be smaller
|
||||||
|
* than 8.
|
||||||
|
* \param ucValues Thew new values for the bits. The value for the first bit
|
||||||
|
* starting at <code>usBitOffset</code> is the LSB of the value
|
||||||
|
* <code>ucValues</code>
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
* ucBits[2] = {0, 0};
|
||||||
|
*
|
||||||
|
* // Set bit 4 to 1 (read: set 1 bit starting at bit offset 4 to value 1)
|
||||||
|
* xMBUtilSetBits( ucBits, 4, 1, 1 );
|
||||||
|
*
|
||||||
|
* // Set bit 7 to 1 and bit 8 to 0.
|
||||||
|
* xMBUtilSetBits( ucBits, 7, 2, 0x01 );
|
||||||
|
*
|
||||||
|
* // Set bits 8 - 11 to 0x05 and bits 12 - 15 to 0x0A;
|
||||||
|
* xMBUtilSetBits( ucBits, 8, 8, 0x5A);
|
||||||
|
* \endcode
|
||||||
|
*/
|
||||||
|
void xMBUtilSetBits( UCHAR * ucByteBuf, USHORT usBitOffset,
|
||||||
|
UCHAR ucNBits, UCHAR ucValues );
|
||||||
|
|
||||||
|
/*! \brief Function to read bits in a byte buffer.
|
||||||
|
*
|
||||||
|
* This function is used to extract up bit values from an array. Up to eight
|
||||||
|
* bit values can be extracted in one step.
|
||||||
|
*
|
||||||
|
* \param ucByteBuf A buffer where the bit values are stored.
|
||||||
|
* \param usBitOffset The starting address of the bits to set. The first
|
||||||
|
* bit has the offset 0.
|
||||||
|
* \param ucNBits Number of bits to modify. The value must always be smaller
|
||||||
|
* than 8.
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
* UCHAR ucBits[2] = {0, 0};
|
||||||
|
* UCHAR ucResult;
|
||||||
|
*
|
||||||
|
* // Extract the bits 3 - 10.
|
||||||
|
* ucResult = xMBUtilGetBits( ucBits, 3, 8 );
|
||||||
|
* \endcode
|
||||||
|
*/
|
||||||
|
UCHAR xMBUtilGetBits( UCHAR * ucByteBuf, USHORT usBitOffset,
|
||||||
|
UCHAR ucNBits );
|
||||||
|
|
||||||
|
/*! @} */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
PR_END_EXTERN_C
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,408 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||||
|
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* File: $Id: mb.c,v 1.27 2007/02/18 23:45:41 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ----------------------- System includes ----------------------------------*/
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
/* ----------------------- Platform includes --------------------------------*/
|
||||||
|
#include "port.h"
|
||||||
|
|
||||||
|
/* ----------------------- Modbus includes ----------------------------------*/
|
||||||
|
|
||||||
|
#include "mb.h"
|
||||||
|
#include "mbconfig.h"
|
||||||
|
#include "mbframe.h"
|
||||||
|
#include "mbproto.h"
|
||||||
|
#include "mbfunc.h"
|
||||||
|
|
||||||
|
#include "mbport.h"
|
||||||
|
#if MB_RTU_ENABLED == 1
|
||||||
|
#include "mbrtu.h"
|
||||||
|
#endif
|
||||||
|
#if MB_ASCII_ENABLED == 1
|
||||||
|
#include "mbascii.h"
|
||||||
|
#endif
|
||||||
|
#if MB_TCP_ENABLED == 1
|
||||||
|
#include "mbtcp.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MB_PORT_HAS_CLOSE
|
||||||
|
#define MB_PORT_HAS_CLOSE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ----------------------- Static variables ---------------------------------*/
|
||||||
|
|
||||||
|
static UCHAR ucMBAddress;
|
||||||
|
static eMBMode eMBCurrentMode;
|
||||||
|
|
||||||
|
static enum
|
||||||
|
{
|
||||||
|
STATE_ENABLED,
|
||||||
|
STATE_DISABLED,
|
||||||
|
STATE_NOT_INITIALIZED
|
||||||
|
} eMBState = STATE_NOT_INITIALIZED;
|
||||||
|
|
||||||
|
/* Functions pointer which are initialized in eMBInit( ). Depending on the
|
||||||
|
* mode (RTU or ASCII) the are set to the correct implementations.
|
||||||
|
*/
|
||||||
|
static peMBFrameSend peMBFrameSendCur;
|
||||||
|
static pvMBFrameStart pvMBFrameStartCur;
|
||||||
|
static pvMBFrameStop pvMBFrameStopCur;
|
||||||
|
static peMBFrameReceive peMBFrameReceiveCur;
|
||||||
|
static pvMBFrameClose pvMBFrameCloseCur;
|
||||||
|
|
||||||
|
/* Callback functions required by the porting layer. They are called when
|
||||||
|
* an external event has happend which includes a timeout or the reception
|
||||||
|
* or transmission of a character.
|
||||||
|
*/
|
||||||
|
BOOL( *pxMBFrameCBByteReceived ) ( void );
|
||||||
|
BOOL( *pxMBFrameCBTransmitterEmpty ) ( void );
|
||||||
|
BOOL( *pxMBPortCBTimerExpired ) ( void );
|
||||||
|
|
||||||
|
BOOL( *pxMBFrameCBReceiveFSMCur ) ( void );
|
||||||
|
BOOL( *pxMBFrameCBTransmitFSMCur ) ( void );
|
||||||
|
|
||||||
|
/* An array of Modbus functions handlers which associates Modbus function
|
||||||
|
* codes with implementing functions.
|
||||||
|
*/
|
||||||
|
static xMBFunctionHandler xFuncHandlers[MB_FUNC_HANDLERS_MAX] = {
|
||||||
|
#if MB_FUNC_OTHER_REP_SLAVEID_ENABLED > 0
|
||||||
|
{MB_FUNC_OTHER_REPORT_SLAVEID, eMBFuncReportSlaveID},
|
||||||
|
#endif
|
||||||
|
#if MB_FUNC_READ_INPUT_ENABLED > 0
|
||||||
|
{MB_FUNC_READ_INPUT_REGISTER, eMBFuncReadInputRegister},
|
||||||
|
#endif
|
||||||
|
#if MB_FUNC_READ_HOLDING_ENABLED > 0
|
||||||
|
{MB_FUNC_READ_HOLDING_REGISTER, eMBFuncReadHoldingRegister},
|
||||||
|
#endif
|
||||||
|
#if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0
|
||||||
|
{MB_FUNC_WRITE_MULTIPLE_REGISTERS, eMBFuncWriteMultipleHoldingRegister},
|
||||||
|
#endif
|
||||||
|
#if MB_FUNC_WRITE_HOLDING_ENABLED > 0
|
||||||
|
{MB_FUNC_WRITE_REGISTER, eMBFuncWriteHoldingRegister},
|
||||||
|
#endif
|
||||||
|
#if MB_FUNC_READWRITE_HOLDING_ENABLED > 0
|
||||||
|
{MB_FUNC_READWRITE_MULTIPLE_REGISTERS, eMBFuncReadWriteMultipleHoldingRegister},
|
||||||
|
#endif
|
||||||
|
#if MB_FUNC_READ_COILS_ENABLED > 0
|
||||||
|
{MB_FUNC_READ_COILS, eMBFuncReadCoils},
|
||||||
|
#endif
|
||||||
|
#if MB_FUNC_WRITE_COIL_ENABLED > 0
|
||||||
|
{MB_FUNC_WRITE_SINGLE_COIL, eMBFuncWriteCoil},
|
||||||
|
#endif
|
||||||
|
#if MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED > 0
|
||||||
|
{MB_FUNC_WRITE_MULTIPLE_COILS, eMBFuncWriteMultipleCoils},
|
||||||
|
#endif
|
||||||
|
#if MB_FUNC_READ_DISCRETE_INPUTS_ENABLED > 0
|
||||||
|
{MB_FUNC_READ_DISCRETE_INPUTS, eMBFuncReadDiscreteInputs},
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ----------------------- Start implementation -----------------------------*/
|
||||||
|
eMBErrorCode
|
||||||
|
eMBInit( eMBMode eMode, UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity )
|
||||||
|
{
|
||||||
|
eMBErrorCode eStatus = MB_ENOERR;
|
||||||
|
|
||||||
|
/* check preconditions */
|
||||||
|
if( ( ucSlaveAddress == MB_ADDRESS_BROADCAST ) ||
|
||||||
|
( ucSlaveAddress < MB_ADDRESS_MIN ) || ( ucSlaveAddress > MB_ADDRESS_MAX ) )
|
||||||
|
{
|
||||||
|
eStatus = MB_EINVAL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ucMBAddress = ucSlaveAddress;
|
||||||
|
|
||||||
|
switch ( eMode )
|
||||||
|
{
|
||||||
|
#if MB_RTU_ENABLED > 0
|
||||||
|
case MB_RTU:
|
||||||
|
pvMBFrameStartCur = eMBRTUStart;
|
||||||
|
pvMBFrameStopCur = eMBRTUStop;
|
||||||
|
peMBFrameSendCur = eMBRTUSend;
|
||||||
|
peMBFrameReceiveCur = eMBRTUReceive;
|
||||||
|
pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBPortClose : NULL;
|
||||||
|
pxMBFrameCBByteReceived = xMBRTUReceiveFSM;
|
||||||
|
pxMBFrameCBTransmitterEmpty = xMBRTUTransmitFSM;
|
||||||
|
pxMBPortCBTimerExpired = xMBRTUTimerT35Expired;
|
||||||
|
|
||||||
|
eStatus = eMBRTUInit( ucMBAddress, ucPort, ulBaudRate, eParity );
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#if MB_ASCII_ENABLED > 0
|
||||||
|
case MB_ASCII:
|
||||||
|
pvMBFrameStartCur = eMBASCIIStart;
|
||||||
|
pvMBFrameStopCur = eMBASCIIStop;
|
||||||
|
peMBFrameSendCur = eMBASCIISend;
|
||||||
|
peMBFrameReceiveCur = eMBASCIIReceive;
|
||||||
|
pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBPortClose : NULL;
|
||||||
|
pxMBFrameCBByteReceived = xMBASCIIReceiveFSM;
|
||||||
|
pxMBFrameCBTransmitterEmpty = xMBASCIITransmitFSM;
|
||||||
|
pxMBPortCBTimerExpired = xMBASCIITimerT1SExpired;
|
||||||
|
|
||||||
|
eStatus = eMBASCIIInit( ucMBAddress, ucPort, ulBaudRate, eParity );
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
eStatus = MB_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( eStatus == MB_ENOERR )
|
||||||
|
{
|
||||||
|
if( !xMBPortEventInit( ) )
|
||||||
|
{
|
||||||
|
/* port dependent event module initalization failed. */
|
||||||
|
eStatus = MB_EPORTERR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eMBCurrentMode = eMode;
|
||||||
|
eMBState = STATE_DISABLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MB_TCP_ENABLED > 0
|
||||||
|
eMBErrorCode
|
||||||
|
eMBTCPInit( USHORT ucTCPPort )
|
||||||
|
{
|
||||||
|
eMBErrorCode eStatus = MB_ENOERR;
|
||||||
|
|
||||||
|
if( ( eStatus = eMBTCPDoInit( ucTCPPort ) ) != MB_ENOERR )
|
||||||
|
{
|
||||||
|
eMBState = STATE_DISABLED;
|
||||||
|
}
|
||||||
|
else if( !xMBPortEventInit( ) )
|
||||||
|
{
|
||||||
|
/* Port dependent event module initalization failed. */
|
||||||
|
eStatus = MB_EPORTERR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pvMBFrameStartCur = eMBTCPStart;
|
||||||
|
pvMBFrameStopCur = eMBTCPStop;
|
||||||
|
peMBFrameReceiveCur = eMBTCPReceive;
|
||||||
|
peMBFrameSendCur = eMBTCPSend;
|
||||||
|
pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBTCPPortClose : NULL;
|
||||||
|
ucMBAddress = MB_TCP_PSEUDO_ADDRESS;
|
||||||
|
eMBCurrentMode = MB_TCP;
|
||||||
|
eMBState = STATE_DISABLED;
|
||||||
|
}
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
eMBErrorCode
|
||||||
|
eMBRegisterCB( UCHAR ucFunctionCode, pxMBFunctionHandler pxHandler )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
eMBErrorCode eStatus;
|
||||||
|
|
||||||
|
if( ( 0 < ucFunctionCode ) && ( ucFunctionCode <= 127 ) )
|
||||||
|
{
|
||||||
|
ENTER_CRITICAL_SECTION( );
|
||||||
|
if( pxHandler != NULL )
|
||||||
|
{
|
||||||
|
for( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ )
|
||||||
|
{
|
||||||
|
if( ( xFuncHandlers[i].pxHandler == NULL ) ||
|
||||||
|
( xFuncHandlers[i].pxHandler == pxHandler ) )
|
||||||
|
{
|
||||||
|
xFuncHandlers[i].ucFunctionCode = ucFunctionCode;
|
||||||
|
xFuncHandlers[i].pxHandler = pxHandler;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eStatus = ( i != MB_FUNC_HANDLERS_MAX ) ? MB_ENOERR : MB_ENORES;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ )
|
||||||
|
{
|
||||||
|
if( xFuncHandlers[i].ucFunctionCode == ucFunctionCode )
|
||||||
|
{
|
||||||
|
xFuncHandlers[i].ucFunctionCode = 0;
|
||||||
|
xFuncHandlers[i].pxHandler = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Remove can't fail. */
|
||||||
|
eStatus = MB_ENOERR;
|
||||||
|
}
|
||||||
|
EXIT_CRITICAL_SECTION( );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eStatus = MB_EINVAL;
|
||||||
|
}
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
eMBErrorCode
|
||||||
|
eMBClose( void )
|
||||||
|
{
|
||||||
|
eMBErrorCode eStatus = MB_ENOERR;
|
||||||
|
|
||||||
|
if( eMBState == STATE_DISABLED )
|
||||||
|
{
|
||||||
|
if( pvMBFrameCloseCur != NULL )
|
||||||
|
{
|
||||||
|
pvMBFrameCloseCur( );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eStatus = MB_EILLSTATE;
|
||||||
|
}
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
eMBErrorCode
|
||||||
|
eMBEnable( void )
|
||||||
|
{
|
||||||
|
eMBErrorCode eStatus = MB_ENOERR;
|
||||||
|
|
||||||
|
if( eMBState == STATE_DISABLED )
|
||||||
|
{
|
||||||
|
/* Activate the protocol stack. */
|
||||||
|
pvMBFrameStartCur( );
|
||||||
|
eMBState = STATE_ENABLED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eStatus = MB_EILLSTATE;
|
||||||
|
}
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
eMBErrorCode
|
||||||
|
eMBDisable( void )
|
||||||
|
{
|
||||||
|
eMBErrorCode eStatus;
|
||||||
|
|
||||||
|
if( eMBState == STATE_ENABLED )
|
||||||
|
{
|
||||||
|
pvMBFrameStopCur( );
|
||||||
|
eMBState = STATE_DISABLED;
|
||||||
|
eStatus = MB_ENOERR;
|
||||||
|
}
|
||||||
|
else if( eMBState == STATE_DISABLED )
|
||||||
|
{
|
||||||
|
eStatus = MB_ENOERR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eStatus = MB_EILLSTATE;
|
||||||
|
}
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
eMBErrorCode eMBPoll( void )
|
||||||
|
{
|
||||||
|
static UCHAR *ucMBFrame;
|
||||||
|
static UCHAR ucRcvAddress;
|
||||||
|
static UCHAR ucFunctionCode;
|
||||||
|
static USHORT usLength;
|
||||||
|
static eMBException eException;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
eMBErrorCode eStatus = MB_ENOERR;
|
||||||
|
eMBEventType eEvent;
|
||||||
|
|
||||||
|
/* Check if the protocol stack is ready. */
|
||||||
|
if( eMBState != STATE_ENABLED )
|
||||||
|
{
|
||||||
|
return MB_EILLSTATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if there is a event available. If not return control to caller.
|
||||||
|
* Otherwise we will handle the event. */
|
||||||
|
if( xMBPortEventGet( &eEvent ) == TRUE )
|
||||||
|
{
|
||||||
|
switch ( eEvent )
|
||||||
|
{
|
||||||
|
case EV_READY:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_FRAME_RECEIVED:
|
||||||
|
eStatus = peMBFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength );
|
||||||
|
if( eStatus == MB_ENOERR )
|
||||||
|
{
|
||||||
|
/* Check if the frame is for us. If not ignore the frame. */
|
||||||
|
if( ( ucRcvAddress == ucMBAddress ) || ( ucRcvAddress == MB_ADDRESS_BROADCAST ) )
|
||||||
|
{
|
||||||
|
( void )xMBPortEventPost( EV_EXECUTE );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_EXECUTE:
|
||||||
|
ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF];
|
||||||
|
eException = MB_EX_ILLEGAL_FUNCTION;
|
||||||
|
for( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ )
|
||||||
|
{
|
||||||
|
/* No more function handlers registered. Abort. */
|
||||||
|
if( xFuncHandlers[i].ucFunctionCode == 0 )
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if( xFuncHandlers[i].ucFunctionCode == ucFunctionCode )
|
||||||
|
{
|
||||||
|
eException = xFuncHandlers[i].pxHandler( ucMBFrame, &usLength );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the request was not sent to the broadcast address we
|
||||||
|
* return a reply. */
|
||||||
|
if( ucRcvAddress != MB_ADDRESS_BROADCAST )
|
||||||
|
{
|
||||||
|
if( eException != MB_EX_NONE )
|
||||||
|
{
|
||||||
|
/* An exception occured. Build an error frame. */
|
||||||
|
usLength = 0;
|
||||||
|
ucMBFrame[usLength++] = ( UCHAR )( ucFunctionCode | MB_FUNC_ERROR );
|
||||||
|
ucMBFrame[usLength++] = eException;
|
||||||
|
}
|
||||||
|
eStatus = peMBFrameSendCur( ucMBAddress, ucMBFrame, usLength );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_FRAME_SENT:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MB_ENOERR;
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||||
|
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* File: $Id: mbcrc.c,v 1.7 2007/02/18 23:50:27 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ----------------------- Platform includes --------------------------------*/
|
||||||
|
#include "port.h"
|
||||||
|
|
||||||
|
static const UCHAR aucCRCHi[] = {
|
||||||
|
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||||
|
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
|
||||||
|
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||||
|
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||||
|
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||||
|
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
|
||||||
|
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
|
||||||
|
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
|
||||||
|
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||||
|
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
|
||||||
|
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||||
|
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||||
|
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||||
|
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||||
|
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||||
|
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||||
|
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||||
|
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
|
||||||
|
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||||
|
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
||||||
|
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
||||||
|
0x00, 0xC1, 0x81, 0x40
|
||||||
|
};
|
||||||
|
|
||||||
|
static const UCHAR aucCRCLo[] = {
|
||||||
|
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
|
||||||
|
0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
|
||||||
|
0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
|
||||||
|
0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
|
||||||
|
0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
|
||||||
|
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
|
||||||
|
0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
|
||||||
|
0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
|
||||||
|
0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
|
||||||
|
0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
|
||||||
|
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
|
||||||
|
0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
|
||||||
|
0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,
|
||||||
|
0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
|
||||||
|
0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
|
||||||
|
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
|
||||||
|
0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,
|
||||||
|
0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
|
||||||
|
0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,
|
||||||
|
0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
|
||||||
|
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
|
||||||
|
0x41, 0x81, 0x80, 0x40
|
||||||
|
};
|
||||||
|
|
||||||
|
USHORT
|
||||||
|
usMBCRC16( UCHAR * pucFrame, USHORT usLen )
|
||||||
|
{
|
||||||
|
UCHAR ucCRCHi = 0xFF;
|
||||||
|
UCHAR ucCRCLo = 0xFF;
|
||||||
|
int iIndex;
|
||||||
|
|
||||||
|
while( usLen-- )
|
||||||
|
{
|
||||||
|
iIndex = ucCRCLo ^ *( pucFrame++ );
|
||||||
|
ucCRCLo = ( UCHAR )( ucCRCHi ^ aucCRCHi[iIndex] );
|
||||||
|
ucCRCHi = aucCRCLo[iIndex];
|
||||||
|
}
|
||||||
|
return ( USHORT )( ucCRCHi << 8 | ucCRCLo );
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||||
|
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* File: $Id: mbcrc.h,v 1.5 2006/12/07 22:10:34 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MB_CRC_H
|
||||||
|
#define _MB_CRC_H
|
||||||
|
|
||||||
|
USHORT usMBCRC16( UCHAR * pucFrame, USHORT usLen );
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,355 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||||
|
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* File: $Id: mbrtu.c,v 1.18 2007/09/12 10:15:56 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ----------------------- System includes ----------------------------------*/
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
/* ----------------------- Platform includes --------------------------------*/
|
||||||
|
#include "port.h"
|
||||||
|
|
||||||
|
/* ----------------------- Modbus includes ----------------------------------*/
|
||||||
|
#include "mb.h"
|
||||||
|
#include "mbrtu.h"
|
||||||
|
#include "mbframe.h"
|
||||||
|
|
||||||
|
#include "mbcrc.h"
|
||||||
|
#include "mbport.h"
|
||||||
|
|
||||||
|
/* ----------------------- Defines ------------------------------------------*/
|
||||||
|
#define MB_SER_PDU_SIZE_MIN 4 /*!< Minimum size of a Modbus RTU frame. */
|
||||||
|
#define MB_SER_PDU_SIZE_MAX 256 /*!< Maximum size of a Modbus RTU frame. */
|
||||||
|
#define MB_SER_PDU_SIZE_CRC 2 /*!< Size of CRC field in PDU. */
|
||||||
|
#define MB_SER_PDU_ADDR_OFF 0 /*!< Offset of slave address in Ser-PDU. */
|
||||||
|
#define MB_SER_PDU_PDU_OFF 1 /*!< Offset of Modbus-PDU in Ser-PDU. */
|
||||||
|
|
||||||
|
/* ----------------------- Type definitions ---------------------------------*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
STATE_RX_INIT, /*!< Receiver is in initial state. */
|
||||||
|
STATE_RX_IDLE, /*!< Receiver is in idle state. */
|
||||||
|
STATE_RX_RCV, /*!< Frame is beeing received. */
|
||||||
|
STATE_RX_ERROR /*!< If the frame is invalid. */
|
||||||
|
} eMBRcvState;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
STATE_TX_IDLE, /*!< Transmitter is in idle state. */
|
||||||
|
STATE_TX_XMIT /*!< Transmitter is in transfer state. */
|
||||||
|
} eMBSndState;
|
||||||
|
|
||||||
|
/* ----------------------- Static variables ---------------------------------*/
|
||||||
|
static volatile eMBSndState eSndState;
|
||||||
|
static volatile eMBRcvState eRcvState;
|
||||||
|
|
||||||
|
volatile UCHAR ucRTUBuf[MB_SER_PDU_SIZE_MAX];
|
||||||
|
|
||||||
|
static volatile UCHAR *pucSndBufferCur;
|
||||||
|
static volatile USHORT usSndBufferCount;
|
||||||
|
|
||||||
|
static volatile USHORT usRcvBufferPos;
|
||||||
|
|
||||||
|
/* ----------------------- Start implementation -----------------------------*/
|
||||||
|
eMBErrorCode
|
||||||
|
eMBRTUInit( UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity )
|
||||||
|
{
|
||||||
|
eMBErrorCode eStatus = MB_ENOERR;
|
||||||
|
ULONG usTimerT35_50us;
|
||||||
|
|
||||||
|
( void )ucSlaveAddress;
|
||||||
|
ENTER_CRITICAL_SECTION( );
|
||||||
|
|
||||||
|
/* Modbus RTU uses 8 Databits. */
|
||||||
|
if( xMBPortSerialInit( ucPort, ulBaudRate, 8, eParity ) != TRUE )
|
||||||
|
{
|
||||||
|
eStatus = MB_EPORTERR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* If baudrate > 19200 then we should use the fixed timer values
|
||||||
|
* t35 = 1750us. Otherwise t35 must be 3.5 times the character time.
|
||||||
|
*/
|
||||||
|
if( ulBaudRate > 19200 )
|
||||||
|
{
|
||||||
|
usTimerT35_50us = 35; /* 1800us. */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* The timer reload value for a character is given by:
|
||||||
|
*
|
||||||
|
* ChTimeValue = Ticks_per_1s / ( Baudrate / 11 )
|
||||||
|
* = 11 * Ticks_per_1s / Baudrate
|
||||||
|
* = 220000 / Baudrate
|
||||||
|
* The reload for t3.5 is 1.5 times this value and similary
|
||||||
|
* for t3.5.
|
||||||
|
*/
|
||||||
|
usTimerT35_50us = ( 7UL * 220000UL ) / ( 2UL * ulBaudRate );
|
||||||
|
}
|
||||||
|
if( xMBPortTimersInit( ( USHORT ) usTimerT35_50us ) != TRUE )
|
||||||
|
{
|
||||||
|
eStatus = MB_EPORTERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXIT_CRITICAL_SECTION( );
|
||||||
|
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
eMBRTUStart( void )
|
||||||
|
{
|
||||||
|
ENTER_CRITICAL_SECTION( );
|
||||||
|
/* Initially the receiver is in the state STATE_RX_INIT. we start
|
||||||
|
* the timer and if no character is received within t3.5 we change
|
||||||
|
* to STATE_RX_IDLE. This makes sure that we delay startup of the
|
||||||
|
* modbus protocol stack until the bus is free.
|
||||||
|
*/
|
||||||
|
eRcvState = STATE_RX_INIT;
|
||||||
|
vMBPortSerialEnable( TRUE, FALSE );
|
||||||
|
vMBPortTimersEnable( );
|
||||||
|
|
||||||
|
EXIT_CRITICAL_SECTION( );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
eMBRTUStop( void )
|
||||||
|
{
|
||||||
|
ENTER_CRITICAL_SECTION( );
|
||||||
|
vMBPortSerialEnable( FALSE, FALSE );
|
||||||
|
vMBPortTimersDisable( );
|
||||||
|
EXIT_CRITICAL_SECTION( );
|
||||||
|
}
|
||||||
|
|
||||||
|
eMBErrorCode
|
||||||
|
eMBRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength )
|
||||||
|
{
|
||||||
|
BOOL xFrameReceived = FALSE;
|
||||||
|
eMBErrorCode eStatus = MB_ENOERR;
|
||||||
|
|
||||||
|
ENTER_CRITICAL_SECTION( );
|
||||||
|
assert_param( usRcvBufferPos < MB_SER_PDU_SIZE_MAX );
|
||||||
|
|
||||||
|
/* Length and CRC check */
|
||||||
|
if( ( usRcvBufferPos >= MB_SER_PDU_SIZE_MIN )
|
||||||
|
&& ( usMBCRC16( ( UCHAR * ) ucRTUBuf, usRcvBufferPos ) == 0 ) )
|
||||||
|
{
|
||||||
|
/* Save the address field. All frames are passed to the upper layed
|
||||||
|
* and the decision if a frame is used is done there.
|
||||||
|
*/
|
||||||
|
*pucRcvAddress = ucRTUBuf[MB_SER_PDU_ADDR_OFF];
|
||||||
|
|
||||||
|
/* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus
|
||||||
|
* size of address field and CRC checksum.
|
||||||
|
*/
|
||||||
|
*pusLength = ( USHORT )( usRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_CRC );
|
||||||
|
|
||||||
|
/* Return the start of the Modbus PDU to the caller. */
|
||||||
|
*pucFrame = ( UCHAR * ) & ucRTUBuf[MB_SER_PDU_PDU_OFF];
|
||||||
|
xFrameReceived = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eStatus = MB_EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXIT_CRITICAL_SECTION( );
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
eMBErrorCode
|
||||||
|
eMBRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength )
|
||||||
|
{
|
||||||
|
eMBErrorCode eStatus = MB_ENOERR;
|
||||||
|
USHORT usCRC16;
|
||||||
|
|
||||||
|
ENTER_CRITICAL_SECTION( );
|
||||||
|
|
||||||
|
/* Check if the receiver is still in idle state. If not we where to
|
||||||
|
* slow with processing the received frame and the master sent another
|
||||||
|
* frame on the network. We have to abort sending the frame.
|
||||||
|
*/
|
||||||
|
if( eRcvState == STATE_RX_IDLE )
|
||||||
|
{
|
||||||
|
/* First byte before the Modbus-PDU is the slave address. */
|
||||||
|
pucSndBufferCur = ( UCHAR * ) pucFrame - 1;
|
||||||
|
usSndBufferCount = 1;
|
||||||
|
|
||||||
|
/* Now copy the Modbus-PDU into the Modbus-Serial-Line-PDU. */
|
||||||
|
pucSndBufferCur[MB_SER_PDU_ADDR_OFF] = ucSlaveAddress;
|
||||||
|
usSndBufferCount += usLength;
|
||||||
|
|
||||||
|
/* Calculate CRC16 checksum for Modbus-Serial-Line-PDU. */
|
||||||
|
usCRC16 = usMBCRC16( ( UCHAR * ) pucSndBufferCur, usSndBufferCount );
|
||||||
|
ucRTUBuf[usSndBufferCount++] = ( UCHAR )( usCRC16 & 0xFF );
|
||||||
|
ucRTUBuf[usSndBufferCount++] = ( UCHAR )( usCRC16 >> 8 );
|
||||||
|
|
||||||
|
/* Activate the transmitter. */
|
||||||
|
eSndState = STATE_TX_XMIT;
|
||||||
|
vMBPortSerialEnable( FALSE, TRUE );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eStatus = MB_EIO;
|
||||||
|
}
|
||||||
|
EXIT_CRITICAL_SECTION( );
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
xMBRTUReceiveFSM( void )
|
||||||
|
{
|
||||||
|
BOOL xTaskNeedSwitch = FALSE;
|
||||||
|
UCHAR ucByte;
|
||||||
|
|
||||||
|
assert_param( eSndState == STATE_TX_IDLE );
|
||||||
|
|
||||||
|
/* Always read the character. */
|
||||||
|
( void )xMBPortSerialGetByte( ( CHAR * ) & ucByte );
|
||||||
|
|
||||||
|
switch ( eRcvState )
|
||||||
|
{
|
||||||
|
/* If we have received a character in the init state we have to
|
||||||
|
* wait until the frame is finished.
|
||||||
|
*/
|
||||||
|
case STATE_RX_INIT:
|
||||||
|
vMBPortTimersEnable( );
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* In the error state we wait until all characters in the
|
||||||
|
* damaged frame are transmitted.
|
||||||
|
*/
|
||||||
|
case STATE_RX_ERROR:
|
||||||
|
vMBPortTimersEnable( );
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* In the idle state we wait for a new character. If a character
|
||||||
|
* is received the t1.5 and t3.5 timers are started and the
|
||||||
|
* receiver is in the state STATE_RX_RECEIVCE.
|
||||||
|
*/
|
||||||
|
case STATE_RX_IDLE:
|
||||||
|
usRcvBufferPos = 0;
|
||||||
|
ucRTUBuf[usRcvBufferPos++] = ucByte;
|
||||||
|
eRcvState = STATE_RX_RCV;
|
||||||
|
|
||||||
|
/* Enable t3.5 timers. */
|
||||||
|
vMBPortTimersEnable( );
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* We are currently receiving a frame. Reset the timer after
|
||||||
|
* every character received. If more than the maximum possible
|
||||||
|
* number of bytes in a modbus frame is received the frame is
|
||||||
|
* ignored.
|
||||||
|
*/
|
||||||
|
case STATE_RX_RCV:
|
||||||
|
if( usRcvBufferPos < MB_SER_PDU_SIZE_MAX )
|
||||||
|
{
|
||||||
|
ucRTUBuf[usRcvBufferPos++] = ucByte;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eRcvState = STATE_RX_ERROR;
|
||||||
|
}
|
||||||
|
vMBPortTimersEnable();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return xTaskNeedSwitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
xMBRTUTransmitFSM( void )
|
||||||
|
{
|
||||||
|
BOOL xNeedPoll = FALSE;
|
||||||
|
|
||||||
|
assert_param( eRcvState == STATE_RX_IDLE );
|
||||||
|
|
||||||
|
switch ( eSndState )
|
||||||
|
{
|
||||||
|
/* We should not get a transmitter event if the transmitter is in
|
||||||
|
* idle state. */
|
||||||
|
case STATE_TX_IDLE:
|
||||||
|
/* enable receiver/disable transmitter. */
|
||||||
|
vMBPortSerialEnable( TRUE, FALSE );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATE_TX_XMIT:
|
||||||
|
/* check if we are finished. */
|
||||||
|
if( usSndBufferCount != 0 )
|
||||||
|
{
|
||||||
|
xMBPortSerialPutByte( ( CHAR )*pucSndBufferCur );
|
||||||
|
pucSndBufferCur++; /* next byte in sendbuffer. */
|
||||||
|
usSndBufferCount--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xNeedPoll = xMBPortEventPost( EV_FRAME_SENT );
|
||||||
|
/* Disable transmitter. This prevents another transmit buffer
|
||||||
|
* empty interrupt. */
|
||||||
|
vMBPortSerialEnable( TRUE, FALSE );
|
||||||
|
eSndState = STATE_TX_IDLE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return xNeedPoll;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
xMBRTUTimerT35Expired( void )
|
||||||
|
{
|
||||||
|
BOOL xNeedPoll = FALSE;
|
||||||
|
|
||||||
|
switch ( eRcvState )
|
||||||
|
{
|
||||||
|
/* Timer t35 expired. Startup phase is finished. */
|
||||||
|
case STATE_RX_INIT:
|
||||||
|
xNeedPoll = xMBPortEventPost( EV_READY );
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* A frame was received and t35 expired. Notify the listener that
|
||||||
|
* a new frame was received. */
|
||||||
|
case STATE_RX_RCV:
|
||||||
|
xNeedPoll = xMBPortEventPost( EV_FRAME_RECEIVED );
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* An error occured while receiving the frame. */
|
||||||
|
case STATE_RX_ERROR:
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Function called in an illegal state. */
|
||||||
|
default:
|
||||||
|
assert_param( ( eRcvState == STATE_RX_INIT ) ||
|
||||||
|
( eRcvState == STATE_RX_RCV ) || ( eRcvState == STATE_RX_ERROR ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
vMBPortTimersDisable( );
|
||||||
|
eRcvState = STATE_RX_IDLE;
|
||||||
|
|
||||||
|
return xNeedPoll;
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||||
|
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* File: $Id: mbrtu.h,v 1.9 2006/12/07 22:10:34 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MB_RTU_H
|
||||||
|
#define _MB_RTU_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
PR_BEGIN_EXTERN_C
|
||||||
|
#endif
|
||||||
|
eMBErrorCode eMBRTUInit( UCHAR slaveAddress, UCHAR ucPort, ULONG ulBaudRate,
|
||||||
|
eMBParity eParity );
|
||||||
|
void eMBRTUStart( void );
|
||||||
|
void eMBRTUStop( void );
|
||||||
|
eMBErrorCode eMBRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength );
|
||||||
|
eMBErrorCode eMBRTUSend( UCHAR slaveAddress, const UCHAR * pucFrame, USHORT usLength );
|
||||||
|
BOOL xMBRTUReceiveFSM( void );
|
||||||
|
BOOL xMBRTUTransmitFSM( void );
|
||||||
|
BOOL xMBRTUTimerT15Expired( void );
|
||||||
|
BOOL xMBRTUTimerT35Expired( void );
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
PR_END_EXTERN_C
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,158 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||||
|
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* File: $Id: mbtcp.c,v 1.3 2006/12/07 22:10:34 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ----------------------- System includes ----------------------------------*/
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
/* ----------------------- Platform includes --------------------------------*/
|
||||||
|
#include "port.h"
|
||||||
|
|
||||||
|
/* ----------------------- Modbus includes ----------------------------------*/
|
||||||
|
#include "mb.h"
|
||||||
|
#include "mbconfig.h"
|
||||||
|
#include "mbtcp.h"
|
||||||
|
#include "mbframe.h"
|
||||||
|
#include "mbport.h"
|
||||||
|
|
||||||
|
#if MB_TCP_ENABLED > 0
|
||||||
|
|
||||||
|
/* ----------------------- Defines ------------------------------------------*/
|
||||||
|
|
||||||
|
/* ----------------------- MBAP Header --------------------------------------*/
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* <------------------------ MODBUS TCP/IP ADU(1) ------------------------->
|
||||||
|
* <----------- MODBUS PDU (1') ---------------->
|
||||||
|
* +-----------+---------------+------------------------------------------+
|
||||||
|
* | TID | PID | Length | UID |Code | Data |
|
||||||
|
* +-----------+---------------+------------------------------------------+
|
||||||
|
* | | | | |
|
||||||
|
* (2) (3) (4) (5) (6)
|
||||||
|
*
|
||||||
|
* (2) ... MB_TCP_TID = 0 (Transaction Identifier - 2 Byte)
|
||||||
|
* (3) ... MB_TCP_PID = 2 (Protocol Identifier - 2 Byte)
|
||||||
|
* (4) ... MB_TCP_LEN = 4 (Number of bytes - 2 Byte)
|
||||||
|
* (5) ... MB_TCP_UID = 6 (Unit Identifier - 1 Byte)
|
||||||
|
* (6) ... MB_TCP_FUNC = 7 (Modbus Function Code)
|
||||||
|
*
|
||||||
|
* (1) ... Modbus TCP/IP Application Data Unit
|
||||||
|
* (1') ... Modbus Protocol Data Unit
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MB_TCP_TID 0
|
||||||
|
#define MB_TCP_PID 2
|
||||||
|
#define MB_TCP_LEN 4
|
||||||
|
#define MB_TCP_UID 6
|
||||||
|
#define MB_TCP_FUNC 7
|
||||||
|
|
||||||
|
#define MB_TCP_PROTOCOL_ID 0 /* 0 = Modbus Protocol */
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------------------- Start implementation -----------------------------*/
|
||||||
|
eMBErrorCode
|
||||||
|
eMBTCPDoInit( USHORT ucTCPPort )
|
||||||
|
{
|
||||||
|
eMBErrorCode eStatus = MB_ENOERR;
|
||||||
|
|
||||||
|
if( xMBTCPPortInit( ucTCPPort ) == FALSE )
|
||||||
|
{
|
||||||
|
eStatus = MB_EPORTERR;
|
||||||
|
}
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
eMBTCPStart( void )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
eMBTCPStop( void )
|
||||||
|
{
|
||||||
|
/* Make sure that no more clients are connected. */
|
||||||
|
vMBTCPPortDisable( );
|
||||||
|
}
|
||||||
|
|
||||||
|
eMBErrorCode
|
||||||
|
eMBTCPReceive( UCHAR * pucRcvAddress, UCHAR ** ppucFrame, USHORT * pusLength )
|
||||||
|
{
|
||||||
|
eMBErrorCode eStatus = MB_EIO;
|
||||||
|
UCHAR *pucMBTCPFrame;
|
||||||
|
USHORT usLength;
|
||||||
|
USHORT usPID;
|
||||||
|
|
||||||
|
if( xMBTCPPortGetRequest( &pucMBTCPFrame, &usLength ) != FALSE )
|
||||||
|
{
|
||||||
|
usPID = pucMBTCPFrame[MB_TCP_PID] << 8U;
|
||||||
|
usPID |= pucMBTCPFrame[MB_TCP_PID + 1];
|
||||||
|
|
||||||
|
if( usPID == MB_TCP_PROTOCOL_ID )
|
||||||
|
{
|
||||||
|
*ppucFrame = &pucMBTCPFrame[MB_TCP_FUNC];
|
||||||
|
*pusLength = usLength - MB_TCP_FUNC;
|
||||||
|
eStatus = MB_ENOERR;
|
||||||
|
|
||||||
|
/* Modbus TCP does not use any addresses. Fake the source address such
|
||||||
|
* that the processing part deals with this frame.
|
||||||
|
*/
|
||||||
|
*pucRcvAddress = MB_TCP_PSEUDO_ADDRESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eStatus = MB_EIO;
|
||||||
|
}
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
eMBErrorCode
|
||||||
|
eMBTCPSend( UCHAR _unused, const UCHAR * pucFrame, USHORT usLength )
|
||||||
|
{
|
||||||
|
eMBErrorCode eStatus = MB_ENOERR;
|
||||||
|
UCHAR *pucMBTCPFrame = ( UCHAR * ) pucFrame - MB_TCP_FUNC;
|
||||||
|
USHORT usTCPLength = usLength + MB_TCP_FUNC;
|
||||||
|
|
||||||
|
/* The MBAP header is already initialized because the caller calls this
|
||||||
|
* function with the buffer returned by the previous call. Therefore we
|
||||||
|
* only have to update the length in the header. Note that the length
|
||||||
|
* header includes the size of the Modbus PDU and the UID Byte. Therefore
|
||||||
|
* the length is usLength plus one.
|
||||||
|
*/
|
||||||
|
pucMBTCPFrame[MB_TCP_LEN] = ( usLength + 1 ) >> 8U;
|
||||||
|
pucMBTCPFrame[MB_TCP_LEN + 1] = ( usLength + 1 ) & 0xFF;
|
||||||
|
if( xMBTCPPortSendResponse( pucMBTCPFrame, usTCPLength ) == FALSE )
|
||||||
|
{
|
||||||
|
eStatus = MB_EIO;
|
||||||
|
}
|
||||||
|
return eStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||||
|
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* File: $Id: mbtcp.h,v 1.2 2006/12/07 22:10:34 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MB_TCP_H
|
||||||
|
#define _MB_TCP_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
PR_BEGIN_EXTERN_C
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ----------------------- Defines ------------------------------------------*/
|
||||||
|
#define MB_TCP_PSEUDO_ADDRESS 255
|
||||||
|
|
||||||
|
/* ----------------------- Function prototypes ------------------------------*/
|
||||||
|
eMBErrorCode eMBTCPDoInit( USHORT ucTCPPort );
|
||||||
|
void eMBTCPStart( void );
|
||||||
|
void eMBTCPStop( void );
|
||||||
|
eMBErrorCode eMBTCPReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame,
|
||||||
|
USHORT * pusLength );
|
||||||
|
eMBErrorCode eMBTCPSend( UCHAR _unused, const UCHAR * pucFrame,
|
||||||
|
USHORT usLength );
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
PR_END_EXTERN_C
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: LPC214X Port
|
||||||
|
* Copyright (C) 2007 Tiago Prado Lone <tiago@maxwellbohr.com.br>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* File: $Id: port.c,v 1.1 2007/04/24 23:15:18 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ----------------------- System includes --------------------------------*/
|
||||||
|
|
||||||
|
/* ----------------------- Modbus includes ----------------------------------*/
|
||||||
|
#include "port.h"
|
||||||
|
/* ----------------------- Variables ----------------------------------------*/
|
||||||
|
|
||||||
|
/* ----------------------- Start implementation -----------------------------*/
|
||||||
|
void EnterCriticalSection(void)
|
||||||
|
{
|
||||||
|
//关闭全局中断
|
||||||
|
__disable_irq();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExitCriticalSection(void)
|
||||||
|
{
|
||||||
|
//开启全局中断
|
||||||
|
__enable_irq();
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: BARE Port
|
||||||
|
* Copyright (C) 2006 Christian Walter <wolti@sil.at>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* File: $Id: port.h,v 1.1 2007/04/24 23:15:18 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PORT_H
|
||||||
|
#define _PORT_H
|
||||||
|
|
||||||
|
#include <stm32f10x_conf.h>
|
||||||
|
#include <rthw.h>
|
||||||
|
#include <rtthread.h>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#define INLINE
|
||||||
|
#define PR_BEGIN_EXTERN_C extern "C" {
|
||||||
|
#define PR_END_EXTERN_C }
|
||||||
|
|
||||||
|
//TODO 暂时先写B13引脚,等组网测试时再确认
|
||||||
|
#define RS485_SEND_MODE GPIO_SetBits(GPIOB,GPIO_Pin_13)
|
||||||
|
#define RS485_RECEIVE_MODE GPIO_ResetBits(GPIOB,GPIO_Pin_13)
|
||||||
|
|
||||||
|
//void USART1_IRQHandler(void);
|
||||||
|
//void TIM3_IRQHandler(void);
|
||||||
|
|
||||||
|
#define ENTER_CRITICAL_SECTION() EnterCriticalSection()
|
||||||
|
#define EXIT_CRITICAL_SECTION() ExitCriticalSection()
|
||||||
|
|
||||||
|
void EnterCriticalSection(void);
|
||||||
|
void ExitCriticalSection(void);
|
||||||
|
void prvvUARTTxReadyISR(void);
|
||||||
|
void prvvUARTRxISR(void);
|
||||||
|
void TIMERExpiredISR(void);
|
||||||
|
|
||||||
|
typedef uint8_t BOOL;
|
||||||
|
|
||||||
|
typedef unsigned char UCHAR;
|
||||||
|
typedef char CHAR;
|
||||||
|
|
||||||
|
typedef uint16_t USHORT;
|
||||||
|
typedef int16_t SHORT;
|
||||||
|
|
||||||
|
typedef uint32_t ULONG;
|
||||||
|
typedef int32_t LONG;
|
||||||
|
|
||||||
|
#ifndef TRUE
|
||||||
|
#define TRUE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FALSE
|
||||||
|
#define FALSE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: LPC214X Port
|
||||||
|
* Copyright (C) 2007 Tiago Prado Lone <tiago@maxwellbohr.com.br>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* File: $Id: portevent.c,v 1.1 2007/04/24 23:15:18 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ----------------------- Modbus includes ----------------------------------*/
|
||||||
|
#include "mb.h"
|
||||||
|
#include "mbport.h"
|
||||||
|
|
||||||
|
/* ----------------------- Variables ----------------------------------------*/
|
||||||
|
static eMBEventType eQueuedEvent;
|
||||||
|
static BOOL xEventInQueue;
|
||||||
|
|
||||||
|
/* ----------------------- Start implementation -----------------------------*/
|
||||||
|
BOOL
|
||||||
|
xMBPortEventInit( void )
|
||||||
|
{
|
||||||
|
xEventInQueue = FALSE;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
xMBPortEventPost( eMBEventType eEvent )
|
||||||
|
{
|
||||||
|
xEventInQueue = TRUE;
|
||||||
|
eQueuedEvent = eEvent;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
xMBPortEventGet( eMBEventType * eEvent )
|
||||||
|
{
|
||||||
|
BOOL xEventHappened = FALSE;
|
||||||
|
|
||||||
|
if( xEventInQueue )
|
||||||
|
{
|
||||||
|
*eEvent = eQueuedEvent;
|
||||||
|
xEventInQueue = FALSE;
|
||||||
|
xEventHappened = TRUE;
|
||||||
|
}
|
||||||
|
return xEventHappened;
|
||||||
|
}
|
|
@ -0,0 +1,190 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: LPC214X Port
|
||||||
|
* Copyright (C) 2007 Tiago Prado Lone <tiago@maxwellbohr.com.br>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* File: $Id: portserial.c,v 1.1 2007/04/24 23:15:18 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "port.h"
|
||||||
|
|
||||||
|
/* ----------------------- Modbus includes ----------------------------------*/
|
||||||
|
#include "mb.h"
|
||||||
|
#include "mbport.h"
|
||||||
|
/* ----------------------- static functions ---------------------------------*/
|
||||||
|
static void prvvUARTTxReadyISR(void);
|
||||||
|
static void prvvUARTRxISR(void);
|
||||||
|
/* ----------------------- Start implementation -----------------------------*/
|
||||||
|
|
||||||
|
void vMBPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable)
|
||||||
|
{
|
||||||
|
if (xRxEnable)
|
||||||
|
{
|
||||||
|
RS485_RECEIVE_MODE;
|
||||||
|
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RS485_SEND_MODE;
|
||||||
|
USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
|
||||||
|
}
|
||||||
|
if (xTxEnable)
|
||||||
|
{
|
||||||
|
USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vMBPortClose(void)
|
||||||
|
{
|
||||||
|
USART_ITConfig(USART1, USART_IT_TXE | USART_IT_RXNE, DISABLE);
|
||||||
|
USART_Cmd(USART1, DISABLE);
|
||||||
|
}
|
||||||
|
//默认一个从机 串口1 波特率可设置 奇偶检验可设置
|
||||||
|
BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
|
||||||
|
eMBParity eParity)
|
||||||
|
{
|
||||||
|
GPIO_InitTypeDef GPIO_InitStructure;
|
||||||
|
USART_InitTypeDef USART_InitStructure;
|
||||||
|
NVIC_InitTypeDef NVIC_InitStructure;
|
||||||
|
//======================时钟初始化=======================================
|
||||||
|
RCC_APB2PeriphClockCmd(
|
||||||
|
RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_USART1,
|
||||||
|
ENABLE);
|
||||||
|
//======================IO初始化=======================================
|
||||||
|
//USART1_TX
|
||||||
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
||||||
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
|
||||||
|
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
|
||||||
|
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||||
|
//USART1_RX
|
||||||
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
||||||
|
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
|
||||||
|
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||||
|
//配置485发送和接收模式
|
||||||
|
// TODO 暂时先写B13 等之后组网测试时再修改
|
||||||
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||||
|
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
|
||||||
|
GPIO_Init(GPIOB, &GPIO_InitStructure);
|
||||||
|
//======================串口初始化=======================================
|
||||||
|
USART_InitStructure.USART_BaudRate = ulBaudRate;
|
||||||
|
//设置校验模式
|
||||||
|
switch (eParity)
|
||||||
|
{
|
||||||
|
case MB_PAR_NONE: //无校验
|
||||||
|
USART_InitStructure.USART_Parity = USART_Parity_No;
|
||||||
|
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
|
||||||
|
break;
|
||||||
|
case MB_PAR_ODD: //奇校验
|
||||||
|
USART_InitStructure.USART_Parity = USART_Parity_Odd;
|
||||||
|
USART_InitStructure.USART_WordLength = USART_WordLength_9b;
|
||||||
|
break;
|
||||||
|
case MB_PAR_EVEN: //偶校验
|
||||||
|
USART_InitStructure.USART_Parity = USART_Parity_Even;
|
||||||
|
USART_InitStructure.USART_WordLength = USART_WordLength_9b;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
USART_InitStructure.USART_StopBits = USART_StopBits_1;
|
||||||
|
USART_InitStructure.USART_HardwareFlowControl =
|
||||||
|
USART_HardwareFlowControl_None;
|
||||||
|
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
|
||||||
|
if (ucPORT > 1)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
ENTER_CRITICAL_SECTION(); //关全局中断
|
||||||
|
|
||||||
|
USART_Init(USART1, &USART_InitStructure);
|
||||||
|
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
|
||||||
|
USART_Cmd(USART1, ENABLE);
|
||||||
|
|
||||||
|
//=====================中断初始化======================================
|
||||||
|
//设置NVIC优先级分组为Group2:0-3抢占式优先级,0-3的响应式优先级
|
||||||
|
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
|
||||||
|
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
|
||||||
|
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
|
||||||
|
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
|
||||||
|
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||||
|
NVIC_Init(&NVIC_InitStructure);
|
||||||
|
|
||||||
|
EXIT_CRITICAL_SECTION(); //开全局中断
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL xMBPortSerialPutByte(CHAR ucByte)
|
||||||
|
{
|
||||||
|
USART_SendData(USART1, ucByte);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL xMBPortSerialGetByte(CHAR * pucByte)
|
||||||
|
{
|
||||||
|
*pucByte = USART_ReceiveData(USART1);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create an interrupt handler for the transmit buffer empty interrupt
|
||||||
|
* (or an equivalent) for your target processor. This function should then
|
||||||
|
* call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
|
||||||
|
* a new character can be sent. The protocol stack will then call
|
||||||
|
* xMBPortSerialPutByte( ) to send the character.
|
||||||
|
*/
|
||||||
|
void prvvUARTTxReadyISR(void)
|
||||||
|
{
|
||||||
|
pxMBFrameCBTransmitterEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create an interrupt handler for the receive interrupt for your target
|
||||||
|
* processor. This function should then call pxMBFrameCBByteReceived( ). The
|
||||||
|
* protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
|
||||||
|
* character.
|
||||||
|
*/
|
||||||
|
void prvvUARTRxISR(void)
|
||||||
|
{
|
||||||
|
pxMBFrameCBByteReceived();
|
||||||
|
}
|
||||||
|
/*******************************************************************************
|
||||||
|
* Function Name : USART1_IRQHandler
|
||||||
|
* Description : This function handles USART1 global interrupt request.
|
||||||
|
* Input : None
|
||||||
|
* Output : None
|
||||||
|
* Return : None
|
||||||
|
*******************************************************************************/
|
||||||
|
void USART1_IRQHandler(void)
|
||||||
|
{
|
||||||
|
rt_interrupt_enter();
|
||||||
|
//接收中断
|
||||||
|
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
|
||||||
|
{
|
||||||
|
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
|
||||||
|
prvvUARTRxISR();
|
||||||
|
}
|
||||||
|
//发送中断
|
||||||
|
if (USART_GetITStatus(USART1, USART_IT_TXE) == SET)
|
||||||
|
{
|
||||||
|
USART_ClearITPendingBit(USART1, USART_IT_TC);
|
||||||
|
prvvUARTTxReadyISR();
|
||||||
|
}
|
||||||
|
rt_interrupt_leave();
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* FreeModbus Libary: LPC214X Port
|
||||||
|
* Copyright (C) 2007 Tiago Prado Lone <tiago@maxwellbohr.com.br>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* File: $Id: porttimer.c,v 1.1 2007/04/24 23:15:18 wolti Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ----------------------- Platform includes --------------------------------*/
|
||||||
|
#include "port.h"
|
||||||
|
|
||||||
|
/* ----------------------- Modbus includes ----------------------------------*/
|
||||||
|
#include "mb.h"
|
||||||
|
#include "mbport.h"
|
||||||
|
|
||||||
|
/* ----------------------- Start implementation -----------------------------*/
|
||||||
|
BOOL xMBPortTimersInit(USHORT usTim1Timerout50us)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint16_t PrescalerValue = 0;
|
||||||
|
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
|
||||||
|
NVIC_InitTypeDef NVIC_InitStructure;
|
||||||
|
//====================================时钟初始化===========================
|
||||||
|
//使能定时器3时钟
|
||||||
|
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
|
||||||
|
//====================================定时器初始化===========================
|
||||||
|
//定时器时间基配置说明
|
||||||
|
//HCLK为72MHz,APB1经过2分频为36MHz
|
||||||
|
//TIM3的时钟倍频后为72MHz(硬件自动倍频,达到最大)
|
||||||
|
//TIM3的分频系数为3599,时间基频率为72 / (1 + Prescaler) = 20KHz,基准为50us
|
||||||
|
//TIM最大计数值为usTim1Timerout50u
|
||||||
|
|
||||||
|
PrescalerValue = (uint16_t) (SystemCoreClock / 20000) - 1;
|
||||||
|
//定时器1初始化
|
||||||
|
TIM_TimeBaseStructure.TIM_Period = (uint16_t) usTim1Timerout50us;
|
||||||
|
TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;
|
||||||
|
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
|
||||||
|
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
||||||
|
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
|
||||||
|
//预装载使能
|
||||||
|
TIM_ARRPreloadConfig(TIM3, ENABLE);
|
||||||
|
//====================================中断初始化===========================
|
||||||
|
//设置NVIC优先级分组为Group2:0-3抢占式优先级,0-3的响应式优先级
|
||||||
|
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
|
||||||
|
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
|
||||||
|
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
|
||||||
|
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
|
||||||
|
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
|
||||||
|
NVIC_Init(&NVIC_InitStructure);
|
||||||
|
//清除溢出中断标志位
|
||||||
|
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
|
||||||
|
//定时器3溢出中断关闭
|
||||||
|
TIM_ITConfig(TIM3, TIM_IT_Update, DISABLE);
|
||||||
|
//定时器3禁能
|
||||||
|
TIM_Cmd(TIM3, DISABLE);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vMBPortTimersEnable()
|
||||||
|
{
|
||||||
|
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
|
||||||
|
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
|
||||||
|
TIM_SetCounter(TIM3, 0);
|
||||||
|
TIM_Cmd(TIM3, ENABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vMBPortTimersDisable()
|
||||||
|
{
|
||||||
|
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
|
||||||
|
TIM_ITConfig(TIM3, TIM_IT_Update, DISABLE);
|
||||||
|
TIM_SetCounter(TIM3, 0);
|
||||||
|
TIM_Cmd(TIM3, DISABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void prvvTIMERExpiredISR(void)
|
||||||
|
{
|
||||||
|
(void) pxMBPortCBTimerExpired();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TIM3_IRQHandler(void)
|
||||||
|
{
|
||||||
|
rt_interrupt_enter();
|
||||||
|
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
|
||||||
|
{
|
||||||
|
|
||||||
|
TIM_ClearFlag(TIM3, TIM_FLAG_Update); //清中断标记
|
||||||
|
TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除定时器T3溢出中断标志位
|
||||||
|
prvvTIMERExpiredISR();
|
||||||
|
}
|
||||||
|
rt_interrupt_leave();
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
|
@ -400,6 +400,11 @@
|
||||||
<FileType>1</FileType>
|
<FileType>1</FileType>
|
||||||
<FilePath>..\APP\src\stm32f10x_it.c</FilePath>
|
<FilePath>..\APP\src\stm32f10x_it.c</FilePath>
|
||||||
</File>
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>UserModbusSlaver.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\APP\src\UserModbusSlaver.c</FilePath>
|
||||||
|
</File>
|
||||||
<File>
|
<File>
|
||||||
<FileName>cpuusage.c</FileName>
|
<FileName>cpuusage.c</FileName>
|
||||||
<FileType>1</FileType>
|
<FileType>1</FileType>
|
||||||
|
@ -566,9 +571,9 @@
|
||||||
<FilePath>..\Libaries\STM32F10x_StdPeriph_Driver\src\stm32f10x_wwdg.c</FilePath>
|
<FilePath>..\Libaries\STM32F10x_StdPeriph_Driver\src\stm32f10x_wwdg.c</FilePath>
|
||||||
</File>
|
</File>
|
||||||
<File>
|
<File>
|
||||||
<FileName>startup_stm32f10x_hd.s</FileName>
|
<FileName>startup_stm32f10x_md.s</FileName>
|
||||||
<FileType>2</FileType>
|
<FileType>2</FileType>
|
||||||
<FilePath>..\Libaries\CMSIS_MDK\CM3\DeviceSupport\ST\STM32F10x\startup\arm\startup_stm32f10x_hd.s</FilePath>
|
<FilePath>..\Libaries\CMSIS_MDK\CM3\DeviceSupport\ST\STM32F10x\startup\arm\startup_stm32f10x_md.s</FilePath>
|
||||||
</File>
|
</File>
|
||||||
</Files>
|
</Files>
|
||||||
</Group>
|
</Group>
|
||||||
|
@ -667,6 +672,81 @@
|
||||||
</File>
|
</File>
|
||||||
</Files>
|
</Files>
|
||||||
</Group>
|
</Group>
|
||||||
|
<Group>
|
||||||
|
<GroupName>FreeModbusSlaver</GroupName>
|
||||||
|
<Files>
|
||||||
|
<File>
|
||||||
|
<FileName>mb.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\modbus\mb.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>mbfunccoils.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\modbus\functions\mbfunccoils.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>mbfuncdiag.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\modbus\functions\mbfuncdiag.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>mbfuncdisc.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\modbus\functions\mbfuncdisc.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>mbfuncholding.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\modbus\functions\mbfuncholding.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>mbfuncinput.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\modbus\functions\mbfuncinput.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>mbfuncother.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\modbus\functions\mbfuncother.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>mbutils.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\modbus\functions\mbutils.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>mbcrc.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\modbus\rtu\mbcrc.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>mbrtu.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\modbus\rtu\mbrtu.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>port.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\port\port.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>portevent.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\port\portevent.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>portserial.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\port\portserial.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>porttimer.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\port\porttimer.c</FilePath>
|
||||||
|
</File>
|
||||||
|
</Files>
|
||||||
|
</Group>
|
||||||
</Groups>
|
</Groups>
|
||||||
</Target>
|
</Target>
|
||||||
<Target>
|
<Target>
|
||||||
|
@ -1008,7 +1088,7 @@
|
||||||
<MiscControls></MiscControls>
|
<MiscControls></MiscControls>
|
||||||
<Define>USE_STDPERIPH_DRIVER,STM32F10X_MD</Define>
|
<Define>USE_STDPERIPH_DRIVER,STM32F10X_MD</Define>
|
||||||
<Undefine></Undefine>
|
<Undefine></Undefine>
|
||||||
<IncludePath>..\Libaries\CMSIS_MDK\CM3\CoreSupport;..\Libaries\CMSIS_MDK\CM3\DeviceSupport\ST\STM32F10x;..\Libaries\STM32F10x_StdPeriph_Driver\inc;..\Libaries\USB-FS-Device_Driver\inc;..\BSP\inc;..\APP\inc;..\RT-Thread-1.1.1\include;..\RT-Thread-1.1.1\libcpu\arm\stm32</IncludePath>
|
<IncludePath>..\Libaries\CMSIS_MDK\CM3\CoreSupport;..\Libaries\CMSIS_MDK\CM3\DeviceSupport\ST\STM32F10x;..\Libaries\STM32F10x_StdPeriph_Driver\inc;..\Libaries\USB-FS-Device_Driver\inc;..\BSP\inc;..\APP\inc;..\RT-Thread-1.1.1\include;..\RT-Thread-1.1.1\libcpu\arm\stm32;..\FreeModbus\modbus\include;..\FreeModbus\modbus\rtu;..\FreeModbus\port</IncludePath>
|
||||||
</VariousControls>
|
</VariousControls>
|
||||||
</Cads>
|
</Cads>
|
||||||
<Aads>
|
<Aads>
|
||||||
|
@ -1063,6 +1143,11 @@
|
||||||
<FileType>1</FileType>
|
<FileType>1</FileType>
|
||||||
<FilePath>..\APP\src\stm32f10x_it.c</FilePath>
|
<FilePath>..\APP\src\stm32f10x_it.c</FilePath>
|
||||||
</File>
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>UserModbusSlaver.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\APP\src\UserModbusSlaver.c</FilePath>
|
||||||
|
</File>
|
||||||
<File>
|
<File>
|
||||||
<FileName>cpuusage.c</FileName>
|
<FileName>cpuusage.c</FileName>
|
||||||
<FileType>1</FileType>
|
<FileType>1</FileType>
|
||||||
|
@ -1229,9 +1314,9 @@
|
||||||
<FilePath>..\Libaries\STM32F10x_StdPeriph_Driver\src\stm32f10x_wwdg.c</FilePath>
|
<FilePath>..\Libaries\STM32F10x_StdPeriph_Driver\src\stm32f10x_wwdg.c</FilePath>
|
||||||
</File>
|
</File>
|
||||||
<File>
|
<File>
|
||||||
<FileName>startup_stm32f10x_hd.s</FileName>
|
<FileName>startup_stm32f10x_md.s</FileName>
|
||||||
<FileType>2</FileType>
|
<FileType>2</FileType>
|
||||||
<FilePath>..\Libaries\CMSIS_MDK\CM3\DeviceSupport\ST\STM32F10x\startup\arm\startup_stm32f10x_hd.s</FilePath>
|
<FilePath>..\Libaries\CMSIS_MDK\CM3\DeviceSupport\ST\STM32F10x\startup\arm\startup_stm32f10x_md.s</FilePath>
|
||||||
</File>
|
</File>
|
||||||
</Files>
|
</Files>
|
||||||
</Group>
|
</Group>
|
||||||
|
@ -1330,6 +1415,81 @@
|
||||||
</File>
|
</File>
|
||||||
</Files>
|
</Files>
|
||||||
</Group>
|
</Group>
|
||||||
|
<Group>
|
||||||
|
<GroupName>FreeModbusSlaver</GroupName>
|
||||||
|
<Files>
|
||||||
|
<File>
|
||||||
|
<FileName>mb.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\modbus\mb.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>mbfunccoils.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\modbus\functions\mbfunccoils.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>mbfuncdiag.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\modbus\functions\mbfuncdiag.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>mbfuncdisc.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\modbus\functions\mbfuncdisc.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>mbfuncholding.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\modbus\functions\mbfuncholding.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>mbfuncinput.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\modbus\functions\mbfuncinput.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>mbfuncother.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\modbus\functions\mbfuncother.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>mbutils.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\modbus\functions\mbutils.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>mbcrc.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\modbus\rtu\mbcrc.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>mbrtu.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\modbus\rtu\mbrtu.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>port.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\port\port.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>portevent.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\port\portevent.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>portserial.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\port\portserial.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>porttimer.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\FreeModbus\port\porttimer.c</FilePath>
|
||||||
|
</File>
|
||||||
|
</Files>
|
||||||
|
</Group>
|
||||||
</Groups>
|
</Groups>
|
||||||
</Target>
|
</Target>
|
||||||
</Targets>
|
</Targets>
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
1091
RVMDK/JLinkLog.txt
1091
RVMDK/JLinkLog.txt
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue