mirror of
https://github.com/IoTManagerProject/IoTManager.git
synced 2026-03-26 14:12:16 +03:00
modbus support
This commit is contained in:
66
lib/ModbusMaster/.github/ISSUE_TEMPLATE.md
vendored
Normal file
66
lib/ModbusMaster/.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
<!----------------------------------------------------------------------------
|
||||
Title - ensure the issue title is clear & concise
|
||||
- QUESTIONS - describe the specific question
|
||||
- BUG REPORTS - describe an activity
|
||||
- FEATURE REQUESTS - describe an activity
|
||||
-->
|
||||
|
||||
<!----------------------------------------------------------------------------
|
||||
Provide the following information for all issues. Replace [brackets] and placeholder text with your responses.
|
||||
(QUESTIONS, BUG REPORTS, FEATURE REQUESTS)
|
||||
-->
|
||||
### ModbusMaster version
|
||||
[Version of the project where you are encountering the issue]
|
||||
|
||||
### Arduino IDE version
|
||||
[Version of Arduino IDE in your environment]
|
||||
|
||||
### Arduino Hardware
|
||||
[Hardware information, including board and processor]
|
||||
|
||||
### Platform Details
|
||||
[Operating system distribution and release version]
|
||||
|
||||
---
|
||||
<!----------------------------------------------------------------------------
|
||||
Provide the following for QUESTIONS & BUG REPORTS. Replace [brackets] and placeholder text with your responses.
|
||||
-->
|
||||
### Scenario:
|
||||
[What you are trying to achieve and you can't?]
|
||||
|
||||
### Steps to Reproduce:
|
||||
[If you are filing an issue what are the things we need to do in order to repro your problem? How are you using this project or any resources it includes?]
|
||||
|
||||
### Expected Result:
|
||||
[What are you expecting to happen as the consequence of above reproduction steps?]
|
||||
|
||||
### Actual Result:
|
||||
[What actually happens after the reproduction steps? Include the error output or a link to a gist if possible.]
|
||||
|
||||
---
|
||||
<!----------------------------------------------------------------------------
|
||||
Provide the following for FEATURE REQUESTS. Replace [brackets] and placeholder text with your responses.
|
||||
Refer to [What's in a Story?](https://dannorth.net/whats-in-a-story/)
|
||||
-->
|
||||
### Feature Request
|
||||
|
||||
#### Narrative:
|
||||
<!-- Replace role, feature, benefit. -->
|
||||
```` text
|
||||
As a [role]
|
||||
I want [feature]
|
||||
So that [benefit]
|
||||
````
|
||||
|
||||
#### Acceptance Criteria:
|
||||
<!--
|
||||
Present as one or more Scenarios, replacing context, event, outcome.
|
||||
-->
|
||||
```` text
|
||||
Scenario 1: Title
|
||||
Given [context]
|
||||
And [some more context]...
|
||||
When [event]
|
||||
Then [outcome]
|
||||
And [another outcome]...
|
||||
````
|
||||
37
lib/ModbusMaster/.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
37
lib/ModbusMaster/.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<!----------------------------------------------------------------------------
|
||||
Please make sure you've read and understood our contributing guidelines;
|
||||
https://github.com/4-20ma/ModbusMaster/blob/master/CONTRIBUTING.md
|
||||
|
||||
Provide the following information for all issues. Replace [brackets] and placeholder text with your responses.
|
||||
(QUESTIONS, BUG REPORTS, FEATURE REQUESTS).
|
||||
-->
|
||||
### Description
|
||||
[Describe what this change achieves]
|
||||
|
||||
### Issues Resolved
|
||||
[List any existing issues this PR resolves; include Fixes #xxx or Closes #xxx (where xxx is issue number)]
|
||||
|
||||
### Check List
|
||||
|
||||
General
|
||||
|
||||
- [ ] Code follows coding style defined in STYLE.md
|
||||
- [ ] Doxygen comments are included inline with code
|
||||
- [ ] No unnecessary whitespace; check with `git diff --check` before committing.
|
||||
|
||||
The following have been modified to reflect new features, if warranted
|
||||
|
||||
- [ ] README.md
|
||||
- [ ] keywords.txt (use tabs as whitespace separators)
|
||||
- [ ] library.properties
|
||||
- [ ] examples/ - update or create new ones, as warranted
|
||||
|
||||
The following have **NOT** been modified
|
||||
|
||||
- [ ] doc/ - will be updated upon versioned release
|
||||
- [ ] .ruby-gemset
|
||||
- [ ] .ruby-version
|
||||
- [ ] CHANGELOG.md - will be updated upon versioned release (HISTORY.md is deprecated)
|
||||
- [ ] Gemfile
|
||||
- [ ] LICENSE
|
||||
- [ ] VERSION - will be updated upon versioned release
|
||||
8
lib/ModbusMaster/.github_changelog_generator
Normal file
8
lib/ModbusMaster/.github_changelog_generator
Normal file
@@ -0,0 +1,8 @@
|
||||
add_issues_wo_labels=false
|
||||
add_pr_wo_labels=false
|
||||
enhancement-labels=Type: Enhancement
|
||||
bug-labels=Type: Bug
|
||||
exclude-labels=Type: Question
|
||||
header=# ModbusMaster CHANGELOG
|
||||
include-labels=Type: Bug,Type: Enhancement,Type: Feature Request,Type: Maintenance
|
||||
future-release=Unreleased
|
||||
56
lib/ModbusMaster/.gitignore
vendored
Normal file
56
lib/ModbusMaster/.gitignore
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
#---------------------------------------------------------------- ModbusMaster
|
||||
doc/html/
|
||||
doc/latex/
|
||||
|
||||
|
||||
#-------------- https://github.com/github/gitignore/blob/master/Ruby.gitignore
|
||||
*.gem
|
||||
*.rbc
|
||||
/.config
|
||||
/coverage/
|
||||
/InstalledFiles
|
||||
/pkg/
|
||||
/spec/reports/
|
||||
/spec/examples.txt
|
||||
/test/tmp/
|
||||
/test/version_tmp/
|
||||
/tmp/
|
||||
|
||||
# Used by dotenv library to load environment variables.
|
||||
# .env
|
||||
|
||||
## Specific to RubyMotion:
|
||||
.dat*
|
||||
.repl_history
|
||||
build/
|
||||
*.bridgesupport
|
||||
build-iPhoneOS/
|
||||
build-iPhoneSimulator/
|
||||
|
||||
## Specific to RubyMotion (use of CocoaPods):
|
||||
#
|
||||
# We recommend against adding the Pods directory to your .gitignore. However
|
||||
# you should judge for yourself, the pros and cons are mentioned at:
|
||||
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
||||
#
|
||||
# vendor/Pods/
|
||||
|
||||
## Documentation cache and generated files:
|
||||
/.yardoc/
|
||||
/_yardoc/
|
||||
/doc/
|
||||
/rdoc/
|
||||
|
||||
## Environment normalization:
|
||||
/.bundle/
|
||||
/vendor/bundle
|
||||
/lib/bundler/man/
|
||||
|
||||
# for a library or gem, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# Gemfile.lock
|
||||
# .ruby-version
|
||||
# .ruby-gemset
|
||||
|
||||
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
||||
.rvmrc
|
||||
1
lib/ModbusMaster/.ruby-gemset
Normal file
1
lib/ModbusMaster/.ruby-gemset
Normal file
@@ -0,0 +1 @@
|
||||
global
|
||||
1
lib/ModbusMaster/.ruby-version
Normal file
1
lib/ModbusMaster/.ruby-version
Normal file
@@ -0,0 +1 @@
|
||||
2.3.1
|
||||
30
lib/ModbusMaster/.travis.yml
Normal file
30
lib/ModbusMaster/.travis.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
language: python
|
||||
|
||||
python:
|
||||
- 2.7
|
||||
|
||||
sudo: false
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- ~/.platformio
|
||||
|
||||
# update Makefile if target boards added
|
||||
env:
|
||||
- PLATFORMIO_BOARD=uno
|
||||
- PLATFORMIO_BOARD=due
|
||||
- PLATFORMIO_BOARD=huzzah
|
||||
- PLATFORMIO_BOARD=genuino101
|
||||
- PLATFORMIO_BOARD=teensy31
|
||||
|
||||
install:
|
||||
- pip install -U platformio
|
||||
|
||||
before_script:
|
||||
- env
|
||||
- echo $HOME
|
||||
- echo $TRAVIS_BUILD_DIR
|
||||
- ls -al $PWD
|
||||
|
||||
script:
|
||||
- make build
|
||||
141
lib/ModbusMaster/CHANGELOG.md
Normal file
141
lib/ModbusMaster/CHANGELOG.md
Normal file
@@ -0,0 +1,141 @@
|
||||
# ModbusMaster CHANGELOG
|
||||
|
||||
## [v2.0.0](https://github.com/4-20ma/ModbusMaster/tree/v2.0.0) (2016-09-24)
|
||||
[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v1.0.0...v2.0.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- BREAK: Update library to match IDE 1.5 spec v2.1 [\#81](https://github.com/4-20ma/ModbusMaster/pull/81) ([4-20ma](https://github.com/4-20ma))
|
||||
- Use platformio to build multiple boards [\#79](https://github.com/4-20ma/ModbusMaster/pull/79) ([4-20ma](https://github.com/4-20ma))
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Use platformio to build against multiple boards [\#78](https://github.com/4-20ma/ModbusMaster/issues/78)
|
||||
- Add ruby files to .gitignore [\#75](https://github.com/4-20ma/ModbusMaster/issues/75)
|
||||
- Reorder Installation section of README [\#73](https://github.com/4-20ma/ModbusMaster/issues/73)
|
||||
- Update README [\#71](https://github.com/4-20ma/ModbusMaster/issues/71)
|
||||
- Rename HISTORY to CHANGELOG [\#47](https://github.com/4-20ma/ModbusMaster/issues/47)
|
||||
- Update library to match 1.5 specification [\#14](https://github.com/4-20ma/ModbusMaster/issues/14)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Use relative path to examples [\#80](https://github.com/4-20ma/ModbusMaster/pull/80) ([4-20ma](https://github.com/4-20ma))
|
||||
- Add files to .gitignore [\#76](https://github.com/4-20ma/ModbusMaster/pull/76) ([4-20ma](https://github.com/4-20ma))
|
||||
- Reorder installation section of README [\#74](https://github.com/4-20ma/ModbusMaster/pull/74) ([4-20ma](https://github.com/4-20ma))
|
||||
- Update README [\#72](https://github.com/4-20ma/ModbusMaster/pull/72) ([4-20ma](https://github.com/4-20ma))
|
||||
- Automate CHANGELOG generation [\#68](https://github.com/4-20ma/ModbusMaster/pull/68) ([4-20ma](https://github.com/4-20ma))
|
||||
|
||||
## [v1.0.0](https://github.com/4-20ma/ModbusMaster/tree/v1.0.0) (2016-09-12)
|
||||
[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.11.0...v1.0.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Add LICENSE, convert project to Apache 2.0 [\#67](https://github.com/4-20ma/ModbusMaster/pull/67) ([4-20ma](https://github.com/4-20ma))
|
||||
- Add example sketch for half-duplex RS485 [\#66](https://github.com/4-20ma/ModbusMaster/pull/66) ([kintel](https://github.com/kintel))
|
||||
- Add continuous integration testing with Travis CI [\#63](https://github.com/4-20ma/ModbusMaster/pull/63) ([4-20ma](https://github.com/4-20ma))
|
||||
- Disable \_\_MODBUSMASTER\_DEBUG\_\_ mode by default [\#43](https://github.com/4-20ma/ModbusMaster/pull/43) ([kintel](https://github.com/kintel))
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Fix documentation references in ModbusMaster.h, .cpp [\#69](https://github.com/4-20ma/ModbusMaster/issues/69)
|
||||
- Clean up template wording [\#64](https://github.com/4-20ma/ModbusMaster/issues/64)
|
||||
- Add Label section to CONTRIBUTING [\#60](https://github.com/4-20ma/ModbusMaster/issues/60)
|
||||
- Update README contact information [\#58](https://github.com/4-20ma/ModbusMaster/issues/58)
|
||||
- Add continuous integration testing with travis [\#55](https://github.com/4-20ma/ModbusMaster/issues/55)
|
||||
- Add Code of Conduct [\#54](https://github.com/4-20ma/ModbusMaster/issues/54)
|
||||
- Create PULL\_REQUEST\_TEMPLATE [\#49](https://github.com/4-20ma/ModbusMaster/issues/49)
|
||||
- Create ISSUE\_TEMPLATE [\#48](https://github.com/4-20ma/ModbusMaster/issues/48)
|
||||
- Change license to Apache 2.0 [\#45](https://github.com/4-20ma/ModbusMaster/issues/45)
|
||||
- Set \_\_MODBUSMASTER\_DEBUG\_\_ to 0 by default [\#35](https://github.com/4-20ma/ModbusMaster/issues/35)
|
||||
- Pass Stream object instead of integer reference [\#17](https://github.com/4-20ma/ModbusMaster/issues/17)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Add documentation cross-references [\#70](https://github.com/4-20ma/ModbusMaster/pull/70) ([4-20ma](https://github.com/4-20ma))
|
||||
- Clean up ISSUE/PULL\_REQUEST templates [\#65](https://github.com/4-20ma/ModbusMaster/pull/65) ([4-20ma](https://github.com/4-20ma))
|
||||
- Add initial .travis.yml configuration [\#62](https://github.com/4-20ma/ModbusMaster/pull/62) ([4-20ma](https://github.com/4-20ma))
|
||||
- Add label guidance to CONTRIBUTING [\#61](https://github.com/4-20ma/ModbusMaster/pull/61) ([4-20ma](https://github.com/4-20ma))
|
||||
- Update README contact information [\#59](https://github.com/4-20ma/ModbusMaster/pull/59) ([4-20ma](https://github.com/4-20ma))
|
||||
- Add email address to CODE\_OF\_CONDUCT [\#57](https://github.com/4-20ma/ModbusMaster/pull/57) ([4-20ma](https://github.com/4-20ma))
|
||||
- Add CODE\_OF\_CONDUCT [\#56](https://github.com/4-20ma/ModbusMaster/pull/56) ([4-20ma](https://github.com/4-20ma))
|
||||
- Add initial PULL\_REQUEST\_TEMPLATE [\#53](https://github.com/4-20ma/ModbusMaster/pull/53) ([4-20ma](https://github.com/4-20ma))
|
||||
- Clarify instructions in ISSUE\_TEMPLATE [\#52](https://github.com/4-20ma/ModbusMaster/pull/52) ([4-20ma](https://github.com/4-20ma))
|
||||
- Add ISSUE\_TEMPLATE title reqs, separator lines [\#51](https://github.com/4-20ma/ModbusMaster/pull/51) ([4-20ma](https://github.com/4-20ma))
|
||||
- Add initial ISSUE\_TEMPLATE [\#50](https://github.com/4-20ma/ModbusMaster/pull/50) ([4-20ma](https://github.com/4-20ma))
|
||||
- Add preTransmission\(\), postTransmission\(\) for half-duplex [\#44](https://github.com/4-20ma/ModbusMaster/pull/44) ([kintel](https://github.com/kintel))
|
||||
- Add STYLE coding style guide [\#29](https://github.com/4-20ma/ModbusMaster/pull/29) ([4-20ma](https://github.com/4-20ma))
|
||||
|
||||
## [v0.11.0](https://github.com/4-20ma/ModbusMaster/tree/v0.11.0) (2015-05-22)
|
||||
[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.10.3...v0.11.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Update architecture switch [\#28](https://github.com/4-20ma/ModbusMaster/pull/28) ([4-20ma](https://github.com/4-20ma))
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Update architecture switch to match Arduino convention [\#27](https://github.com/4-20ma/ModbusMaster/issues/27)
|
||||
- Request timeout is impatient [\#3](https://github.com/4-20ma/ModbusMaster/issues/3)
|
||||
|
||||
## [v0.10.3](https://github.com/4-20ma/ModbusMaster/tree/v0.10.3) (2015-05-22)
|
||||
[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.10.2...v0.10.3)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Inconsistent Doxygen comments [\#25](https://github.com/4-20ma/ModbusMaster/issues/25)
|
||||
- Replace C macros with inline functions [\#18](https://github.com/4-20ma/ModbusMaster/issues/18)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Adjust doxygen comments to be consistent [\#26](https://github.com/4-20ma/ModbusMaster/pull/26) ([4-20ma](https://github.com/4-20ma))
|
||||
- Replace C macros w/inline functions [\#24](https://github.com/4-20ma/ModbusMaster/pull/24) ([4-20ma](https://github.com/4-20ma))
|
||||
|
||||
## [v0.10.2](https://github.com/4-20ma/ModbusMaster/tree/v0.10.2) (2015-05-22)
|
||||
[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.9.1...v0.10.2)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Implement CRC16 for SAM3X8E microprocessor [\#11](https://github.com/4-20ma/ModbusMaster/pull/11) ([4-20ma](https://github.com/4-20ma))
|
||||
- Add rx flush, change response timeout to 2000 ms [\#10](https://github.com/4-20ma/ModbusMaster/pull/10) ([agprimatic](https://github.com/agprimatic))
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- Fix documentation build error [\#23](https://github.com/4-20ma/ModbusMaster/pull/23) ([4-20ma](https://github.com/4-20ma))
|
||||
- Work around HardwareSerial for SAM3 micro [\#12](https://github.com/4-20ma/ModbusMaster/pull/12) ([4-20ma](https://github.com/4-20ma))
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Update pointers to match C++ convention [\#22](https://github.com/4-20ma/ModbusMaster/pull/22) ([4-20ma](https://github.com/4-20ma))
|
||||
- Rename markdown file extensions [\#21](https://github.com/4-20ma/ModbusMaster/pull/21) ([4-20ma](https://github.com/4-20ma))
|
||||
|
||||
## [v0.9.1](https://github.com/4-20ma/ModbusMaster/tree/v0.9.1) (2013-01-02)
|
||||
[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.9...v0.9.1)
|
||||
|
||||
## [v0.9](https://github.com/4-20ma/ModbusMaster/tree/v0.9) (2011-12-27)
|
||||
[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.8...v0.9)
|
||||
|
||||
## [v0.8](https://github.com/4-20ma/ModbusMaster/tree/v0.8) (2011-11-09)
|
||||
[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.7...v0.8)
|
||||
|
||||
## [v0.7](https://github.com/4-20ma/ModbusMaster/tree/v0.7) (2010-02-10)
|
||||
[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.6...v0.7)
|
||||
|
||||
## [v0.6](https://github.com/4-20ma/ModbusMaster/tree/v0.6) (2010-02-05)
|
||||
[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.5...v0.6)
|
||||
|
||||
## [v0.5](https://github.com/4-20ma/ModbusMaster/tree/v0.5) (2010-01-30)
|
||||
[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.4...v0.5)
|
||||
|
||||
## [v0.4](https://github.com/4-20ma/ModbusMaster/tree/v0.4) (2010-01-30)
|
||||
[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.3...v0.4)
|
||||
|
||||
## [v0.3](https://github.com/4-20ma/ModbusMaster/tree/v0.3) (2010-01-29)
|
||||
[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.2...v0.3)
|
||||
|
||||
## [v0.2](https://github.com/4-20ma/ModbusMaster/tree/v0.2) (2010-01-26)
|
||||
[Full Changelog](https://github.com/4-20ma/ModbusMaster/compare/v0.1...v0.2)
|
||||
|
||||
## [v0.1](https://github.com/4-20ma/ModbusMaster/tree/v0.1) (2010-01-25)
|
||||
|
||||
|
||||
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
|
||||
78
lib/ModbusMaster/CODE_OF_CONDUCT.md
Normal file
78
lib/ModbusMaster/CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||
nationality, personal appearance, race, religion, or sexual identity and
|
||||
orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project owner at 4-20ma@wvfans.net. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Project Maintainers
|
||||
|
||||
- Doc Walker <<4-20ma@wvfans.net>>
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
58
lib/ModbusMaster/CONTRIBUTING.md
Normal file
58
lib/ModbusMaster/CONTRIBUTING.md
Normal file
@@ -0,0 +1,58 @@
|
||||
Contributing
|
||||
============
|
||||
|
||||
- Fork, then clone the repo:
|
||||
````
|
||||
git clone git@github.com:your_username/ModbusMaster.git
|
||||
````
|
||||
|
||||
- Create a topic branch from where you want to base your work
|
||||
- This is usually the master branch
|
||||
- Only target release branches if you are certain your fix must be on that branch
|
||||
- To quickly create a topic branch based on master; `git checkout -b fix/master/my_contribution master`. Please avoid working directly on the `master` branch.
|
||||
|
||||
- Follow the [style guide](https://github.com/4-20ma/ModbusMaster/blob/master/STYLE.md)
|
||||
|
||||
- Test your change
|
||||
|
||||
```` bash
|
||||
$ make
|
||||
````
|
||||
|
||||
Project must build successfully using `make` in order for contribution to be considered.
|
||||
|
||||
- Make commits of logical units
|
||||
- Check for unnecessary whitespace with `git diff --check` before committing
|
||||
- Each commit should represent one atomic change and should stand on its own
|
||||
- Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
|
||||
|
||||
- Push to your fork and [submit a pull request](https://github.com/4-20ma/ModbusMaster/compare/)
|
||||
- [Code of conduct](https://github.com/4-20ma/ModbusMaster/blob/master/CODE_OF_CONDUCT.md)
|
||||
|
||||
### Labels
|
||||
|
||||
Project maintainers assign labels to Issues and Pull Requests (PRs) to categorize, prioritize, and provide status. The following guidelines and conventions are used in this project:
|
||||
|
||||
#### Type
|
||||
|
||||
- `Bug` - existing code does not behave as described in the project documentation; _requires_ clear test case and be _reproducible_ by project maintainer
|
||||
- `Enhancement` - improvement to an existing feature (Issue or Pull Request)
|
||||
- `Feature Requst` - new functionality; _requires_ a well-written, clear user story (Issue)
|
||||
- `Maintenance` - minor administrative change that does not provide enhancement or introduce new feature
|
||||
- `Question` - self-explanatory
|
||||
|
||||
#### Priority
|
||||
|
||||
- `Low` - default priority; new issues generally start here
|
||||
- `Medium` - issues are escalated, depending on severity of the issue
|
||||
- `High` - issues are escalated, depending on severity of the issue
|
||||
- `Critical` - these issues are to be resolved ahead of any other
|
||||
|
||||
#### Status
|
||||
|
||||
- `Abandoned` - issue/PR closed due to inactivity
|
||||
- `Blocked` - issue/PR will not be resolved/merged (some projects label these items as `wontfix`; include explanation in issue/PR)
|
||||
- `In Progress` - issue has been assigned and is actively being addressed; re-label issue `On Hold` with explanation if there will be a significant delay
|
||||
- `Maintainer Review Needed` - last step prior to merge; PR passes continuous integration tests and is able to be cleanly merged - awaiting review for style, code cleanliness, etc.
|
||||
- `On Hold` - implementation delayed; provide explanation in issue/PR
|
||||
- `Pending Contributor Response` - issue/PR closed after 14 days of inactivity (re-label `Abandoned` at closure)
|
||||
30
lib/ModbusMaster/Gemfile
Normal file
30
lib/ModbusMaster/Gemfile
Normal file
@@ -0,0 +1,30 @@
|
||||
# encoding: utf-8
|
||||
# Gemfile style guide derived from:
|
||||
# http://mcdowall.info/posts/gemfile-best-practices-and-discourse/
|
||||
|
||||
# Use `bundle install` after changing this file
|
||||
# `bundle update [gemname]` to force update of gem
|
||||
# `bundle show [gemname]` to see where a bundled gem is installed
|
||||
# `bundle open [gemname]` to edit a bundled gem
|
||||
# `bundle package` to add gem to vendor/cache
|
||||
|
||||
source 'https://rubygems.org'
|
||||
|
||||
|
||||
# place gems sourced from github.com in this section _________________________
|
||||
|
||||
|
||||
# place gems sourced from a project path in this section _____________________
|
||||
|
||||
|
||||
# place general project gems in this section (alphabetical order) ____________
|
||||
gem 'git', '~> 1.3.0' # git management
|
||||
gem 'github_changelog_generator', '~> 1.13.1'
|
||||
gem 'rake', '~> 11.2.2'
|
||||
gem 'version', '~> 1.0.0' # version management gem
|
||||
|
||||
|
||||
# place gems related to test/specs in this section (alphabetical order) ______
|
||||
|
||||
|
||||
# place gems related to development in this section (alphabetical order) _____
|
||||
47
lib/ModbusMaster/Gemfile.lock
Normal file
47
lib/ModbusMaster/Gemfile.lock
Normal file
@@ -0,0 +1,47 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
addressable (2.4.0)
|
||||
colorize (0.8.1)
|
||||
descendants_tracker (0.0.4)
|
||||
thread_safe (~> 0.3, >= 0.3.1)
|
||||
faraday (0.9.2)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
git (1.3.0)
|
||||
github_api (0.14.5)
|
||||
addressable (~> 2.4.0)
|
||||
descendants_tracker (~> 0.0.4)
|
||||
faraday (~> 0.8, < 0.10)
|
||||
hashie (>= 3.4)
|
||||
oauth2 (~> 1.0)
|
||||
github_changelog_generator (1.13.1)
|
||||
colorize (~> 0.7)
|
||||
github_api (~> 0.12)
|
||||
rake (>= 10.0)
|
||||
hashie (3.4.4)
|
||||
jwt (1.5.4)
|
||||
multi_json (1.12.1)
|
||||
multi_xml (0.5.5)
|
||||
multipart-post (2.0.0)
|
||||
oauth2 (1.2.0)
|
||||
faraday (>= 0.8, < 0.10)
|
||||
jwt (~> 1.0)
|
||||
multi_json (~> 1.3)
|
||||
multi_xml (~> 0.5)
|
||||
rack (>= 1.2, < 3)
|
||||
rack (2.0.1)
|
||||
rake (11.2.2)
|
||||
thread_safe (0.3.5)
|
||||
version (1.0.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
git (~> 1.3.0)
|
||||
github_changelog_generator (~> 1.13.1)
|
||||
rake (~> 11.2.2)
|
||||
version (~> 1.0.0)
|
||||
|
||||
BUNDLED WITH
|
||||
1.12.1
|
||||
201
lib/ModbusMaster/LICENSE
Normal file
201
lib/ModbusMaster/LICENSE
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
19
lib/ModbusMaster/Makefile
Normal file
19
lib/ModbusMaster/Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
#-------------------------------------------------------------------- settings
|
||||
FIND := find
|
||||
DIR := examples
|
||||
CRITERIA := \( -name "*.ino" -o -name "*.pde" \)
|
||||
EACH_EXAMPLE := $(FIND) $(DIR) $(CRITERIA) -exec
|
||||
BUILD := platformio ci
|
||||
LIB := src
|
||||
|
||||
#--------------------------------------------------------------------- targets
|
||||
# update .travis.yml if target boards added
|
||||
all: uno due huzzah genuino101 teensy31
|
||||
|
||||
uno due huzzah genuino101 teensy31:
|
||||
PLATFORMIO_BOARD=$@ $(MAKE) build
|
||||
|
||||
build:
|
||||
$(EACH_EXAMPLE) $(BUILD) --board=$(PLATFORMIO_BOARD) --lib=$(LIB) {} \;
|
||||
|
||||
.PHONY: all uno due huzzah genuino101 teensy31 build
|
||||
167
lib/ModbusMaster/README.md
Normal file
167
lib/ModbusMaster/README.md
Normal file
@@ -0,0 +1,167 @@
|
||||
# ModbusMaster
|
||||
[][GitHub release]
|
||||
[][Travis]
|
||||
[][license]
|
||||
[][code of conduct]
|
||||
|
||||
[GitHub release]: https://github.com/4-20ma/ModbusMaster
|
||||
[Travis]: https://travis-ci.org/4-20ma/ModbusMaster
|
||||
[license]: LICENSE
|
||||
[code of conduct]: CODE_OF_CONDUCT.md
|
||||
|
||||
|
||||
## Overview
|
||||
This is an Arduino library for communicating with Modbus slaves over RS232/485 (via RTU protocol).
|
||||
|
||||
|
||||
## Features
|
||||
The following Modbus functions are available:
|
||||
|
||||
Discrete Coils/Flags
|
||||
|
||||
- 0x01 - Read Coils
|
||||
- 0x02 - Read Discrete Inputs
|
||||
- 0x05 - Write Single Coil
|
||||
- 0x0F - Write Multiple Coils
|
||||
|
||||
Registers
|
||||
|
||||
- 0x03 - Read Holding Registers
|
||||
- 0x04 - Read Input Registers
|
||||
- 0x06 - Write Single Register
|
||||
- 0x10 - Write Multiple Registers
|
||||
- 0x16 - Mask Write Register
|
||||
- 0x17 - Read Write Multiple Registers
|
||||
|
||||
Both full-duplex and half-duplex RS232/485 transceivers are supported. Callback functions are provided to toggle Data Enable (DE) and Receiver Enable (/RE) pins.
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
#### Library Manager
|
||||
Install the library into your Arduino IDE using the Library Manager (available from IDE version 1.6.2). Open the IDE and click Sketch > Include Library > Manage Libraries…
|
||||
|
||||
Scroll or search for `ModbusMaster`, then select the version of the library you want to install. Quit/re-launch the IDE to refresh the list; new versions are automatically added to the list, once released on GitHub.
|
||||
|
||||
Refer to Arduino Tutorials > Libraries [Using the Library Manager](https://www.arduino.cc/en/Guide/Libraries#toc3).
|
||||
|
||||
#### Zip Library
|
||||
Refer to Arduino Tutorials > Libraries [Importing a .zip Library](https://www.arduino.cc/en/Guide/Libraries#toc4).
|
||||
|
||||
#### Manual
|
||||
Refer to Arduino Tutorials > Libraries [Manual Installation](https://www.arduino.cc/en/Guide/Libraries#toc5).
|
||||
|
||||
|
||||
## Hardware
|
||||
This library has been tested with an Arduino [Duemilanove](http://www.arduino.cc/en/Main/ArduinoBoardDuemilanove), PHOENIX CONTACT [nanoLine](https://www.phoenixcontact.com/online/portal/us?1dmy&urile=wcm%3apath%3a/usen/web/main/products/subcategory_pages/standard_logic_modules_p-21-03-03/3329dd38-7c6a-46e1-8260-b9208235d6fe/3329dd38-7c6a-46e1-8260-b9208235d6fe) controller, connected via RS485 using a Maxim [MAX488EPA](http://www.maxim-ic.com/quick_view2.cfm/qv_pk/1111) transceiver.
|
||||
|
||||
|
||||
## Caveats
|
||||
Conforms to Arduino IDE 1.5 Library Specification v2.1 which requires Arduino IDE >= 1.5.
|
||||
|
||||
Arduinos prior to the Mega have one serial port which must be connected to USB (FTDI) for uploading sketches and to the RS232/485 device/network for running sketches. You will need to disconnect pin 0 (RX) while uploading sketches. After a successful upload, you can reconnect pin 0.
|
||||
|
||||
|
||||
## Support
|
||||
Please [submit an issue](https://github.com/4-20ma/ModbusMaster/issues) for all questions, bug reports, and feature requests. Email requests will be politely redirected to the issue tracker so others may contribute to the discussion and requestors get a more timely response.
|
||||
|
||||
|
||||
## Example
|
||||
The library contains a few sketches that demonstrate use of the `ModbusMaster` library. You can find these in the [examples](https://github.com/4-20ma/ModbusMaster/tree/master/examples) folder.
|
||||
|
||||
``` cpp
|
||||
/*
|
||||
|
||||
Basic.pde - example using ModbusMaster library
|
||||
|
||||
Library:: ModbusMaster
|
||||
Author:: Doc Walker <4-20ma@wvfans.net>
|
||||
|
||||
Copyright:: 2009-2016 Doc Walker
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
#include <ModbusMaster.h>
|
||||
|
||||
|
||||
// instantiate ModbusMaster object
|
||||
ModbusMaster node;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
// use Serial (port 0); initialize Modbus communication baud rate
|
||||
Serial.begin(19200);
|
||||
|
||||
// communicate with Modbus slave ID 2 over Serial (port 0)
|
||||
node.begin(2, Serial);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
static uint32_t i;
|
||||
uint8_t j, result;
|
||||
uint16_t data[6];
|
||||
|
||||
i++;
|
||||
|
||||
// set word 0 of TX buffer to least-significant word of counter (bits 15..0)
|
||||
node.setTransmitBuffer(0, lowWord(i));
|
||||
|
||||
// set word 1 of TX buffer to most-significant word of counter (bits 31..16)
|
||||
node.setTransmitBuffer(1, highWord(i));
|
||||
|
||||
// slave: write TX buffer to (2) 16-bit registers starting at register 0
|
||||
result = node.writeMultipleRegisters(0, 2);
|
||||
|
||||
// slave: read (6) 16-bit registers starting at register 2 to RX buffer
|
||||
result = node.readHoldingRegisters(2, 6);
|
||||
|
||||
// do something with data if read is successful
|
||||
if (result == node.ku8MBSuccess)
|
||||
{
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
data[j] = node.getResponseBuffer(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
_Project inspired by [Arduino Modbus Master](http://sites.google.com/site/jpmzometa/arduino-mbrt/arduino-modbus-master)._
|
||||
|
||||
|
||||
## License & Authors
|
||||
|
||||
- Author:: Doc Walker ([4-20ma@wvfans.net](mailto:4-20ma@wvfans.net))
|
||||
- Author:: Ag Primatic ([agprimatic@gmail.com](mailto:agprimatic@gmail.com))
|
||||
- Author:: Marius Kintel ([marius@kintel.net](mailto:marius@kintel.net))
|
||||
|
||||
```
|
||||
Copyright:: 2009-2016 Doc Walker
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
```
|
||||
218
lib/ModbusMaster/Rakefile
Normal file
218
lib/ModbusMaster/Rakefile
Normal file
@@ -0,0 +1,218 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Copyright:: 2009-2016 Doc Walker
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
require 'git'
|
||||
require 'github_changelog_generator/task'
|
||||
require 'rake'
|
||||
require 'rubygems'
|
||||
require 'rake/version_task' # gem install version
|
||||
require 'version'
|
||||
|
||||
# requires additional packages on MacOS (including Homebrew):
|
||||
# $ /usr/bin/ruby -e "$(curl -fsSL \
|
||||
# https://raw.githubusercontent.com/Homebrew/install/master/install)"
|
||||
# $ brew install doxygen # generates documentation from source code
|
||||
# $ brew cask install mactex # MacTeX
|
||||
|
||||
Rake::VersionTask.new do |task|
|
||||
# prevent auto-commit on version bump
|
||||
task.with_git = false
|
||||
end
|
||||
|
||||
# adjust as appropriate
|
||||
CWD = File.expand_path(File.dirname(__FILE__))
|
||||
DOXYFILE = 'Doxyfile'
|
||||
GITHUB_USERNAME = '4-20ma'
|
||||
GITHUB_REPO = 'ModbusMaster'
|
||||
HEADER_FILE = "#{GITHUB_REPO}.h"
|
||||
CHANGELOG_FILE = 'CHANGELOG.md'
|
||||
PROPERTIES_FILE = 'library.properties'
|
||||
VERSION_FILE = Version.version_file('').basename.to_s
|
||||
|
||||
|
||||
task :default => :info
|
||||
|
||||
desc 'Display instructions for public release'
|
||||
task :info do
|
||||
puts <<-EOF.gsub(/^\s{2}/, '')
|
||||
|
||||
Instructions for public release
|
||||
|
||||
- Update version, as appropriate:
|
||||
|
||||
$ rake version:bump # or
|
||||
$ rake version:bump:minor # or
|
||||
$ rake version:bump:major # or
|
||||
edit 'VERSION' file directly
|
||||
|
||||
- Prepare release date, 'CHANGELOG.md' file, documentation:
|
||||
|
||||
$ rake prepare
|
||||
|
||||
- Review changes to 'CHANGELOG.md' file
|
||||
This file is assembled using git commit messages; review for completeness.
|
||||
|
||||
- Review html documentation files
|
||||
These files are assembled using source code Doxygen tags; review for
|
||||
for completeness.
|
||||
|
||||
- Add & commit source files, tag, push to origin/master;
|
||||
add & commit documentation files, push to origin/gh-pages:
|
||||
|
||||
$ rake release
|
||||
|
||||
EOF
|
||||
end # task :info
|
||||
|
||||
|
||||
desc "Prepare #{CHANGELOG_FILE} for release"
|
||||
task :prepare => 'prepare:default'
|
||||
|
||||
namespace :prepare do
|
||||
task :default => [
|
||||
:release_date,
|
||||
:library_properties,
|
||||
:changelog,
|
||||
:documentation
|
||||
]
|
||||
|
||||
desc 'Prepare documentation'
|
||||
task :documentation do
|
||||
version = Version.current.to_s
|
||||
|
||||
# update parameters in Doxyfile
|
||||
file = File.join(CWD, 'doc', DOXYFILE)
|
||||
|
||||
contents = IO.read(file)
|
||||
contents.sub!(/(^PROJECT_NUMBER\s*=)(.*)$/) do |match|
|
||||
"#{$1} v#{version}"
|
||||
end # contents.sub!(...)
|
||||
IO.write(file, contents)
|
||||
|
||||
# chdir to doc/ and call doxygen to update documentation
|
||||
Dir.chdir(to = File.join(CWD, 'doc'))
|
||||
system('doxygen', DOXYFILE)
|
||||
|
||||
# chdir to doc/latex and call doxygen to update documentation
|
||||
Dir.chdir(from = File.join(CWD, 'doc', 'latex'))
|
||||
system('make')
|
||||
|
||||
# move/rename file to 'extras/GITHUB_REPO reference-x.y.pdf'
|
||||
to = File.join(CWD, 'extras')
|
||||
FileUtils.mv(File.join(from, 'refman.pdf'),
|
||||
File.join(to, "#{GITHUB_REPO} reference-#{version}.pdf"))
|
||||
end # task :documentation
|
||||
|
||||
desc 'Prepare release history'
|
||||
GitHubChangelogGenerator::RakeTask.new(:changelog) do |config|
|
||||
config.add_issues_wo_labels = false
|
||||
config.add_pr_wo_labels = false
|
||||
config.enhancement_labels = [
|
||||
'Type: Enhancement'
|
||||
]
|
||||
config.bug_labels = ['Type: Bug']
|
||||
config.exclude_labels = ['Type: Question']
|
||||
config.header = '# ModbusMaster CHANGELOG'
|
||||
config.include_labels = [
|
||||
'Type: Bug',
|
||||
'Type: Enhancement',
|
||||
'Type: Feature Request',
|
||||
'Type: Maintenance'
|
||||
]
|
||||
# config.since_tag = '0.1.0'
|
||||
config.future_release = "v#{Version.current.to_s}"
|
||||
config.user = GITHUB_USERNAME
|
||||
config.project = GITHUB_REPO
|
||||
end # GitHubChangelogGenerator::RakeTask.new
|
||||
|
||||
desc 'Update version in library properties file'
|
||||
task :library_properties do
|
||||
version = Version.current.to_s
|
||||
|
||||
file = File.join(CWD, PROPERTIES_FILE)
|
||||
|
||||
contents = IO.read(file)
|
||||
contents.sub!(/(version=\s*)(.*)$/) do |match|
|
||||
"#{$1}#{version}"
|
||||
end # contents.sub!(...)
|
||||
IO.write(file, contents)
|
||||
end # task :library_properties
|
||||
|
||||
desc 'Update release date in header file'
|
||||
task :release_date do
|
||||
file = File.join(CWD, 'src', HEADER_FILE)
|
||||
|
||||
contents = IO.read(file)
|
||||
contents.sub!(/(\\date\s*)(.*)$/) do |match|
|
||||
"#{$1}#{Time.now.strftime('%-d %b %Y')}"
|
||||
end # contents.sub!(...)
|
||||
IO.write(file, contents)
|
||||
end # task :release_date
|
||||
|
||||
end # namespace :prepare
|
||||
|
||||
|
||||
desc 'Release source & documentation'
|
||||
task :release => 'release:default'
|
||||
|
||||
namespace :release do
|
||||
task :default => [:source, :documentation]
|
||||
|
||||
desc 'Commit documentation changes related to version bump'
|
||||
task :documentation do
|
||||
version = Version.current.to_s
|
||||
cwd = File.expand_path(File.join(File.dirname(__FILE__), 'doc', 'html'))
|
||||
g = Git.open(cwd)
|
||||
|
||||
# `git add .`
|
||||
g.add
|
||||
|
||||
# remove each deleted item
|
||||
g.status.deleted.each do |item|
|
||||
g.remove(item[0])
|
||||
end # g.status.deleted.each
|
||||
|
||||
# commit changes if items added, changed, or deleted
|
||||
if g.status.added.size > 0 || g.status.changed.size > 0 ||
|
||||
g.status.deleted.size > 0 then
|
||||
message = "Update documentation for v#{version}"
|
||||
puts g.commit(message)
|
||||
else
|
||||
puts "No changes to commit v#{version}"
|
||||
end # if g.status.added.size > 0 || g.status.changed.size > 0...
|
||||
|
||||
g.push('origin', 'gh-pages')
|
||||
end # task :documentation
|
||||
|
||||
desc 'Commit source changes related to version bump'
|
||||
task :source do
|
||||
version = Version.current.to_s
|
||||
`git add \
|
||||
doc/#{DOXYFILE} \
|
||||
"extras/#{GITHUB_REPO} reference-#{version}.pdf" \
|
||||
src/#{HEADER_FILE} \
|
||||
#{CHANGELOG_FILE} \
|
||||
#{PROPERTIES_FILE} \
|
||||
#{VERSION_FILE} \
|
||||
`
|
||||
`git commit -m 'Version bump to v#{version}'`
|
||||
`git tag -a -f -m 'Version v#{version}' v#{version}`
|
||||
`git push origin master`
|
||||
`git push --tags`
|
||||
end # task :source
|
||||
|
||||
end # namespace :release
|
||||
372
lib/ModbusMaster/STYLE.md
Normal file
372
lib/ModbusMaster/STYLE.md
Normal file
@@ -0,0 +1,372 @@
|
||||
ModbusMaster Style Guide
|
||||
========================
|
||||
|
||||
The following references provide sound guidance for writing C/C++ code for the Arduino platform.
|
||||
|
||||
- [Arduino API Style Guide (AASG)](http://www.arduino.cc/en/Reference/APIStyleGuide)
|
||||
- [Bjarne Stroustrup's C++ Style Guide](http://www.stroustrup.com/bs_faq2.html)
|
||||
- [JSF Air Vehicle C++ Coding Standards (JSFAV)](http://www.stroustrup.com/JSF-AV-rules.pdf)
|
||||
|
||||
Opinions about style and generally accepted usage patterns may vary widely. I've carefully chosen a few key items to emphasize and enforce for this library in order to promote readability, usability, and safe coding practices. **Pull requests will follow these guidelines in order to be considered**.
|
||||
|
||||
|
||||
General \[AASG\]
|
||||
-------
|
||||
|
||||
Use the established Arduino core libraries and styles.
|
||||
|
||||
- Use `read()` to read inputs, and `write()` to write to outputs, e.g. `digitalRead()`, `analogWrite()`, etc.
|
||||
- Use the `Stream.h` and `Print.h` libraries when dealing with byte streams. If it’s not appropriate, at least try to use its API as a model. For more on this, see below.
|
||||
- For network applications, use the Client and Server libraries as the basis.
|
||||
- Use `begin()` to initialize a library instance, usually with some settings. Use `end()` to stop it.
|
||||
- Use camelCase function names, not underscore. For example, `analogRead`, not `analog_read`. Or `myNewFunction`, not `my_new_function`. We've adopted this from Processing.org for readability's sake. Refer to AV Rule 45 and AV Rule 51.
|
||||
- When using serial communication, allow the user to specify any `Stream` object, rather than hard-coding `Serial`. This will make the library compatible with all serial ports on Mega and the Due, and can also use alternate interfaces like `SoftwareSerial`. The `Stream` object can be passed to the library's constructor or to a `begin()` function (as a reference, not a pointer). See Firmata 2.3 or XBee 0.4 for examples of each approach.
|
||||
|
||||
|
||||
Rules \[JSFAV 4.2\]
|
||||
-----
|
||||
|
||||
#### Should, Will, and Shall Rules
|
||||
|
||||
There are three types of rules: **should**, **will**, and **shall** rules. Each rule contains either a **"should"**, **"will"** or a **"shall"** in bold letters indicating its type.
|
||||
|
||||
- **Should** rules are advisory rules. They strongly suggest the recommended way of doing things.
|
||||
- **Will** rules are intended to be mandatory requirements. It is expected that they will be followed, but they do not require verification. They are limited to non-safety-critical requirements that cannot be easily verified (e.g., naming conventions).
|
||||
- **Shall** rules are mandatory requirements. They must be followed and they require verification (either automatic or manual).
|
||||
|
||||
|
||||
Pre-Processing Directives \[JSFAV 4.6\]
|
||||
-------------------------
|
||||
Since the pre-processor knows nothing about C++, it should not be used to do what can otherwise be done in C++.
|
||||
|
||||
- AV Rule 26
|
||||
|
||||
Only the following pre-processor directives shall be used:
|
||||
|
||||
1. `#ifndef`
|
||||
1. `#define`
|
||||
1. `#endif`
|
||||
1. `#include`
|
||||
|
||||
**Rationale**: Limit the use of the pre-processor to those cases where it is necessary.
|
||||
|
||||
#### \#ifndef and \#endif Pre-Processing Directives
|
||||
|
||||
- AV Rule 27
|
||||
|
||||
`#ifndef`, `#define` and `#endif` **will** be used to prevent multiple inclusions of the same header file. Other techniques to prevent the multiple inclusions of header files **will not** be used.
|
||||
|
||||
**Rationale**: Eliminate multiple inclusions of the same header file in a standard way.
|
||||
|
||||
- AV Rule 28
|
||||
|
||||
The `#ifndef` and `#endif` pre-processor directives **will** only be used as defined in AV Rule 27 to prevent multiple inclusions of the same header file.
|
||||
|
||||
**Rationale**: Conditional code compilation should be kept to a minimum as it can significantly obscure testing and maintenance efforts.
|
||||
|
||||
#### \#define Pre-Processing Directive
|
||||
|
||||
- AV Rule 29
|
||||
|
||||
The `#define` pre-processor directive **shall not** be used to create inline macros. Inline functions **shall** be used instead.
|
||||
|
||||
**Rationale**: Inline functions do not require text substitutions and behave well when called with arguments (e.g. type checking is performed).
|
||||
|
||||
- AV Rule 30
|
||||
|
||||
The `#define` pre-processor directive **shall not** be used to define constant values. Instead, the `const` qualifier shall be applied to variable declarations to specify constant values.
|
||||
|
||||
**Rationale**: `const` variables follow scope rules, are subject to type checking and do not require text substitutions (which can be confusing or misleading).
|
||||
|
||||
- AV Rule 31
|
||||
|
||||
The `#define` pre-processor directive **will** only be used as part of the technique to prevent multiple inclusions of the same header file.
|
||||
|
||||
**Rationale**: `#define` can be used to specify conditional compilation (AV Rule 27 and AV Rule 28), inline macros (AV Rule 29) and constants (AV Rule 30). This rule specifies that the only allowable use of `#define` is to prevent multiple includes of the same header file (AV Rule 27).
|
||||
|
||||
#### \#include Pre-Processing Directive
|
||||
|
||||
- AV Rule 32
|
||||
|
||||
The `#include` pre-processor directive **will** only be used to include header (\*.h) files.
|
||||
|
||||
**Rationale**: Clarity. The only files included in a .cpp file should be the relevant header (\*.h) files.
|
||||
|
||||
|
||||
Header Files \[JSFAV 4.7\]
|
||||
------------
|
||||
|
||||
- AV Rule 33
|
||||
|
||||
The `#include` directive **shall** use the `<filename.h>` notation to include header files.
|
||||
|
||||
**Rationale**: The include form `"filename.h"` is typically used to include local header files. However, due to the unfortunate divergence in vendor implementations, only the `<filename.h>` form will be used.
|
||||
|
||||
- AV Rule 35
|
||||
|
||||
A header file **will** contain a mechanism that prevents multiple inclusions of itself.
|
||||
|
||||
**Rationale**: Avoid accidental header file recursion. Note AV Rule 27 specifies the mechanism by which multiple inclusions are to be eliminated whereas this rule (AV Rule 35) specifies that each header file must use that mechanism.
|
||||
|
||||
- AV Rule 37
|
||||
|
||||
Header (include) files **should** include only those header files that are required for them to successfully compile. Files that are only used by the associated .cpp file should be placed in the .cpp file—not the .h file.
|
||||
|
||||
**Rationale**: The `#include` statements in a header file define the dependencies of the file. Fewer dependencies imply looser couplings and hence a smaller ripple-effect when the header file is required to change.
|
||||
|
||||
|
||||
Style \[JSFAV 4.9\]
|
||||
-----
|
||||
Imposing constraints on the format of syntactic elements makes source code easier to read due to consistency in form and appearance.
|
||||
|
||||
- AV Rule 41 (modified)
|
||||
|
||||
Source lines **will** be kept to a length of 78 characters or less.
|
||||
|
||||
**Rationale**: Readability and style. Very long source lines can be difficult to read and understand.
|
||||
|
||||
- AV Rule 42
|
||||
|
||||
Each expression-statement **will** be on a separate line.
|
||||
|
||||
**Rationale**: Simplicity, readability, and style.
|
||||
|
||||
- AV Rule 43 (modified)
|
||||
|
||||
Tabs **will** be avoided.
|
||||
|
||||
**Rationale**: Tabs are interpreted differently across various editors and printers.
|
||||
|
||||
- AV Rule 44
|
||||
|
||||
All indentations **will** be at least two spaces and be consistent within the same source file.
|
||||
|
||||
**Rationale**: Readability and style.
|
||||
|
||||
#### Naming Identifiers
|
||||
|
||||
The choice of identifier names should:
|
||||
|
||||
- Suggest the usage of the identifier.
|
||||
- Consist of a descriptive name that is short yet meaningful.
|
||||
- Be long enough to avoid name conflicts, but not excessive in length.
|
||||
- Include abbreviations that are generally accepted.
|
||||
|
||||
Note: In general, the above guidelines should be followed. However, conventional usage of simple identifiers (i, x, y, p, etc.) in small scopes can lead to cleaner code and will therefore be permitted.
|
||||
|
||||
Additionally, the term ‘word’ in the following naming convention rules may be used to refer to a word, an acronym, an abbreviation, or a number.
|
||||
|
||||
- AV Rule 45
|
||||
|
||||
All words in an identifier **will** be separated by the '\_' character.
|
||||
|
||||
**Exception**: Function names follow the camelCase convention according to the Arduino API Style Guide. Refer to AV Rule 51.
|
||||
|
||||
**Rationale**: Readability and Style.
|
||||
|
||||
- AV Rule 47 (modified)
|
||||
|
||||
Identifiers **should not** begin with the underscore character '\_'.
|
||||
|
||||
**Exception**: Currently, private members of the `ModbusMaster` class begin with '\_'.
|
||||
|
||||
**Rationale**: '\_' is often used as the first character in the name of library functions (e.g. `_main`, `_exit`, etc.) In order to avoid name collisions, identifiers should not begin with '\_'.
|
||||
|
||||
- AV Rule 49
|
||||
|
||||
All acronyms in an identifier **will** be composed of uppercase letters.
|
||||
|
||||
Note: An acronym will always be in uppercase, even if the acronym is located in a portion of an identifier that is specified to be lowercase by other rules.
|
||||
|
||||
**Rationale**: Readability.
|
||||
|
||||
- AV Rule 50
|
||||
|
||||
The first word of the name of a class, structure, namespace, enumeration, or type created with typedef **will** begin with an uppercase letter. All others letters will be lowercase.
|
||||
|
||||
**Rationale**: Style.
|
||||
|
||||
**Exception**: The first letter of a typedef name may be in lowercase in order to conform to a standard library interface or when used as a replacement for fundamental types.
|
||||
|
||||
- AV Rule 51 (modified)
|
||||
|
||||
All letters contained in *function* names **will** be composed of a mix of lowercase and uppercase letters in camelCase format (e.g. first letter of first word is lowercase and first letter of each subsequent word is uppercase). This is to maintain consistency with the Arduion API Style Guide. Refer to AV Rule 45.
|
||||
|
||||
All letters contained in *variable* names **will** be composed entirely of lowercase letters.
|
||||
|
||||
**Rationale**: Style.
|
||||
|
||||
- AV Rule 52
|
||||
|
||||
Identifiers for constant and enumerator values **shall** be lowercase.
|
||||
|
||||
**Rationale**: Although it is an accepted convention to use uppercase letters for constants and enumerators, it is possible for third party libraries to replace constant/enumerator names as part of the macro substitution process (macros are also typically represented with uppercase letters).
|
||||
|
||||
#### Classes
|
||||
|
||||
- AV Rule 57
|
||||
|
||||
The public, protected, and private sections of a class **will** be declared in that order (the public section is declared before the protected section which is declared before the private section).
|
||||
|
||||
**Rationale**: By placing the public section first, everything that is of interest to a user is gathered in the beginning of the class definition. The protected section may be of interest to designers when considering inheriting from the class. The private section contains details that should be of the least general interest.
|
||||
|
||||
#### Functions
|
||||
|
||||
- AV Rule 58
|
||||
|
||||
When declaring and defining functions with more than two parameters, the leading parenthesis and the first argument **will** be written on the same line as the function name. Each additional argument will be written on a separate line (with the closing parenthesis directly after the last argument).
|
||||
|
||||
**Rationale**: Readability and style.
|
||||
|
||||
#### Blocks
|
||||
|
||||
- AV Rule 59
|
||||
|
||||
The statements forming the body of an `if`, `else if`, `else`, `while`, `do...while` or `for` statement **shall** always be enclosed in braces, even if the braces form an empty block.
|
||||
|
||||
**Rationale**: Readability. It can be difficult to see ';' when it appears by itself.
|
||||
|
||||
- AV Rule 60
|
||||
|
||||
Braces ('{}') which enclose a block will be placed in the same column, on separate lines directly before and after the block.
|
||||
|
||||
**Example**:
|
||||
```
|
||||
if (var_name == true)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
- AV Rule 61
|
||||
|
||||
Braces ('{}') which enclose a block **will** have nothing else on the line except comments (if necessary).
|
||||
|
||||
#### Pointers and References
|
||||
|
||||
- AV Rule 62
|
||||
|
||||
The dereference operator '\*' and the address-of operator '&' **will** be directly connected with the type-specifier.
|
||||
|
||||
**Rationale**: The `int32* p;` form emphasizes type over syntax while the `int32 *p;` form emphasizes syntax over type. Although both forms are equally valid C++, the heavy emphasis on types in C++ suggests that `int32* p;` is the preferable form.
|
||||
|
||||
**Examples**:
|
||||
```
|
||||
int32* p; // correct
|
||||
int32 *p; // incorrect
|
||||
int32* p, q; // probable error
|
||||
```
|
||||
|
||||
#### Miscellaneous
|
||||
|
||||
- AV Rule 63
|
||||
|
||||
Spaces **will not** be used around '.' or '->', nor between unary operators and operands.
|
||||
|
||||
**Rationale**: Readability and style.
|
||||
|
||||
|
||||
Classes \[JSFAV 4.10\]
|
||||
-------
|
||||
|
||||
#### const Member Functions
|
||||
|
||||
- AV Rule 69
|
||||
|
||||
A member function that does not affect the state of an object (its instance variables) **will** be declared `const`.
|
||||
|
||||
Member functions should be `const` by default. Only when there is a clear, explicit reason should the `const` modifier on member functions be omitted.
|
||||
|
||||
**Rationale**: Declaring a member function `const` is a means of ensuring that objects will not be modified when they should not. Furthermore, C++ allows member functions to be overloaded on their `const`-ness.
|
||||
|
||||
|
||||
Initialization \[JSFAV 4.16\]
|
||||
--------------
|
||||
|
||||
- AV Rule 142
|
||||
|
||||
All variables **shall** be initialized before use.
|
||||
|
||||
**Rationale**: Prevent the use of variables before they have been properly initialized.
|
||||
|
||||
- AV Rule 143
|
||||
|
||||
Variables **will not** be introduced until they can be initialized with meaningful values.
|
||||
|
||||
**Rationale**: Prevent clients from accessing variables without meaningful values.
|
||||
|
||||
|
||||
Constants \[JSFAV 4.18\]
|
||||
---------
|
||||
|
||||
- AV Rule 149
|
||||
|
||||
Octal constants (other than zero) **shall not** be used.
|
||||
|
||||
**Rationale**: Any integer constant beginning with a zero ('0') is defined by the C++ standard to be an octal constant. Due to the confusion this causes, octal constants should be avoided.
|
||||
|
||||
Note: Hexadecimal numbers and zero (which is also an octal constant) are allowed.
|
||||
|
||||
- AV Rule 150
|
||||
|
||||
Hexadecimal constants **will** be represented using all uppercase letters.
|
||||
|
||||
|
||||
Variables \[JSFAV 4.19\]
|
||||
---------
|
||||
|
||||
- AV Rule 152
|
||||
|
||||
Multiple variable declarations **shall not** be allowed on the same line.
|
||||
|
||||
**Rationale**: Increases readability and prevents confusion (see also AV Rule 62).
|
||||
|
||||
**Examples**:
|
||||
```
|
||||
int32 p; // correct
|
||||
int32 q; // correct
|
||||
int32 p, q; // probable error
|
||||
int32 first_button_on_the_left_box, i; // incorrect; easy to overlook i
|
||||
```
|
||||
|
||||
|
||||
Flow Control Structures \[JSFAV 4.24\]
|
||||
-----------------------
|
||||
|
||||
- AV Rule 188
|
||||
|
||||
Labels **will** not be used, except in switch statements.
|
||||
|
||||
**Rationale**: Labels are typically either used in switch statements or are as the targets for goto statements. See exception given in AV Rule 189.
|
||||
|
||||
- AV Rule 189
|
||||
|
||||
The `goto` statement **shall not** be used.
|
||||
|
||||
**Rationale**: Frequent use of the `goto` statement tends to lead to code that is both difficult to read and maintain.
|
||||
|
||||
- AV Rule 190
|
||||
|
||||
The `continue` statement **shall not** be used.
|
||||
|
||||
- AV Rule 191
|
||||
|
||||
The `break` statement **shall not** be used (except to terminate the cases of a switch statement).
|
||||
|
||||
**Exception**: The `break` statement may be used to "break" out of a single loop provided the alternative would obscure or otherwise significantly complicate the control logic.
|
||||
|
||||
- AV Rule 192
|
||||
|
||||
All `if`, `else if` constructs **will** contain either a final `else` clause or a comment indicating why a final `else` clause is not necessary.
|
||||
|
||||
**Rationale**: Provide a defensive strategy to ensure that all cases are handled by an `else if` series.
|
||||
|
||||
Note: This rule only applies when an `if` statement is followed by one or more `else if`’s.
|
||||
|
||||
- AV Rule 193
|
||||
|
||||
Every non-empty `case` clause in a `switch` statement **shall** be terminated with a `break` statement.
|
||||
|
||||
**Rationale**: Eliminates potentially confusing behavior since execution will fall through to the code of the next `case` clause if a `break` statement does not terminate the previous `case` clause.
|
||||
1
lib/ModbusMaster/VERSION
Normal file
1
lib/ModbusMaster/VERSION
Normal file
@@ -0,0 +1 @@
|
||||
2.0.1
|
||||
69
lib/ModbusMaster/examples/Basic/Basic.pde
Normal file
69
lib/ModbusMaster/examples/Basic/Basic.pde
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
|
||||
Basic.pde - example using ModbusMaster library
|
||||
|
||||
Library:: ModbusMaster
|
||||
Author:: Doc Walker <4-20ma@wvfans.net>
|
||||
|
||||
Copyright:: 2009-2016 Doc Walker
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
#include <ModbusMaster.h>
|
||||
|
||||
|
||||
// instantiate ModbusMaster object
|
||||
ModbusMaster node;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
// use Serial (port 0); initialize Modbus communication baud rate
|
||||
Serial.begin(19200);
|
||||
|
||||
// communicate with Modbus slave ID 2 over Serial (port 0)
|
||||
node.begin(2, Serial);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
static uint32_t i;
|
||||
uint8_t j, result;
|
||||
uint16_t data[6];
|
||||
|
||||
i++;
|
||||
|
||||
// set word 0 of TX buffer to least-significant word of counter (bits 15..0)
|
||||
node.setTransmitBuffer(0, lowWord(i));
|
||||
|
||||
// set word 1 of TX buffer to most-significant word of counter (bits 31..16)
|
||||
node.setTransmitBuffer(1, highWord(i));
|
||||
|
||||
// slave: write TX buffer to (2) 16-bit registers starting at register 0
|
||||
result = node.writeMultipleRegisters(0, 2);
|
||||
|
||||
// slave: read (6) 16-bit registers starting at register 2 to RX buffer
|
||||
result = node.readHoldingRegisters(2, 6);
|
||||
|
||||
// do something with data if read is successful
|
||||
if (result == node.ku8MBSuccess)
|
||||
{
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
data[j] = node.getResponseBuffer(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
|
||||
PhoenixContact_nanoLC.pde - example using ModbusMaster library
|
||||
to communicate with PHOENIX CONTACT nanoLine controller.
|
||||
|
||||
Library:: ModbusMaster
|
||||
Author:: Doc Walker <4-20ma@wvfans.net>
|
||||
|
||||
Copyright:: 2009-2016 Doc Walker
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
#include <ModbusMaster.h>
|
||||
|
||||
// discrete coils
|
||||
#define NANO_DO(n) (0x0000 + n) ///< returns nanoLC discrete output address
|
||||
#define NANO_FLAG(n) (0x1000 + n) ///< returns nanoLC flag address
|
||||
|
||||
// discrete inputs
|
||||
#define NANO_DI(n) (0x0000 + n) ///< returns nanoLC discrete input address
|
||||
|
||||
// analog holding registers
|
||||
#define NANO_REG(n) (0x0000 + 2 * n) ///< returns nanoLC holding register address
|
||||
#define NANO_AO(n) (0x1000 + 2 * n) ///< returns nanoLC analog output address
|
||||
#define NANO_TCP(n) (0x2000 + 2 * n) ///< returns nanoLC timer/counter preset address
|
||||
#define NANO_OTP(n) (0x3000 + 2 * n) ///< returns nanoLC discrete output preset address
|
||||
#define NANO_HSP(n) (0x4000 + 2 * n) ///< returns nanoLC high-speed counter preset address
|
||||
#define NANO_TCA(n) (0x5000 + 2 * n) ///< returns nanoLC timer/counter accumulator address
|
||||
#define NANO_OTA(n) (0x6000 + 2 * n) ///< returns nanoLC discrete output accumulator address
|
||||
#define NANO_HSA(n) (0x7000 + 2 * n) ///< returns nanoLC high-speed counter accumulator address
|
||||
|
||||
// analog input registers
|
||||
#define NANO_AI(n) (0x0000 + 2 * n) ///< returns nanoLC analog input address
|
||||
|
||||
|
||||
// instantiate ModbusMaster object
|
||||
ModbusMaster nanoLC;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
// use Serial (port 0); initialize Modbus communication baud rate
|
||||
Serial.begin(19200);
|
||||
|
||||
// communicate with Modbus slave ID 1 over Serial (port 0)
|
||||
nanoLC.begin(1, Serial);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
static uint32_t u32ShiftRegister;
|
||||
static uint32_t i;
|
||||
uint8_t u8Status;
|
||||
|
||||
u32ShiftRegister = ((u32ShiftRegister < 0x01000000) ? (u32ShiftRegister << 4) : 1);
|
||||
if (u32ShiftRegister == 0) u32ShiftRegister = 1;
|
||||
i++;
|
||||
|
||||
// set word 0 of TX buffer to least-significant word of u32ShiftRegister (bits 15..0)
|
||||
nanoLC.setTransmitBuffer(0, lowWord(u32ShiftRegister));
|
||||
|
||||
// set word 1 of TX buffer to most-significant word of u32ShiftRegister (bits 31..16)
|
||||
nanoLC.setTransmitBuffer(1, highWord(u32ShiftRegister));
|
||||
|
||||
// set word 2 of TX buffer to least-significant word of i (bits 15..0)
|
||||
nanoLC.setTransmitBuffer(2, lowWord(i));
|
||||
|
||||
// set word 3 of TX buffer to most-significant word of i (bits 31..16)
|
||||
nanoLC.setTransmitBuffer(3, highWord(i));
|
||||
|
||||
// write TX buffer to (4) 16-bit registers starting at NANO_REG(1)
|
||||
// read (4) 16-bit registers starting at NANO_REG(0) to RX buffer
|
||||
// data is available via nanoLC.getResponseBuffer(0..3)
|
||||
nanoLC.readWriteMultipleRegisters(NANO_REG(0), 4, NANO_REG(1), 4);
|
||||
|
||||
// write lowWord(u32ShiftRegister) to single 16-bit register starting at NANO_REG(3)
|
||||
nanoLC.writeSingleRegister(NANO_REG(3), lowWord(u32ShiftRegister));
|
||||
|
||||
// write highWord(u32ShiftRegister) to single 16-bit register starting at NANO_REG(3) + 1
|
||||
nanoLC.writeSingleRegister(NANO_REG(3) + 1, highWord(u32ShiftRegister));
|
||||
|
||||
// set word 0 of TX buffer to nanoLC.getResponseBuffer(0) (bits 15..0)
|
||||
nanoLC.setTransmitBuffer(0, nanoLC.getResponseBuffer(0));
|
||||
|
||||
// set word 1 of TX buffer to nanoLC.getResponseBuffer(1) (bits 31..16)
|
||||
nanoLC.setTransmitBuffer(1, nanoLC.getResponseBuffer(1));
|
||||
|
||||
// write TX buffer to (2) 16-bit registers starting at NANO_REG(4)
|
||||
nanoLC.writeMultipleRegisters(NANO_REG(4), 2);
|
||||
|
||||
// read 17 coils starting at NANO_FLAG(0) to RX buffer
|
||||
// bits 15..0 are available via nanoLC.getResponseBuffer(0)
|
||||
// bit 16 is available via zero-padded nanoLC.getResponseBuffer(1)
|
||||
nanoLC.readCoils(NANO_FLAG(0), 17);
|
||||
|
||||
// read (66) 16-bit registers starting at NANO_REG(0) to RX buffer
|
||||
// generates Modbus exception ku8MBIllegalDataAddress (0x02)
|
||||
u8Status = nanoLC.readHoldingRegisters(NANO_REG(0), 66);
|
||||
if (u8Status == nanoLC.ku8MBIllegalDataAddress)
|
||||
{
|
||||
// read (64) 16-bit registers starting at NANO_REG(0) to RX buffer
|
||||
// data is available via nanoLC.getResponseBuffer(0..63)
|
||||
u8Status = nanoLC.readHoldingRegisters(NANO_REG(0), 64);
|
||||
}
|
||||
|
||||
// read (8) 16-bit registers starting at NANO_AO(0) to RX buffer
|
||||
// data is available via nanoLC.getResponseBuffer(0..7)
|
||||
nanoLC.readHoldingRegisters(NANO_AO(0), 8);
|
||||
|
||||
// read (64) 16-bit registers starting at NANO_TCP(0) to RX buffer
|
||||
// data is available via nanoLC.getResponseBuffer(0..63)
|
||||
nanoLC.readHoldingRegisters(NANO_TCP(0), 64);
|
||||
|
||||
// read (64) 16-bit registers starting at NANO_OTP(0) to RX buffer
|
||||
// data is available via nanoLC.getResponseBuffer(0..63)
|
||||
nanoLC.readHoldingRegisters(NANO_OTP(0), 64);
|
||||
|
||||
// read (64) 16-bit registers starting at NANO_TCA(0) to RX buffer
|
||||
// data is available via nanoLC.getResponseBuffer(0..63)
|
||||
nanoLC.readHoldingRegisters(NANO_TCA(0), 64);
|
||||
|
||||
// read (64) 16-bit registers starting at NANO_OTA(0) to RX buffer
|
||||
// data is available via nanoLC.getResponseBuffer(0..63)
|
||||
nanoLC.readHoldingRegisters(NANO_OTA(0), 64);
|
||||
|
||||
// read (8) 16-bit registers starting at NANO_AI(0) to RX buffer
|
||||
// data is available via nanoLC.getResponseBuffer(0..7)
|
||||
nanoLC.readInputRegisters(NANO_AI(0), 8);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
|
||||
RS485_HalfDuplex.pde - example using ModbusMaster library to communicate
|
||||
with EPSolar LS2024B controller using a half-duplex RS485 transceiver.
|
||||
|
||||
This example is tested against an EPSolar LS2024B solar charge controller.
|
||||
See here for protocol specs:
|
||||
http://www.solar-elektro.cz/data/dokumenty/1733_modbus_protocol.pdf
|
||||
|
||||
Library:: ModbusMaster
|
||||
Author:: Marius Kintel <marius at kintel dot net>
|
||||
|
||||
Copyright:: 2009-2016 Doc Walker
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
#include <ModbusMaster.h>
|
||||
|
||||
/*!
|
||||
We're using a MAX485-compatible RS485 Transceiver.
|
||||
Rx/Tx is hooked up to the hardware serial port at 'Serial'.
|
||||
The Data Enable and Receiver Enable pins are hooked up as follows:
|
||||
*/
|
||||
#define MAX485_DE 3
|
||||
#define MAX485_RE_NEG 2
|
||||
|
||||
// instantiate ModbusMaster object
|
||||
ModbusMaster node;
|
||||
|
||||
void preTransmission()
|
||||
{
|
||||
digitalWrite(MAX485_RE_NEG, 1);
|
||||
digitalWrite(MAX485_DE, 1);
|
||||
}
|
||||
|
||||
void postTransmission()
|
||||
{
|
||||
digitalWrite(MAX485_RE_NEG, 0);
|
||||
digitalWrite(MAX485_DE, 0);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(MAX485_RE_NEG, OUTPUT);
|
||||
pinMode(MAX485_DE, OUTPUT);
|
||||
// Init in receive mode
|
||||
digitalWrite(MAX485_RE_NEG, 0);
|
||||
digitalWrite(MAX485_DE, 0);
|
||||
|
||||
// Modbus communication runs at 115200 baud
|
||||
Serial.begin(115200);
|
||||
|
||||
// Modbus slave ID 1
|
||||
node.begin(1, Serial);
|
||||
// Callbacks allow us to configure the RS485 transceiver correctly
|
||||
node.preTransmission(preTransmission);
|
||||
node.postTransmission(postTransmission);
|
||||
}
|
||||
|
||||
bool state = true;
|
||||
|
||||
void loop()
|
||||
{
|
||||
uint8_t result;
|
||||
uint16_t data[6];
|
||||
|
||||
// Toggle the coil at address 0x0002 (Manual Load Control)
|
||||
result = node.writeSingleCoil(0x0002, state);
|
||||
state = !state;
|
||||
|
||||
// Read 16 registers starting at 0x3100)
|
||||
result = node.readInputRegisters(0x3100, 16);
|
||||
if (result == node.ku8MBSuccess)
|
||||
{
|
||||
Serial.print("Vbatt: ");
|
||||
Serial.println(node.getResponseBuffer(0x04)/100.0f);
|
||||
Serial.print("Vload: ");
|
||||
Serial.println(node.getResponseBuffer(0xC0)/100.0f);
|
||||
Serial.print("Pload: ");
|
||||
Serial.println((node.getResponseBuffer(0x0D) +
|
||||
node.getResponseBuffer(0x0E) << 16)/100.0f);
|
||||
}
|
||||
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
BIN
lib/ModbusMaster/extras/ModbusMaster reference-2.0.1.pdf
Normal file
BIN
lib/ModbusMaster/extras/ModbusMaster reference-2.0.1.pdf
Normal file
Binary file not shown.
6
lib/ModbusMaster/extras/README.txt
Normal file
6
lib/ModbusMaster/extras/README.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
Documentation is available at:
|
||||
http://4-20ma.github.com/ModbusMaster
|
||||
|
||||
Alternatively, you can download the HTML files at:
|
||||
[tarball] https://github.com/4-20ma/ModbusMaster/tarball/gh-pages
|
||||
[zipball] https://github.com/4-20ma/ModbusMaster/zipball/gh-pages
|
||||
50
lib/ModbusMaster/keywords.txt
Normal file
50
lib/ModbusMaster/keywords.txt
Normal file
@@ -0,0 +1,50 @@
|
||||
#######################################
|
||||
# Syntax Coloring Map For ModbusMaster
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
ModbusMaster KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
lowWord KEYWORD2
|
||||
highWord KEYWORD2
|
||||
LONG KEYWORD2
|
||||
|
||||
begin KEYWORD2
|
||||
|
||||
getResponseBuffer KEYWORD2
|
||||
clearResponseBuffer KEYWORD2
|
||||
setTransmitBuffer KEYWORD2
|
||||
clearTransmitBuffer KEYWORD2
|
||||
|
||||
readCoils KEYWORD2
|
||||
readDiscreteInputs KEYWORD2
|
||||
readHoldingRegisters KEYWORD2
|
||||
readInputRegisters KEYWORD2
|
||||
writeSingleCoil KEYWORD2
|
||||
writeSingleRegister KEYWORD2
|
||||
writeMultipleCoils KEYWORD2
|
||||
writeMultipleRegisters KEYWORD2
|
||||
maskWriteRegister KEYWORD2
|
||||
readWriteMultipleRegisters KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
||||
ku8MBIllegalFunction LITERAL1
|
||||
ku8MBIllegalDataAddress LITERAL1
|
||||
ku8MBIllegalDataValue LITERAL1
|
||||
ku8MBSlaveDeviceFailure LITERAL1
|
||||
|
||||
ku8MBSuccess LITERAL1
|
||||
ku8MBInvalidSlaveID LITERAL1
|
||||
ku8MBInvalidFunction LITERAL1
|
||||
ku8MBResponseTimedOut LITERAL1
|
||||
ku8MBInvalidCRC LITERAL1
|
||||
10
lib/ModbusMaster/library.properties
Normal file
10
lib/ModbusMaster/library.properties
Normal file
@@ -0,0 +1,10 @@
|
||||
name=ModbusMaster
|
||||
version=2.0.1
|
||||
author=Doc Walker
|
||||
maintainer=Doc Walker <4-20ma@wvfans.net>
|
||||
sentence=Enlighten your Arduino to be a Modbus master.
|
||||
paragraph=Enables communication with Modbus slaves over RS232/485 (via RTU protocol). Requires an RS232/485 transceiver.
|
||||
category=Communication
|
||||
url=https://github.com/4-20ma/ModbusMaster
|
||||
architectures=*
|
||||
includes=ModbusMaster.h
|
||||
876
lib/ModbusMaster/src/ModbusMaster.cpp
Normal file
876
lib/ModbusMaster/src/ModbusMaster.cpp
Normal file
@@ -0,0 +1,876 @@
|
||||
/**
|
||||
@file
|
||||
Arduino library for communicating with Modbus slaves over RS232/485 (via RTU protocol).
|
||||
*/
|
||||
/*
|
||||
|
||||
ModbusMaster.cpp - Arduino library for communicating with Modbus slaves
|
||||
over RS232/485 (via RTU protocol).
|
||||
|
||||
Library:: ModbusMaster
|
||||
|
||||
Copyright:: 2009-2016 Doc Walker
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* _____PROJECT INCLUDES_____________________________________________________ */
|
||||
#include "ModbusMaster.h"
|
||||
|
||||
|
||||
/* _____GLOBAL VARIABLES_____________________________________________________ */
|
||||
|
||||
|
||||
/* _____PUBLIC FUNCTIONS_____________________________________________________ */
|
||||
/**
|
||||
Constructor.
|
||||
|
||||
Creates class object; initialize it using ModbusMaster::begin().
|
||||
|
||||
@ingroup setup
|
||||
*/
|
||||
ModbusMaster::ModbusMaster(void)
|
||||
{
|
||||
_idle = 0;
|
||||
_preTransmission = 0;
|
||||
_postTransmission = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Initialize class object.
|
||||
|
||||
Assigns the Modbus slave ID and serial port.
|
||||
Call once class has been instantiated, typically within setup().
|
||||
|
||||
@param slave Modbus slave ID (1..255)
|
||||
@param &serial reference to serial port object (Serial, Serial1, ... Serial3)
|
||||
@ingroup setup
|
||||
*/
|
||||
void ModbusMaster::begin(uint8_t slave, Stream &serial)
|
||||
{
|
||||
// txBuffer = (uint16_t*) calloc(ku8MaxBufferSize, sizeof(uint16_t));
|
||||
_u8MBSlave = slave;
|
||||
_serial = &serial;
|
||||
_u8TransmitBufferIndex = 0;
|
||||
u16TransmitBufferLength = 0;
|
||||
|
||||
#if __MODBUSMASTER_DEBUG__
|
||||
pinMode(__MODBUSMASTER_DEBUG_PIN_A__, OUTPUT);
|
||||
pinMode(__MODBUSMASTER_DEBUG_PIN_B__, OUTPUT);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void ModbusMaster::beginTransmission(uint16_t u16Address)
|
||||
{
|
||||
_u16WriteAddress = u16Address;
|
||||
_u8TransmitBufferIndex = 0;
|
||||
u16TransmitBufferLength = 0;
|
||||
}
|
||||
|
||||
// eliminate this function in favor of using existing MB request functions
|
||||
uint8_t ModbusMaster::requestFrom(uint16_t address, uint16_t quantity)
|
||||
{
|
||||
uint8_t read;
|
||||
// clamp to buffer length
|
||||
if (quantity > ku8MaxBufferSize)
|
||||
{
|
||||
quantity = ku8MaxBufferSize;
|
||||
}
|
||||
// set rx buffer iterator vars
|
||||
_u8ResponseBufferIndex = 0;
|
||||
_u8ResponseBufferLength = read;
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
|
||||
void ModbusMaster::sendBit(bool data)
|
||||
{
|
||||
uint8_t txBitIndex = u16TransmitBufferLength % 16;
|
||||
if ((u16TransmitBufferLength >> 4) < ku8MaxBufferSize)
|
||||
{
|
||||
if (0 == txBitIndex)
|
||||
{
|
||||
_u16TransmitBuffer[_u8TransmitBufferIndex] = 0;
|
||||
}
|
||||
bitWrite(_u16TransmitBuffer[_u8TransmitBufferIndex], txBitIndex, data);
|
||||
u16TransmitBufferLength++;
|
||||
_u8TransmitBufferIndex = u16TransmitBufferLength >> 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ModbusMaster::send(uint16_t data)
|
||||
{
|
||||
if (_u8TransmitBufferIndex < ku8MaxBufferSize)
|
||||
{
|
||||
_u16TransmitBuffer[_u8TransmitBufferIndex++] = data;
|
||||
u16TransmitBufferLength = _u8TransmitBufferIndex << 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ModbusMaster::send(uint32_t data)
|
||||
{
|
||||
send(lowWord(data));
|
||||
send(highWord(data));
|
||||
}
|
||||
|
||||
|
||||
void ModbusMaster::send(uint8_t data)
|
||||
{
|
||||
send(word(data));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
uint8_t ModbusMaster::available(void)
|
||||
{
|
||||
return _u8ResponseBufferLength - _u8ResponseBufferIndex;
|
||||
}
|
||||
|
||||
|
||||
uint16_t ModbusMaster::receive(void)
|
||||
{
|
||||
if (_u8ResponseBufferIndex < _u8ResponseBufferLength)
|
||||
{
|
||||
return _u16ResponseBuffer[_u8ResponseBufferIndex++];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Set idle time callback function (cooperative multitasking).
|
||||
|
||||
This function gets called in the idle time between transmission of data
|
||||
and response from slave. Do not call functions that read from the serial
|
||||
buffer that is used by ModbusMaster. Use of i2c/TWI, 1-Wire, other
|
||||
serial ports, etc. is permitted within callback function.
|
||||
|
||||
@see ModbusMaster::ModbusMasterTransaction()
|
||||
*/
|
||||
void ModbusMaster::idle(void (*idle)())
|
||||
{
|
||||
_idle = idle;
|
||||
}
|
||||
|
||||
/**
|
||||
Set pre-transmission callback function.
|
||||
|
||||
This function gets called just before a Modbus message is sent over serial.
|
||||
Typical usage of this callback is to enable an RS485 transceiver's
|
||||
Driver Enable pin, and optionally disable its Receiver Enable pin.
|
||||
|
||||
@see ModbusMaster::ModbusMasterTransaction()
|
||||
@see ModbusMaster::postTransmission()
|
||||
*/
|
||||
void ModbusMaster::preTransmission(void (*preTransmission)())
|
||||
{
|
||||
_preTransmission = preTransmission;
|
||||
}
|
||||
|
||||
/**
|
||||
Set post-transmission callback function.
|
||||
|
||||
This function gets called after a Modbus message has finished sending
|
||||
(i.e. after all data has been physically transmitted onto the serial
|
||||
bus).
|
||||
|
||||
Typical usage of this callback is to enable an RS485 transceiver's
|
||||
Receiver Enable pin, and disable its Driver Enable pin.
|
||||
|
||||
@see ModbusMaster::ModbusMasterTransaction()
|
||||
@see ModbusMaster::preTransmission()
|
||||
*/
|
||||
void ModbusMaster::postTransmission(void (*postTransmission)())
|
||||
{
|
||||
_postTransmission = postTransmission;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Retrieve data from response buffer.
|
||||
|
||||
@see ModbusMaster::clearResponseBuffer()
|
||||
@param u8Index index of response buffer array (0x00..0x3F)
|
||||
@return value in position u8Index of response buffer (0x0000..0xFFFF)
|
||||
@ingroup buffer
|
||||
*/
|
||||
uint16_t ModbusMaster::getResponseBuffer(uint8_t u8Index)
|
||||
{
|
||||
if (u8Index < ku8MaxBufferSize)
|
||||
{
|
||||
return _u16ResponseBuffer[u8Index];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Clear Modbus response buffer.
|
||||
|
||||
@see ModbusMaster::getResponseBuffer(uint8_t u8Index)
|
||||
@ingroup buffer
|
||||
*/
|
||||
void ModbusMaster::clearResponseBuffer()
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < ku8MaxBufferSize; i++)
|
||||
{
|
||||
_u16ResponseBuffer[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Place data in transmit buffer.
|
||||
|
||||
@see ModbusMaster::clearTransmitBuffer()
|
||||
@param u8Index index of transmit buffer array (0x00..0x3F)
|
||||
@param u16Value value to place in position u8Index of transmit buffer (0x0000..0xFFFF)
|
||||
@return 0 on success; exception number on failure
|
||||
@ingroup buffer
|
||||
*/
|
||||
uint8_t ModbusMaster::setTransmitBuffer(uint8_t u8Index, uint16_t u16Value)
|
||||
{
|
||||
if (u8Index < ku8MaxBufferSize)
|
||||
{
|
||||
_u16TransmitBuffer[u8Index] = u16Value;
|
||||
return ku8MBSuccess;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ku8MBIllegalDataAddress;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Clear Modbus transmit buffer.
|
||||
|
||||
@see ModbusMaster::setTransmitBuffer(uint8_t u8Index, uint16_t u16Value)
|
||||
@ingroup buffer
|
||||
*/
|
||||
void ModbusMaster::clearTransmitBuffer()
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < ku8MaxBufferSize; i++)
|
||||
{
|
||||
_u16TransmitBuffer[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Modbus function 0x01 Read Coils.
|
||||
|
||||
This function code is used to read from 1 to 2000 contiguous status of
|
||||
coils in a remote device. The request specifies the starting address,
|
||||
i.e. the address of the first coil specified, and the number of coils.
|
||||
Coils are addressed starting at zero.
|
||||
|
||||
The coils in the response buffer are packed as one coil per bit of the
|
||||
data field. Status is indicated as 1=ON and 0=OFF. The LSB of the first
|
||||
data word contains the output addressed in the query. The other coils
|
||||
follow toward the high order end of this word and from low order to high
|
||||
order in subsequent words.
|
||||
|
||||
If the returned quantity is not a multiple of sixteen, the remaining
|
||||
bits in the final data word will be padded with zeros (toward the high
|
||||
order end of the word).
|
||||
|
||||
@param u16ReadAddress address of first coil (0x0000..0xFFFF)
|
||||
@param u16BitQty quantity of coils to read (1..2000, enforced by remote device)
|
||||
@return 0 on success; exception number on failure
|
||||
@ingroup discrete
|
||||
*/
|
||||
uint8_t ModbusMaster::readCoils(uint16_t u16ReadAddress, uint16_t u16BitQty)
|
||||
{
|
||||
_u16ReadAddress = u16ReadAddress;
|
||||
_u16ReadQty = u16BitQty;
|
||||
return ModbusMasterTransaction(ku8MBReadCoils);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Modbus function 0x02 Read Discrete Inputs.
|
||||
|
||||
This function code is used to read from 1 to 2000 contiguous status of
|
||||
discrete inputs in a remote device. The request specifies the starting
|
||||
address, i.e. the address of the first input specified, and the number
|
||||
of inputs. Discrete inputs are addressed starting at zero.
|
||||
|
||||
The discrete inputs in the response buffer are packed as one input per
|
||||
bit of the data field. Status is indicated as 1=ON; 0=OFF. The LSB of
|
||||
the first data word contains the input addressed in the query. The other
|
||||
inputs follow toward the high order end of this word, and from low order
|
||||
to high order in subsequent words.
|
||||
|
||||
If the returned quantity is not a multiple of sixteen, the remaining
|
||||
bits in the final data word will be padded with zeros (toward the high
|
||||
order end of the word).
|
||||
|
||||
@param u16ReadAddress address of first discrete input (0x0000..0xFFFF)
|
||||
@param u16BitQty quantity of discrete inputs to read (1..2000, enforced by remote device)
|
||||
@return 0 on success; exception number on failure
|
||||
@ingroup discrete
|
||||
*/
|
||||
uint8_t ModbusMaster::readDiscreteInputs(uint16_t u16ReadAddress,
|
||||
uint16_t u16BitQty)
|
||||
{
|
||||
_u16ReadAddress = u16ReadAddress;
|
||||
_u16ReadQty = u16BitQty;
|
||||
return ModbusMasterTransaction(ku8MBReadDiscreteInputs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Modbus function 0x03 Read Holding Registers.
|
||||
|
||||
This function code is used to read the contents of a contiguous block of
|
||||
holding registers in a remote device. The request specifies the starting
|
||||
register address and the number of registers. Registers are addressed
|
||||
starting at zero.
|
||||
|
||||
The register data in the response buffer is packed as one word per
|
||||
register.
|
||||
|
||||
@param u16ReadAddress address of the first holding register (0x0000..0xFFFF)
|
||||
@param u16ReadQty quantity of holding registers to read (1..125, enforced by remote device)
|
||||
@return 0 on success; exception number on failure
|
||||
@ingroup register
|
||||
*/
|
||||
uint8_t ModbusMaster::readHoldingRegisters(uint16_t u16ReadAddress,
|
||||
uint16_t u16ReadQty)
|
||||
{
|
||||
_u16ReadAddress = u16ReadAddress;
|
||||
_u16ReadQty = u16ReadQty;
|
||||
return ModbusMasterTransaction(ku8MBReadHoldingRegisters);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Modbus function 0x04 Read Input Registers.
|
||||
|
||||
This function code is used to read from 1 to 125 contiguous input
|
||||
registers in a remote device. The request specifies the starting
|
||||
register address and the number of registers. Registers are addressed
|
||||
starting at zero.
|
||||
|
||||
The register data in the response buffer is packed as one word per
|
||||
register.
|
||||
|
||||
@param u16ReadAddress address of the first input register (0x0000..0xFFFF)
|
||||
@param u16ReadQty quantity of input registers to read (1..125, enforced by remote device)
|
||||
@return 0 on success; exception number on failure
|
||||
@ingroup register
|
||||
*/
|
||||
uint8_t ModbusMaster::readInputRegisters(uint16_t u16ReadAddress,
|
||||
uint8_t u16ReadQty)
|
||||
{
|
||||
_u16ReadAddress = u16ReadAddress;
|
||||
_u16ReadQty = u16ReadQty;
|
||||
return ModbusMasterTransaction(ku8MBReadInputRegisters);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Modbus function 0x05 Write Single Coil.
|
||||
|
||||
This function code is used to write a single output to either ON or OFF
|
||||
in a remote device. The requested ON/OFF state is specified by a
|
||||
constant in the state field. A non-zero value requests the output to be
|
||||
ON and a value of 0 requests it to be OFF. The request specifies the
|
||||
address of the coil to be forced. Coils are addressed starting at zero.
|
||||
|
||||
@param u16WriteAddress address of the coil (0x0000..0xFFFF)
|
||||
@param u8State 0=OFF, non-zero=ON (0x00..0xFF)
|
||||
@return 0 on success; exception number on failure
|
||||
@ingroup discrete
|
||||
*/
|
||||
uint8_t ModbusMaster::writeSingleCoil(uint16_t u16WriteAddress, uint8_t u8State)
|
||||
{
|
||||
_u16WriteAddress = u16WriteAddress;
|
||||
_u16WriteQty = (u8State ? 0xFF00 : 0x0000);
|
||||
return ModbusMasterTransaction(ku8MBWriteSingleCoil);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Modbus function 0x06 Write Single Register.
|
||||
|
||||
This function code is used to write a single holding register in a
|
||||
remote device. The request specifies the address of the register to be
|
||||
written. Registers are addressed starting at zero.
|
||||
|
||||
@param u16WriteAddress address of the holding register (0x0000..0xFFFF)
|
||||
@param u16WriteValue value to be written to holding register (0x0000..0xFFFF)
|
||||
@return 0 on success; exception number on failure
|
||||
@ingroup register
|
||||
*/
|
||||
uint8_t ModbusMaster::writeSingleRegister(uint16_t u16WriteAddress,
|
||||
uint16_t u16WriteValue)
|
||||
{
|
||||
_u16WriteAddress = u16WriteAddress;
|
||||
_u16WriteQty = 0;
|
||||
_u16TransmitBuffer[0] = u16WriteValue;
|
||||
return ModbusMasterTransaction(ku8MBWriteSingleRegister);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Modbus function 0x0F Write Multiple Coils.
|
||||
|
||||
This function code is used to force each coil in a sequence of coils to
|
||||
either ON or OFF in a remote device. The request specifies the coil
|
||||
references to be forced. Coils are addressed starting at zero.
|
||||
|
||||
The requested ON/OFF states are specified by contents of the transmit
|
||||
buffer. A logical '1' in a bit position of the buffer requests the
|
||||
corresponding output to be ON. A logical '0' requests it to be OFF.
|
||||
|
||||
@param u16WriteAddress address of the first coil (0x0000..0xFFFF)
|
||||
@param u16BitQty quantity of coils to write (1..2000, enforced by remote device)
|
||||
@return 0 on success; exception number on failure
|
||||
@ingroup discrete
|
||||
*/
|
||||
uint8_t ModbusMaster::writeMultipleCoils(uint16_t u16WriteAddress,
|
||||
uint16_t u16BitQty)
|
||||
{
|
||||
_u16WriteAddress = u16WriteAddress;
|
||||
_u16WriteQty = u16BitQty;
|
||||
return ModbusMasterTransaction(ku8MBWriteMultipleCoils);
|
||||
}
|
||||
uint8_t ModbusMaster::writeMultipleCoils()
|
||||
{
|
||||
_u16WriteQty = u16TransmitBufferLength;
|
||||
return ModbusMasterTransaction(ku8MBWriteMultipleCoils);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Modbus function 0x10 Write Multiple Registers.
|
||||
|
||||
This function code is used to write a block of contiguous registers (1
|
||||
to 123 registers) in a remote device.
|
||||
|
||||
The requested written values are specified in the transmit buffer. Data
|
||||
is packed as one word per register.
|
||||
|
||||
@param u16WriteAddress address of the holding register (0x0000..0xFFFF)
|
||||
@param u16WriteQty quantity of holding registers to write (1..123, enforced by remote device)
|
||||
@return 0 on success; exception number on failure
|
||||
@ingroup register
|
||||
*/
|
||||
uint8_t ModbusMaster::writeMultipleRegisters(uint16_t u16WriteAddress,
|
||||
uint16_t u16WriteQty)
|
||||
{
|
||||
_u16WriteAddress = u16WriteAddress;
|
||||
_u16WriteQty = u16WriteQty;
|
||||
return ModbusMasterTransaction(ku8MBWriteMultipleRegisters);
|
||||
}
|
||||
|
||||
// new version based on Wire.h
|
||||
uint8_t ModbusMaster::writeMultipleRegisters()
|
||||
{
|
||||
_u16WriteQty = _u8TransmitBufferIndex;
|
||||
return ModbusMasterTransaction(ku8MBWriteMultipleRegisters);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Modbus function 0x16 Mask Write Register.
|
||||
|
||||
This function code is used to modify the contents of a specified holding
|
||||
register using a combination of an AND mask, an OR mask, and the
|
||||
register's current contents. The function can be used to set or clear
|
||||
individual bits in the register.
|
||||
|
||||
The request specifies the holding register to be written, the data to be
|
||||
used as the AND mask, and the data to be used as the OR mask. Registers
|
||||
are addressed starting at zero.
|
||||
|
||||
The function's algorithm is:
|
||||
|
||||
Result = (Current Contents && And_Mask) || (Or_Mask && (~And_Mask))
|
||||
|
||||
@param u16WriteAddress address of the holding register (0x0000..0xFFFF)
|
||||
@param u16AndMask AND mask (0x0000..0xFFFF)
|
||||
@param u16OrMask OR mask (0x0000..0xFFFF)
|
||||
@return 0 on success; exception number on failure
|
||||
@ingroup register
|
||||
*/
|
||||
uint8_t ModbusMaster::maskWriteRegister(uint16_t u16WriteAddress,
|
||||
uint16_t u16AndMask, uint16_t u16OrMask)
|
||||
{
|
||||
_u16WriteAddress = u16WriteAddress;
|
||||
_u16TransmitBuffer[0] = u16AndMask;
|
||||
_u16TransmitBuffer[1] = u16OrMask;
|
||||
return ModbusMasterTransaction(ku8MBMaskWriteRegister);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Modbus function 0x17 Read Write Multiple Registers.
|
||||
|
||||
This function code performs a combination of one read operation and one
|
||||
write operation in a single MODBUS transaction. The write operation is
|
||||
performed before the read. Holding registers are addressed starting at
|
||||
zero.
|
||||
|
||||
The request specifies the starting address and number of holding
|
||||
registers to be read as well as the starting address, and the number of
|
||||
holding registers. The data to be written is specified in the transmit
|
||||
buffer.
|
||||
|
||||
@param u16ReadAddress address of the first holding register (0x0000..0xFFFF)
|
||||
@param u16ReadQty quantity of holding registers to read (1..125, enforced by remote device)
|
||||
@param u16WriteAddress address of the first holding register (0x0000..0xFFFF)
|
||||
@param u16WriteQty quantity of holding registers to write (1..121, enforced by remote device)
|
||||
@return 0 on success; exception number on failure
|
||||
@ingroup register
|
||||
*/
|
||||
uint8_t ModbusMaster::readWriteMultipleRegisters(uint16_t u16ReadAddress,
|
||||
uint16_t u16ReadQty, uint16_t u16WriteAddress, uint16_t u16WriteQty)
|
||||
{
|
||||
_u16ReadAddress = u16ReadAddress;
|
||||
_u16ReadQty = u16ReadQty;
|
||||
_u16WriteAddress = u16WriteAddress;
|
||||
_u16WriteQty = u16WriteQty;
|
||||
return ModbusMasterTransaction(ku8MBReadWriteMultipleRegisters);
|
||||
}
|
||||
uint8_t ModbusMaster::readWriteMultipleRegisters(uint16_t u16ReadAddress,
|
||||
uint16_t u16ReadQty)
|
||||
{
|
||||
_u16ReadAddress = u16ReadAddress;
|
||||
_u16ReadQty = u16ReadQty;
|
||||
_u16WriteQty = _u8TransmitBufferIndex;
|
||||
return ModbusMasterTransaction(ku8MBReadWriteMultipleRegisters);
|
||||
}
|
||||
|
||||
|
||||
/* _____PRIVATE FUNCTIONS____________________________________________________ */
|
||||
/**
|
||||
Modbus transaction engine.
|
||||
Sequence:
|
||||
- assemble Modbus Request Application Data Unit (ADU),
|
||||
based on particular function called
|
||||
- transmit request over selected serial port
|
||||
- wait for/retrieve response
|
||||
- evaluate/disassemble response
|
||||
- return status (success/exception)
|
||||
|
||||
@param u8MBFunction Modbus function (0x01..0xFF)
|
||||
@return 0 on success; exception number on failure
|
||||
*/
|
||||
uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction)
|
||||
{
|
||||
uint8_t u8ModbusADU[256];
|
||||
uint8_t u8ModbusADUSize = 0;
|
||||
uint8_t i, u8Qty;
|
||||
uint16_t u16CRC;
|
||||
uint32_t u32StartTime;
|
||||
uint8_t u8BytesLeft = 8;
|
||||
uint8_t u8MBStatus = ku8MBSuccess;
|
||||
|
||||
// assemble Modbus Request Application Data Unit
|
||||
u8ModbusADU[u8ModbusADUSize++] = _u8MBSlave;
|
||||
u8ModbusADU[u8ModbusADUSize++] = u8MBFunction;
|
||||
|
||||
switch(u8MBFunction)
|
||||
{
|
||||
case ku8MBReadCoils:
|
||||
case ku8MBReadDiscreteInputs:
|
||||
case ku8MBReadInputRegisters:
|
||||
case ku8MBReadHoldingRegisters:
|
||||
case ku8MBReadWriteMultipleRegisters:
|
||||
u8ModbusADU[u8ModbusADUSize++] = highByte(_u16ReadAddress);
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16ReadAddress);
|
||||
u8ModbusADU[u8ModbusADUSize++] = highByte(_u16ReadQty);
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16ReadQty);
|
||||
break;
|
||||
}
|
||||
|
||||
switch(u8MBFunction)
|
||||
{
|
||||
case ku8MBWriteSingleCoil:
|
||||
case ku8MBMaskWriteRegister:
|
||||
case ku8MBWriteMultipleCoils:
|
||||
case ku8MBWriteSingleRegister:
|
||||
case ku8MBWriteMultipleRegisters:
|
||||
case ku8MBReadWriteMultipleRegisters:
|
||||
u8ModbusADU[u8ModbusADUSize++] = highByte(_u16WriteAddress);
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteAddress);
|
||||
break;
|
||||
}
|
||||
|
||||
switch(u8MBFunction)
|
||||
{
|
||||
case ku8MBWriteSingleCoil:
|
||||
u8ModbusADU[u8ModbusADUSize++] = highByte(_u16WriteQty);
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteQty);
|
||||
break;
|
||||
|
||||
case ku8MBWriteSingleRegister:
|
||||
u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[0]);
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[0]);
|
||||
break;
|
||||
|
||||
case ku8MBWriteMultipleCoils:
|
||||
u8ModbusADU[u8ModbusADUSize++] = highByte(_u16WriteQty);
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteQty);
|
||||
u8Qty = (_u16WriteQty % 8) ? ((_u16WriteQty >> 3) + 1) : (_u16WriteQty >> 3);
|
||||
u8ModbusADU[u8ModbusADUSize++] = u8Qty;
|
||||
for (i = 0; i < u8Qty; i++)
|
||||
{
|
||||
switch(i % 2)
|
||||
{
|
||||
case 0: // i is even
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[i >> 1]);
|
||||
break;
|
||||
|
||||
case 1: // i is odd
|
||||
u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[i >> 1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ku8MBWriteMultipleRegisters:
|
||||
case ku8MBReadWriteMultipleRegisters:
|
||||
u8ModbusADU[u8ModbusADUSize++] = highByte(_u16WriteQty);
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteQty);
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16WriteQty << 1);
|
||||
|
||||
for (i = 0; i < lowByte(_u16WriteQty); i++)
|
||||
{
|
||||
u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[i]);
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case ku8MBMaskWriteRegister:
|
||||
u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[0]);
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[0]);
|
||||
u8ModbusADU[u8ModbusADUSize++] = highByte(_u16TransmitBuffer[1]);
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte(_u16TransmitBuffer[1]);
|
||||
break;
|
||||
}
|
||||
|
||||
// append CRC
|
||||
u16CRC = 0xFFFF;
|
||||
for (i = 0; i < u8ModbusADUSize; i++)
|
||||
{
|
||||
u16CRC = crc16_update(u16CRC, u8ModbusADU[i]);
|
||||
}
|
||||
u8ModbusADU[u8ModbusADUSize++] = lowByte(u16CRC);
|
||||
u8ModbusADU[u8ModbusADUSize++] = highByte(u16CRC);
|
||||
u8ModbusADU[u8ModbusADUSize] = 0;
|
||||
|
||||
// flush receive buffer before transmitting request
|
||||
while (_serial->read() != -1);
|
||||
|
||||
// transmit request
|
||||
if (_preTransmission)
|
||||
{
|
||||
_preTransmission();
|
||||
}
|
||||
for (i = 0; i < u8ModbusADUSize; i++)
|
||||
{
|
||||
_serial->write(u8ModbusADU[i]);
|
||||
}
|
||||
|
||||
u8ModbusADUSize = 0;
|
||||
_serial->flush(); // flush transmit buffer
|
||||
if (_postTransmission)
|
||||
{
|
||||
_postTransmission();
|
||||
}
|
||||
|
||||
// loop until we run out of time or bytes, or an error occurs
|
||||
u32StartTime = millis();
|
||||
while (u8BytesLeft && !u8MBStatus)
|
||||
{
|
||||
if (_serial->available())
|
||||
{
|
||||
#if __MODBUSMASTER_DEBUG__
|
||||
digitalWrite(__MODBUSMASTER_DEBUG_PIN_A__, true);
|
||||
#endif
|
||||
u8ModbusADU[u8ModbusADUSize++] = _serial->read();
|
||||
u8BytesLeft--;
|
||||
#if __MODBUSMASTER_DEBUG__
|
||||
digitalWrite(__MODBUSMASTER_DEBUG_PIN_A__, false);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if __MODBUSMASTER_DEBUG__
|
||||
digitalWrite(__MODBUSMASTER_DEBUG_PIN_B__, true);
|
||||
#endif
|
||||
if (_idle)
|
||||
{
|
||||
_idle();
|
||||
}
|
||||
#if __MODBUSMASTER_DEBUG__
|
||||
digitalWrite(__MODBUSMASTER_DEBUG_PIN_B__, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
// evaluate slave ID, function code once enough bytes have been read
|
||||
if (u8ModbusADUSize == 5)
|
||||
{
|
||||
// verify response is for correct Modbus slave
|
||||
if (u8ModbusADU[0] != _u8MBSlave)
|
||||
{
|
||||
u8MBStatus = ku8MBInvalidSlaveID;
|
||||
break;
|
||||
}
|
||||
|
||||
// verify response is for correct Modbus function code (mask exception bit 7)
|
||||
if ((u8ModbusADU[1] & 0x7F) != u8MBFunction)
|
||||
{
|
||||
u8MBStatus = ku8MBInvalidFunction;
|
||||
break;
|
||||
}
|
||||
|
||||
// check whether Modbus exception occurred; return Modbus Exception Code
|
||||
if (bitRead(u8ModbusADU[1], 7))
|
||||
{
|
||||
u8MBStatus = u8ModbusADU[2];
|
||||
break;
|
||||
}
|
||||
|
||||
// evaluate returned Modbus function code
|
||||
switch(u8ModbusADU[1])
|
||||
{
|
||||
case ku8MBReadCoils:
|
||||
case ku8MBReadDiscreteInputs:
|
||||
case ku8MBReadInputRegisters:
|
||||
case ku8MBReadHoldingRegisters:
|
||||
case ku8MBReadWriteMultipleRegisters:
|
||||
u8BytesLeft = u8ModbusADU[2];
|
||||
break;
|
||||
|
||||
case ku8MBWriteSingleCoil:
|
||||
case ku8MBWriteMultipleCoils:
|
||||
case ku8MBWriteSingleRegister:
|
||||
case ku8MBWriteMultipleRegisters:
|
||||
u8BytesLeft = 3;
|
||||
break;
|
||||
|
||||
case ku8MBMaskWriteRegister:
|
||||
u8BytesLeft = 5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((millis() - u32StartTime) > ku16MBResponseTimeout)
|
||||
{
|
||||
u8MBStatus = ku8MBResponseTimedOut;
|
||||
}
|
||||
}
|
||||
|
||||
// verify response is large enough to inspect further
|
||||
if (!u8MBStatus && u8ModbusADUSize >= 5)
|
||||
{
|
||||
// calculate CRC
|
||||
u16CRC = 0xFFFF;
|
||||
for (i = 0; i < (u8ModbusADUSize - 2); i++)
|
||||
{
|
||||
u16CRC = crc16_update(u16CRC, u8ModbusADU[i]);
|
||||
}
|
||||
|
||||
// verify CRC
|
||||
if (!u8MBStatus && (lowByte(u16CRC) != u8ModbusADU[u8ModbusADUSize - 2] ||
|
||||
highByte(u16CRC) != u8ModbusADU[u8ModbusADUSize - 1]))
|
||||
{
|
||||
u8MBStatus = ku8MBInvalidCRC;
|
||||
}
|
||||
}
|
||||
|
||||
// disassemble ADU into words
|
||||
if (!u8MBStatus)
|
||||
{
|
||||
// evaluate returned Modbus function code
|
||||
switch(u8ModbusADU[1])
|
||||
{
|
||||
case ku8MBReadCoils:
|
||||
case ku8MBReadDiscreteInputs:
|
||||
// load bytes into word; response bytes are ordered L, H, L, H, ...
|
||||
for (i = 0; i < (u8ModbusADU[2] >> 1); i++)
|
||||
{
|
||||
if (i < ku8MaxBufferSize)
|
||||
{
|
||||
_u16ResponseBuffer[i] = word(u8ModbusADU[2 * i + 4], u8ModbusADU[2 * i + 3]);
|
||||
}
|
||||
|
||||
_u8ResponseBufferLength = i;
|
||||
}
|
||||
|
||||
// in the event of an odd number of bytes, load last byte into zero-padded word
|
||||
if (u8ModbusADU[2] % 2)
|
||||
{
|
||||
if (i < ku8MaxBufferSize)
|
||||
{
|
||||
_u16ResponseBuffer[i] = word(0, u8ModbusADU[2 * i + 3]);
|
||||
}
|
||||
|
||||
_u8ResponseBufferLength = i + 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case ku8MBReadInputRegisters:
|
||||
case ku8MBReadHoldingRegisters:
|
||||
case ku8MBReadWriteMultipleRegisters:
|
||||
// load bytes into word; response bytes are ordered H, L, H, L, ...
|
||||
for (i = 0; i < (u8ModbusADU[2] >> 1); i++)
|
||||
{
|
||||
if (i < ku8MaxBufferSize)
|
||||
{
|
||||
_u16ResponseBuffer[i] = word(u8ModbusADU[2 * i + 3], u8ModbusADU[2 * i + 4]);
|
||||
}
|
||||
|
||||
_u8ResponseBufferLength = i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_u8TransmitBufferIndex = 0;
|
||||
u16TransmitBufferLength = 0;
|
||||
_u8ResponseBufferIndex = 0;
|
||||
return u8MBStatus;
|
||||
}
|
||||
270
lib/ModbusMaster/src/ModbusMaster.h
Normal file
270
lib/ModbusMaster/src/ModbusMaster.h
Normal file
@@ -0,0 +1,270 @@
|
||||
/**
|
||||
@file
|
||||
Arduino library for communicating with Modbus slaves over RS232/485 (via RTU protocol).
|
||||
|
||||
@defgroup setup ModbusMaster Object Instantiation/Initialization
|
||||
@defgroup buffer ModbusMaster Buffer Management
|
||||
@defgroup discrete Modbus Function Codes for Discrete Coils/Inputs
|
||||
@defgroup register Modbus Function Codes for Holding/Input Registers
|
||||
@defgroup constant Modbus Function Codes, Exception Codes
|
||||
*/
|
||||
/*
|
||||
|
||||
ModbusMaster.h - Arduino library for communicating with Modbus slaves
|
||||
over RS232/485 (via RTU protocol).
|
||||
|
||||
Library:: ModbusMaster
|
||||
|
||||
Copyright:: 2009-2016 Doc Walker
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ModbusMaster_h
|
||||
#define ModbusMaster_h
|
||||
|
||||
|
||||
/**
|
||||
@def __MODBUSMASTER_DEBUG__ (0)
|
||||
Set to 1 to enable debugging features within class:
|
||||
- PIN A cycles for each byte read in the Modbus response
|
||||
- PIN B cycles for each millisecond timeout during the Modbus response
|
||||
*/
|
||||
#define __MODBUSMASTER_DEBUG__ (0)
|
||||
#define __MODBUSMASTER_DEBUG_PIN_A__ 4
|
||||
#define __MODBUSMASTER_DEBUG_PIN_B__ 5
|
||||
|
||||
/* _____STANDARD INCLUDES____________________________________________________ */
|
||||
// include types & constants of Wiring core API
|
||||
#include "Arduino.h"
|
||||
|
||||
/* _____UTILITY MACROS_______________________________________________________ */
|
||||
|
||||
|
||||
/* _____PROJECT INCLUDES_____________________________________________________ */
|
||||
// functions to calculate Modbus Application Data Unit CRC
|
||||
#include "util/crc16.h"
|
||||
|
||||
// functions to manipulate words
|
||||
#include "util/word.h"
|
||||
|
||||
|
||||
/* _____CLASS DEFINITIONS____________________________________________________ */
|
||||
/**
|
||||
Arduino class library for communicating with Modbus slaves over
|
||||
RS232/485 (via RTU protocol).
|
||||
*/
|
||||
class ModbusMaster
|
||||
{
|
||||
public:
|
||||
ModbusMaster();
|
||||
|
||||
void begin(uint8_t, Stream &serial);
|
||||
void idle(void (*)());
|
||||
void preTransmission(void (*)());
|
||||
void postTransmission(void (*)());
|
||||
|
||||
// Modbus exception codes
|
||||
/**
|
||||
Modbus protocol illegal function exception.
|
||||
|
||||
The function code received in the query is not an allowable action for
|
||||
the server (or slave). This may be because the function code is only
|
||||
applicable to newer devices, and was not implemented in the unit
|
||||
selected. It could also indicate that the server (or slave) is in the
|
||||
wrong state to process a request of this type, for example because it is
|
||||
unconfigured and is being asked to return register values.
|
||||
|
||||
@ingroup constant
|
||||
*/
|
||||
static const uint8_t ku8MBIllegalFunction = 0x01;
|
||||
|
||||
/**
|
||||
Modbus protocol illegal data address exception.
|
||||
|
||||
The data address received in the query is not an allowable address for
|
||||
the server (or slave). More specifically, the combination of reference
|
||||
number and transfer length is invalid. For a controller with 100
|
||||
registers, the ADU addresses the first register as 0, and the last one
|
||||
as 99. If a request is submitted with a starting register address of 96
|
||||
and a quantity of registers of 4, then this request will successfully
|
||||
operate (address-wise at least) on registers 96, 97, 98, 99. If a
|
||||
request is submitted with a starting register address of 96 and a
|
||||
quantity of registers of 5, then this request will fail with Exception
|
||||
Code 0x02 "Illegal Data Address" since it attempts to operate on
|
||||
registers 96, 97, 98, 99 and 100, and there is no register with address
|
||||
100.
|
||||
|
||||
@ingroup constant
|
||||
*/
|
||||
static const uint8_t ku8MBIllegalDataAddress = 0x02;
|
||||
|
||||
/**
|
||||
Modbus protocol illegal data value exception.
|
||||
|
||||
A value contained in the query data field is not an allowable value for
|
||||
server (or slave). This indicates a fault in the structure of the
|
||||
remainder of a complex request, such as that the implied length is
|
||||
incorrect. It specifically does NOT mean that a data item submitted for
|
||||
storage in a register has a value outside the expectation of the
|
||||
application program, since the MODBUS protocol is unaware of the
|
||||
significance of any particular value of any particular register.
|
||||
|
||||
@ingroup constant
|
||||
*/
|
||||
static const uint8_t ku8MBIllegalDataValue = 0x03;
|
||||
|
||||
/**
|
||||
Modbus protocol slave device failure exception.
|
||||
|
||||
An unrecoverable error occurred while the server (or slave) was
|
||||
attempting to perform the requested action.
|
||||
|
||||
@ingroup constant
|
||||
*/
|
||||
static const uint8_t ku8MBSlaveDeviceFailure = 0x04;
|
||||
|
||||
// Class-defined success/exception codes
|
||||
/**
|
||||
ModbusMaster success.
|
||||
|
||||
Modbus transaction was successful; the following checks were valid:
|
||||
- slave ID
|
||||
- function code
|
||||
- response code
|
||||
- data
|
||||
- CRC
|
||||
|
||||
@ingroup constant
|
||||
*/
|
||||
static const uint8_t ku8MBSuccess = 0x00;
|
||||
|
||||
/**
|
||||
ModbusMaster invalid response slave ID exception.
|
||||
|
||||
The slave ID in the response does not match that of the request.
|
||||
|
||||
@ingroup constant
|
||||
*/
|
||||
static const uint8_t ku8MBInvalidSlaveID = 0xE0;
|
||||
|
||||
/**
|
||||
ModbusMaster invalid response function exception.
|
||||
|
||||
The function code in the response does not match that of the request.
|
||||
|
||||
@ingroup constant
|
||||
*/
|
||||
static const uint8_t ku8MBInvalidFunction = 0xE1;
|
||||
|
||||
/**
|
||||
ModbusMaster response timed out exception.
|
||||
|
||||
The entire response was not received within the timeout period,
|
||||
ModbusMaster::ku8MBResponseTimeout.
|
||||
|
||||
@ingroup constant
|
||||
*/
|
||||
static const uint8_t ku8MBResponseTimedOut = 0xE2;
|
||||
|
||||
/**
|
||||
ModbusMaster invalid response CRC exception.
|
||||
|
||||
The CRC in the response does not match the one calculated.
|
||||
|
||||
@ingroup constant
|
||||
*/
|
||||
static const uint8_t ku8MBInvalidCRC = 0xE3;
|
||||
|
||||
uint16_t getResponseBuffer(uint8_t);
|
||||
void clearResponseBuffer();
|
||||
uint8_t setTransmitBuffer(uint8_t, uint16_t);
|
||||
void clearTransmitBuffer();
|
||||
|
||||
void beginTransmission(uint16_t);
|
||||
uint8_t requestFrom(uint16_t, uint16_t);
|
||||
void sendBit(bool);
|
||||
void send(uint8_t);
|
||||
void send(uint16_t);
|
||||
void send(uint32_t);
|
||||
uint8_t available(void);
|
||||
uint16_t receive(void);
|
||||
|
||||
|
||||
uint8_t readCoils(uint16_t, uint16_t);
|
||||
uint8_t readDiscreteInputs(uint16_t, uint16_t);
|
||||
uint8_t readHoldingRegisters(uint16_t, uint16_t);
|
||||
uint8_t readInputRegisters(uint16_t, uint8_t);
|
||||
uint8_t writeSingleCoil(uint16_t, uint8_t);
|
||||
uint8_t writeSingleRegister(uint16_t, uint16_t);
|
||||
uint8_t writeMultipleCoils(uint16_t, uint16_t);
|
||||
uint8_t writeMultipleCoils();
|
||||
uint8_t writeMultipleRegisters(uint16_t, uint16_t);
|
||||
uint8_t writeMultipleRegisters();
|
||||
uint8_t maskWriteRegister(uint16_t, uint16_t, uint16_t);
|
||||
uint8_t readWriteMultipleRegisters(uint16_t, uint16_t, uint16_t, uint16_t);
|
||||
uint8_t readWriteMultipleRegisters(uint16_t, uint16_t);
|
||||
|
||||
private:
|
||||
Stream* _serial; ///< reference to serial port object
|
||||
uint8_t _u8MBSlave; ///< Modbus slave (1..255) initialized in begin()
|
||||
static const uint8_t ku8MaxBufferSize = 64; ///< size of response/transmit buffers
|
||||
uint16_t _u16ReadAddress; ///< slave register from which to read
|
||||
uint16_t _u16ReadQty; ///< quantity of words to read
|
||||
uint16_t _u16ResponseBuffer[ku8MaxBufferSize]; ///< buffer to store Modbus slave response; read via GetResponseBuffer()
|
||||
uint16_t _u16WriteAddress; ///< slave register to which to write
|
||||
uint16_t _u16WriteQty; ///< quantity of words to write
|
||||
uint16_t _u16TransmitBuffer[ku8MaxBufferSize]; ///< buffer containing data to transmit to Modbus slave; set via SetTransmitBuffer()
|
||||
uint16_t* txBuffer; // from Wire.h -- need to clean this up Rx
|
||||
uint8_t _u8TransmitBufferIndex;
|
||||
uint16_t u16TransmitBufferLength;
|
||||
uint16_t* rxBuffer; // from Wire.h -- need to clean this up Rx
|
||||
uint8_t _u8ResponseBufferIndex;
|
||||
uint8_t _u8ResponseBufferLength;
|
||||
|
||||
// Modbus function codes for bit access
|
||||
static const uint8_t ku8MBReadCoils = 0x01; ///< Modbus function 0x01 Read Coils
|
||||
static const uint8_t ku8MBReadDiscreteInputs = 0x02; ///< Modbus function 0x02 Read Discrete Inputs
|
||||
static const uint8_t ku8MBWriteSingleCoil = 0x05; ///< Modbus function 0x05 Write Single Coil
|
||||
static const uint8_t ku8MBWriteMultipleCoils = 0x0F; ///< Modbus function 0x0F Write Multiple Coils
|
||||
|
||||
// Modbus function codes for 16 bit access
|
||||
static const uint8_t ku8MBReadHoldingRegisters = 0x03; ///< Modbus function 0x03 Read Holding Registers
|
||||
static const uint8_t ku8MBReadInputRegisters = 0x04; ///< Modbus function 0x04 Read Input Registers
|
||||
static const uint8_t ku8MBWriteSingleRegister = 0x06; ///< Modbus function 0x06 Write Single Register
|
||||
static const uint8_t ku8MBWriteMultipleRegisters = 0x10; ///< Modbus function 0x10 Write Multiple Registers
|
||||
static const uint8_t ku8MBMaskWriteRegister = 0x16; ///< Modbus function 0x16 Mask Write Register
|
||||
static const uint8_t ku8MBReadWriteMultipleRegisters = 0x17; ///< Modbus function 0x17 Read Write Multiple Registers
|
||||
|
||||
// Modbus timeout [milliseconds]
|
||||
static const uint16_t ku16MBResponseTimeout = 150; ///< Modbus timeout [milliseconds]
|
||||
|
||||
// master function that conducts Modbus transactions
|
||||
uint8_t ModbusMasterTransaction(uint8_t u8MBFunction);
|
||||
|
||||
// idle callback function; gets called during idle time between TX and RX
|
||||
void (*_idle)();
|
||||
// preTransmission callback function; gets called before writing a Modbus message
|
||||
void (*_preTransmission)();
|
||||
// postTransmission callback function; gets called after a Modbus message has been sent
|
||||
void (*_postTransmission)();
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
@example examples/Basic/Basic.pde
|
||||
@example examples/PhoenixContact_nanoLC/PhoenixContact_nanoLC.pde
|
||||
@example examples/RS485_HalfDuplex/RS485_HalfDuplex.ino
|
||||
*/
|
||||
88
lib/ModbusMaster/src/util/crc16.h
Normal file
88
lib/ModbusMaster/src/util/crc16.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
@file
|
||||
CRC Computations
|
||||
|
||||
@defgroup util_crc16 "util/crc16.h": CRC Computations
|
||||
@code#include "util/crc16.h"@endcode
|
||||
|
||||
This header file provides functions for calculating
|
||||
cyclic redundancy checks (CRC) using common polynomials.
|
||||
Modified by Doc Walker to be processor-independent (removed inline
|
||||
assembler to allow it to compile on SAM3X8E processors).
|
||||
|
||||
@par References:
|
||||
Jack Crenshaw's "Implementing CRCs" article in the January 1992 issue of @e
|
||||
Embedded @e Systems @e Programming. This may be difficult to find, but it
|
||||
explains CRC's in very clear and concise terms. Well worth the effort to
|
||||
obtain a copy.
|
||||
|
||||
*/
|
||||
/* Copyright (c) 2002, 2003, 2004 Marek Michalkiewicz
|
||||
Copyright (c) 2005, 2007 Joerg Wunsch
|
||||
Copyright (c) 2013 Dave Hylands
|
||||
Copyright (c) 2013 Frederic Nadeau
|
||||
Copyright (c) 2015 Doc Walker
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* 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.
|
||||
|
||||
* Neither the name of the copyright holders nor the names of
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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. */
|
||||
|
||||
|
||||
#ifndef _UTIL_CRC16_H_
|
||||
#define _UTIL_CRC16_H_
|
||||
|
||||
|
||||
/** @ingroup util_crc16
|
||||
Processor-independent CRC-16 calculation.
|
||||
|
||||
Polynomial: x^16 + x^15 + x^2 + 1 (0xA001)<br>
|
||||
Initial value: 0xFFFF
|
||||
|
||||
This CRC is normally used in disk-drive controllers.
|
||||
|
||||
@param uint16_t crc (0x0000..0xFFFF)
|
||||
@param uint8_t a (0x00..0xFF)
|
||||
@return calculated CRC (0x0000..0xFFFF)
|
||||
*/
|
||||
static uint16_t crc16_update(uint16_t crc, uint8_t a)
|
||||
{
|
||||
int i;
|
||||
|
||||
crc ^= a;
|
||||
for (i = 0; i < 8; ++i)
|
||||
{
|
||||
if (crc & 1)
|
||||
crc = (crc >> 1) ^ 0xA001;
|
||||
else
|
||||
crc = (crc >> 1);
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
||||
#endif /* _UTIL_CRC16_H_ */
|
||||
64
lib/ModbusMaster/src/util/word.h
Normal file
64
lib/ModbusMaster/src/util/word.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
@file
|
||||
Utility Functions for Manipulating Words
|
||||
|
||||
@defgroup util_word "util/word.h": Utility Functions for Manipulating Words
|
||||
@code#include "util/word.h"@endcode
|
||||
|
||||
This header file provides utility functions for manipulating words.
|
||||
|
||||
*/
|
||||
/*
|
||||
|
||||
word.h - Utility Functions for Manipulating Words
|
||||
|
||||
This file is part of ModbusMaster.
|
||||
|
||||
ModbusMaster is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ModbusMaster is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with ModbusMaster. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Written by Doc Walker (Rx)
|
||||
Copyright © 2009-2015 Doc Walker <4-20ma at wvfans dot net>
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _UTIL_WORD_H_
|
||||
#define _UTIL_WORD_H_
|
||||
|
||||
|
||||
/** @ingroup util_word
|
||||
Return low word of a 32-bit integer.
|
||||
|
||||
@param uint32_t ww (0x00000000..0xFFFFFFFF)
|
||||
@return low word of input (0x0000..0xFFFF)
|
||||
*/
|
||||
static inline uint16_t lowWord(uint32_t ww)
|
||||
{
|
||||
return (uint16_t) ((ww) & 0xFFFF);
|
||||
}
|
||||
|
||||
|
||||
/** @ingroup util_word
|
||||
Return high word of a 32-bit integer.
|
||||
|
||||
@param uint32_t ww (0x00000000..0xFFFFFFFF)
|
||||
@return high word of input (0x0000..0xFFFF)
|
||||
*/
|
||||
static inline uint16_t highWord(uint32_t ww)
|
||||
{
|
||||
return (uint16_t) ((ww) >> 16);
|
||||
}
|
||||
|
||||
|
||||
#endif /* _UTIL_WORD_H_ */
|
||||
Reference in New Issue
Block a user