Commit f7cb1f06ce8ddeac709dc7a6f4c4784e7e0ef80d
0 parents
initial import
(automatically generated log message)
Showing
14 changed files
with
2900 additions
and
0 deletions
AUTHORS
0 → 100644
COPYING
0 → 100644
| 1 | +++ a/COPYING | |
| 1 | + GNU GENERAL PUBLIC LICENSE | |
| 2 | + Version 2, June 1991 | |
| 3 | + | |
| 4 | + Copyright (C) 1989, 1991 Free Software Foundation, Inc. | |
| 5 | + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 6 | + Everyone is permitted to copy and distribute verbatim copies | |
| 7 | + of this license document, but changing it is not allowed. | |
| 8 | + | |
| 9 | + Preamble | |
| 10 | + | |
| 11 | + The licenses for most software are designed to take away your | |
| 12 | +freedom to share and change it. By contrast, the GNU General Public | |
| 13 | +License is intended to guarantee your freedom to share and change free | |
| 14 | +software--to make sure the software is free for all its users. This | |
| 15 | +General Public License applies to most of the Free Software | |
| 16 | +Foundation's software and to any other program whose authors commit to | |
| 17 | +using it. (Some other Free Software Foundation software is covered by | |
| 18 | +the GNU Library General Public License instead.) You can apply it to | |
| 19 | +your programs, too. | |
| 20 | + | |
| 21 | + When we speak of free software, we are referring to freedom, not | |
| 22 | +price. Our General Public Licenses are designed to make sure that you | |
| 23 | +have the freedom to distribute copies of free software (and charge for | |
| 24 | +this service if you wish), that you receive source code or can get it | |
| 25 | +if you want it, that you can change the software or use pieces of it | |
| 26 | +in new free programs; and that you know you can do these things. | |
| 27 | + | |
| 28 | + To protect your rights, we need to make restrictions that forbid | |
| 29 | +anyone to deny you these rights or to ask you to surrender the rights. | |
| 30 | +These restrictions translate to certain responsibilities for you if you | |
| 31 | +distribute copies of the software, or if you modify it. | |
| 32 | + | |
| 33 | + For example, if you distribute copies of such a program, whether | |
| 34 | +gratis or for a fee, you must give the recipients all the rights that | |
| 35 | +you have. You must make sure that they, too, receive or can get the | |
| 36 | +source code. And you must show them these terms so they know their | |
| 37 | +rights. | |
| 38 | + | |
| 39 | + We protect your rights with two steps: (1) copyright the software, and | |
| 40 | +(2) offer you this license which gives you legal permission to copy, | |
| 41 | +distribute and/or modify the software. | |
| 42 | + | |
| 43 | + Also, for each author's protection and ours, we want to make certain | |
| 44 | +that everyone understands that there is no warranty for this free | |
| 45 | +software. If the software is modified by someone else and passed on, we | |
| 46 | +want its recipients to know that what they have is not the original, so | |
| 47 | +that any problems introduced by others will not reflect on the original | |
| 48 | +authors' reputations. | |
| 49 | + | |
| 50 | + Finally, any free program is threatened constantly by software | |
| 51 | +patents. We wish to avoid the danger that redistributors of a free | |
| 52 | +program will individually obtain patent licenses, in effect making the | |
| 53 | +program proprietary. To prevent this, we have made it clear that any | |
| 54 | +patent must be licensed for everyone's free use or not licensed at all. | |
| 55 | + | |
| 56 | + The precise terms and conditions for copying, distribution and | |
| 57 | +modification follow. | |
| 58 | + | |
| 59 | + GNU GENERAL PUBLIC LICENSE | |
| 60 | + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |
| 61 | + | |
| 62 | + 0. This License applies to any program or other work which contains | |
| 63 | +a notice placed by the copyright holder saying it may be distributed | |
| 64 | +under the terms of this General Public License. The "Program", below, | |
| 65 | +refers to any such program or work, and a "work based on the Program" | |
| 66 | +means either the Program or any derivative work under copyright law: | |
| 67 | +that is to say, a work containing the Program or a portion of it, | |
| 68 | +either verbatim or with modifications and/or translated into another | |
| 69 | +language. (Hereinafter, translation is included without limitation in | |
| 70 | +the term "modification".) Each licensee is addressed as "you". | |
| 71 | + | |
| 72 | +Activities other than copying, distribution and modification are not | |
| 73 | +covered by this License; they are outside its scope. The act of | |
| 74 | +running the Program is not restricted, and the output from the Program | |
| 75 | +is covered only if its contents constitute a work based on the | |
| 76 | +Program (independent of having been made by running the Program). | |
| 77 | +Whether that is true depends on what the Program does. | |
| 78 | + | |
| 79 | + 1. You may copy and distribute verbatim copies of the Program's | |
| 80 | +source code as you receive it, in any medium, provided that you | |
| 81 | +conspicuously and appropriately publish on each copy an appropriate | |
| 82 | +copyright notice and disclaimer of warranty; keep intact all the | |
| 83 | +notices that refer to this License and to the absence of any warranty; | |
| 84 | +and give any other recipients of the Program a copy of this License | |
| 85 | +along with the Program. | |
| 86 | + | |
| 87 | +You may charge a fee for the physical act of transferring a copy, and | |
| 88 | +you may at your option offer warranty protection in exchange for a fee. | |
| 89 | + | |
| 90 | + 2. You may modify your copy or copies of the Program or any portion | |
| 91 | +of it, thus forming a work based on the Program, and copy and | |
| 92 | +distribute such modifications or work under the terms of Section 1 | |
| 93 | +above, provided that you also meet all of these conditions: | |
| 94 | + | |
| 95 | + a) You must cause the modified files to carry prominent notices | |
| 96 | + stating that you changed the files and the date of any change. | |
| 97 | + | |
| 98 | + b) You must cause any work that you distribute or publish, that in | |
| 99 | + whole or in part contains or is derived from the Program or any | |
| 100 | + part thereof, to be licensed as a whole at no charge to all third | |
| 101 | + parties under the terms of this License. | |
| 102 | + | |
| 103 | + c) If the modified program normally reads commands interactively | |
| 104 | + when run, you must cause it, when started running for such | |
| 105 | + interactive use in the most ordinary way, to print or display an | |
| 106 | + announcement including an appropriate copyright notice and a | |
| 107 | + notice that there is no warranty (or else, saying that you provide | |
| 108 | + a warranty) and that users may redistribute the program under | |
| 109 | + these conditions, and telling the user how to view a copy of this | |
| 110 | + License. (Exception: if the Program itself is interactive but | |
| 111 | + does not normally print such an announcement, your work based on | |
| 112 | + the Program is not required to print an announcement.) | |
| 113 | + | |
| 114 | +These requirements apply to the modified work as a whole. If | |
| 115 | +identifiable sections of that work are not derived from the Program, | |
| 116 | +and can be reasonably considered independent and separate works in | |
| 117 | +themselves, then this License, and its terms, do not apply to those | |
| 118 | +sections when you distribute them as separate works. But when you | |
| 119 | +distribute the same sections as part of a whole which is a work based | |
| 120 | +on the Program, the distribution of the whole must be on the terms of | |
| 121 | +this License, whose permissions for other licensees extend to the | |
| 122 | +entire whole, and thus to each and every part regardless of who wrote it. | |
| 123 | + | |
| 124 | +Thus, it is not the intent of this section to claim rights or contest | |
| 125 | +your rights to work written entirely by you; rather, the intent is to | |
| 126 | +exercise the right to control the distribution of derivative or | |
| 127 | +collective works based on the Program. | |
| 128 | + | |
| 129 | +In addition, mere aggregation of another work not based on the Program | |
| 130 | +with the Program (or with a work based on the Program) on a volume of | |
| 131 | +a storage or distribution medium does not bring the other work under | |
| 132 | +the scope of this License. | |
| 133 | + | |
| 134 | + 3. You may copy and distribute the Program (or a work based on it, | |
| 135 | +under Section 2) in object code or executable form under the terms of | |
| 136 | +Sections 1 and 2 above provided that you also do one of the following: | |
| 137 | + | |
| 138 | + a) Accompany it with the complete corresponding machine-readable | |
| 139 | + source code, which must be distributed under the terms of Sections | |
| 140 | + 1 and 2 above on a medium customarily used for software interchange; or, | |
| 141 | + | |
| 142 | + b) Accompany it with a written offer, valid for at least three | |
| 143 | + years, to give any third party, for a charge no more than your | |
| 144 | + cost of physically performing source distribution, a complete | |
| 145 | + machine-readable copy of the corresponding source code, to be | |
| 146 | + distributed under the terms of Sections 1 and 2 above on a medium | |
| 147 | + customarily used for software interchange; or, | |
| 148 | + | |
| 149 | + c) Accompany it with the information you received as to the offer | |
| 150 | + to distribute corresponding source code. (This alternative is | |
| 151 | + allowed only for noncommercial distribution and only if you | |
| 152 | + received the program in object code or executable form with such | |
| 153 | + an offer, in accord with Subsection b above.) | |
| 154 | + | |
| 155 | +The source code for a work means the preferred form of the work for | |
| 156 | +making modifications to it. For an executable work, complete source | |
| 157 | +code means all the source code for all modules it contains, plus any | |
| 158 | +associated interface definition files, plus the scripts used to | |
| 159 | +control compilation and installation of the executable. However, as a | |
| 160 | +special exception, the source code distributed need not include | |
| 161 | +anything that is normally distributed (in either source or binary | |
| 162 | +form) with the major components (compiler, kernel, and so on) of the | |
| 163 | +operating system on which the executable runs, unless that component | |
| 164 | +itself accompanies the executable. | |
| 165 | + | |
| 166 | +If distribution of executable or object code is made by offering | |
| 167 | +access to copy from a designated place, then offering equivalent | |
| 168 | +access to copy the source code from the same place counts as | |
| 169 | +distribution of the source code, even though third parties are not | |
| 170 | +compelled to copy the source along with the object code. | |
| 171 | + | |
| 172 | + 4. You may not copy, modify, sublicense, or distribute the Program | |
| 173 | +except as expressly provided under this License. Any attempt | |
| 174 | +otherwise to copy, modify, sublicense or distribute the Program is | |
| 175 | +void, and will automatically terminate your rights under this License. | |
| 176 | +However, parties who have received copies, or rights, from you under | |
| 177 | +this License will not have their licenses terminated so long as such | |
| 178 | +parties remain in full compliance. | |
| 179 | + | |
| 180 | + 5. You are not required to accept this License, since you have not | |
| 181 | +signed it. However, nothing else grants you permission to modify or | |
| 182 | +distribute the Program or its derivative works. These actions are | |
| 183 | +prohibited by law if you do not accept this License. Therefore, by | |
| 184 | +modifying or distributing the Program (or any work based on the | |
| 185 | +Program), you indicate your acceptance of this License to do so, and | |
| 186 | +all its terms and conditions for copying, distributing or modifying | |
| 187 | +the Program or works based on it. | |
| 188 | + | |
| 189 | + 6. Each time you redistribute the Program (or any work based on the | |
| 190 | +Program), the recipient automatically receives a license from the | |
| 191 | +original licensor to copy, distribute or modify the Program subject to | |
| 192 | +these terms and conditions. You may not impose any further | |
| 193 | +restrictions on the recipients' exercise of the rights granted herein. | |
| 194 | +You are not responsible for enforcing compliance by third parties to | |
| 195 | +this License. | |
| 196 | + | |
| 197 | + 7. If, as a consequence of a court judgment or allegation of patent | |
| 198 | +infringement or for any other reason (not limited to patent issues), | |
| 199 | +conditions are imposed on you (whether by court order, agreement or | |
| 200 | +otherwise) that contradict the conditions of this License, they do not | |
| 201 | +excuse you from the conditions of this License. If you cannot | |
| 202 | +distribute so as to satisfy simultaneously your obligations under this | |
| 203 | +License and any other pertinent obligations, then as a consequence you | |
| 204 | +may not distribute the Program at all. For example, if a patent | |
| 205 | +license would not permit royalty-free redistribution of the Program by | |
| 206 | +all those who receive copies directly or indirectly through you, then | |
| 207 | +the only way you could satisfy both it and this License would be to | |
| 208 | +refrain entirely from distribution of the Program. | |
| 209 | + | |
| 210 | +If any portion of this section is held invalid or unenforceable under | |
| 211 | +any particular circumstance, the balance of the section is intended to | |
| 212 | +apply and the section as a whole is intended to apply in other | |
| 213 | +circumstances. | |
| 214 | + | |
| 215 | +It is not the purpose of this section to induce you to infringe any | |
| 216 | +patents or other property right claims or to contest validity of any | |
| 217 | +such claims; this section has the sole purpose of protecting the | |
| 218 | +integrity of the free software distribution system, which is | |
| 219 | +implemented by public license practices. Many people have made | |
| 220 | +generous contributions to the wide range of software distributed | |
| 221 | +through that system in reliance on consistent application of that | |
| 222 | +system; it is up to the author/donor to decide if he or she is willing | |
| 223 | +to distribute software through any other system and a licensee cannot | |
| 224 | +impose that choice. | |
| 225 | + | |
| 226 | +This section is intended to make thoroughly clear what is believed to | |
| 227 | +be a consequence of the rest of this License. | |
| 228 | + | |
| 229 | + 8. If the distribution and/or use of the Program is restricted in | |
| 230 | +certain countries either by patents or by copyrighted interfaces, the | |
| 231 | +original copyright holder who places the Program under this License | |
| 232 | +may add an explicit geographical distribution limitation excluding | |
| 233 | +those countries, so that distribution is permitted only in or among | |
| 234 | +countries not thus excluded. In such case, this License incorporates | |
| 235 | +the limitation as if written in the body of this License. | |
| 236 | + | |
| 237 | + 9. The Free Software Foundation may publish revised and/or new versions | |
| 238 | +of the General Public License from time to time. Such new versions will | |
| 239 | +be similar in spirit to the present version, but may differ in detail to | |
| 240 | +address new problems or concerns. | |
| 241 | + | |
| 242 | +Each version is given a distinguishing version number. If the Program | |
| 243 | +specifies a version number of this License which applies to it and "any | |
| 244 | +later version", you have the option of following the terms and conditions | |
| 245 | +either of that version or of any later version published by the Free | |
| 246 | +Software Foundation. If the Program does not specify a version number of | |
| 247 | +this License, you may choose any version ever published by the Free Software | |
| 248 | +Foundation. | |
| 249 | + | |
| 250 | + 10. If you wish to incorporate parts of the Program into other free | |
| 251 | +programs whose distribution conditions are different, write to the author | |
| 252 | +to ask for permission. For software which is copyrighted by the Free | |
| 253 | +Software Foundation, write to the Free Software Foundation; we sometimes | |
| 254 | +make exceptions for this. Our decision will be guided by the two goals | |
| 255 | +of preserving the free status of all derivatives of our free software and | |
| 256 | +of promoting the sharing and reuse of software generally. | |
| 257 | + | |
| 258 | + NO WARRANTY | |
| 259 | + | |
| 260 | + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY | |
| 261 | +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN | |
| 262 | +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | |
| 263 | +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED | |
| 264 | +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
| 265 | +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS | |
| 266 | +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE | |
| 267 | +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, | |
| 268 | +REPAIR OR CORRECTION. | |
| 269 | + | |
| 270 | + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | |
| 271 | +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | |
| 272 | +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, | |
| 273 | +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING | |
| 274 | +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED | |
| 275 | +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY | |
| 276 | +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER | |
| 277 | +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE | |
| 278 | +POSSIBILITY OF SUCH DAMAGES. | |
| 279 | + | |
| 280 | + END OF TERMS AND CONDITIONS | |
| 281 | + | |
| 282 | + How to Apply These Terms to Your New Programs | |
| 283 | + | |
| 284 | + If you develop a new program, and you want it to be of the greatest | |
| 285 | +possible use to the public, the best way to achieve this is to make it | |
| 286 | +free software which everyone can redistribute and change under these terms. | |
| 287 | + | |
| 288 | + To do so, attach the following notices to the program. It is safest | |
| 289 | +to attach them to the start of each source file to most effectively | |
| 290 | +convey the exclusion of warranty; and each file should have at least | |
| 291 | +the "copyright" line and a pointer to where the full notice is found. | |
| 292 | + | |
| 293 | + <one line to give the program's name and a brief idea of what it does.> | |
| 294 | + Copyright (C) <year> <name of author> | |
| 295 | + | |
| 296 | + This program is free software; you can redistribute it and/or modify | |
| 297 | + it under the terms of the GNU General Public License as published by | |
| 298 | + the Free Software Foundation; either version 2 of the License, or | |
| 299 | + (at your option) any later version. | |
| 300 | + | |
| 301 | + This program is distributed in the hope that it will be useful, | |
| 302 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 303 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 304 | + GNU General Public License for more details. | |
| 305 | + | |
| 306 | + You should have received a copy of the GNU General Public License | |
| 307 | + along with this program; if not, write to the Free Software | |
| 308 | + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 309 | + | |
| 310 | + | |
| 311 | +Also add information on how to contact you by electronic and paper mail. | |
| 312 | + | |
| 313 | +If the program is interactive, make it output a short notice like this | |
| 314 | +when it starts in an interactive mode: | |
| 315 | + | |
| 316 | + Gnomovision version 69, Copyright (C) year name of author | |
| 317 | + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | |
| 318 | + This is free software, and you are welcome to redistribute it | |
| 319 | + under certain conditions; type `show c' for details. | |
| 320 | + | |
| 321 | +The hypothetical commands `show w' and `show c' should show the appropriate | |
| 322 | +parts of the General Public License. Of course, the commands you use may | |
| 323 | +be called something other than `show w' and `show c'; they could even be | |
| 324 | +mouse-clicks or menu items--whatever suits your program. | |
| 325 | + | |
| 326 | +You should also get your employer (if you work as a programmer) or your | |
| 327 | +school, if any, to sign a "copyright disclaimer" for the program, if | |
| 328 | +necessary. Here is a sample; alter the names: | |
| 329 | + | |
| 330 | + Yoyodyne, Inc., hereby disclaims all copyright interest in the program | |
| 331 | + `Gnomovision' (which makes passes at compilers) written by James Hacker. | |
| 332 | + | |
| 333 | + <signature of Ty Coon>, 1 April 1989 | |
| 334 | + Ty Coon, President of Vice | |
| 335 | + | |
| 336 | +This General Public License does not permit incorporating your program into | |
| 337 | +proprietary programs. If your program is a subroutine library, you may | |
| 338 | +consider it more useful to permit linking proprietary applications with the | |
| 339 | +library. If this is what you want to do, use the GNU Library General | |
| 340 | +Public License instead of this License. | ... | ... |
COPYING.LIB
0 → 100644
| 1 | +++ a/COPYING.LIB | |
| 1 | + GNU LIBRARY GENERAL PUBLIC LICENSE | |
| 2 | + Version 2, June 1991 | |
| 3 | + | |
| 4 | + Copyright (C) 1991 Free Software Foundation, Inc. | |
| 5 | + 675 Mass Ave, Cambridge, MA 02139, USA | |
| 6 | + Everyone is permitted to copy and distribute verbatim copies | |
| 7 | + of this license document, but changing it is not allowed. | |
| 8 | + | |
| 9 | +[This is the first released version of the library GPL. It is | |
| 10 | + numbered 2 because it goes with version 2 of the ordinary GPL.] | |
| 11 | + | |
| 12 | + Preamble | |
| 13 | + | |
| 14 | + The licenses for most software are designed to take away your | |
| 15 | +freedom to share and change it. By contrast, the GNU General Public | |
| 16 | +Licenses are intended to guarantee your freedom to share and change | |
| 17 | +free software--to make sure the software is free for all its users. | |
| 18 | + | |
| 19 | + This license, the Library General Public License, applies to some | |
| 20 | +specially designated Free Software Foundation software, and to any | |
| 21 | +other libraries whose authors decide to use it. You can use it for | |
| 22 | +your libraries, too. | |
| 23 | + | |
| 24 | + When we speak of free software, we are referring to freedom, not | |
| 25 | +price. Our General Public Licenses are designed to make sure that you | |
| 26 | +have the freedom to distribute copies of free software (and charge for | |
| 27 | +this service if you wish), that you receive source code or can get it | |
| 28 | +if you want it, that you can change the software or use pieces of it | |
| 29 | +in new free programs; and that you know you can do these things. | |
| 30 | + | |
| 31 | + To protect your rights, we need to make restrictions that forbid | |
| 32 | +anyone to deny you these rights or to ask you to surrender the rights. | |
| 33 | +These restrictions translate to certain responsibilities for you if | |
| 34 | +you distribute copies of the library, or if you modify it. | |
| 35 | + | |
| 36 | + For example, if you distribute copies of the library, whether gratis | |
| 37 | +or for a fee, you must give the recipients all the rights that we gave | |
| 38 | +you. You must make sure that they, too, receive or can get the source | |
| 39 | +code. If you link a program with the library, you must provide | |
| 40 | +complete object files to the recipients so that they can relink them | |
| 41 | +with the library, after making changes to the library and recompiling | |
| 42 | +it. And you must show them these terms so they know their rights. | |
| 43 | + | |
| 44 | + Our method of protecting your rights has two steps: (1) copyright | |
| 45 | +the library, and (2) offer you this license which gives you legal | |
| 46 | +permission to copy, distribute and/or modify the library. | |
| 47 | + | |
| 48 | + Also, for each distributor's protection, we want to make certain | |
| 49 | +that everyone understands that there is no warranty for this free | |
| 50 | +library. If the library is modified by someone else and passed on, we | |
| 51 | +want its recipients to know that what they have is not the original | |
| 52 | +version, so that any problems introduced by others will not reflect on | |
| 53 | +the original authors' reputations. | |
| 54 | + | |
| 55 | + Finally, any free program is threatened constantly by software | |
| 56 | +patents. We wish to avoid the danger that companies distributing free | |
| 57 | +software will individually obtain patent licenses, thus in effect | |
| 58 | +transforming the program into proprietary software. To prevent this, | |
| 59 | +we have made it clear that any patent must be licensed for everyone's | |
| 60 | +free use or not licensed at all. | |
| 61 | + | |
| 62 | + Most GNU software, including some libraries, is covered by the ordinary | |
| 63 | +GNU General Public License, which was designed for utility programs. This | |
| 64 | +license, the GNU Library General Public License, applies to certain | |
| 65 | +designated libraries. This license is quite different from the ordinary | |
| 66 | +one; be sure to read it in full, and don't assume that anything in it is | |
| 67 | +the same as in the ordinary license. | |
| 68 | + | |
| 69 | + The reason we have a separate public license for some libraries is that | |
| 70 | +they blur the distinction we usually make between modifying or adding to a | |
| 71 | +program and simply using it. Linking a program with a library, without | |
| 72 | +changing the library, is in some sense simply using the library, and is | |
| 73 | +analogous to running a utility program or application program. However, in | |
| 74 | +a textual and legal sense, the linked executable is a combined work, a | |
| 75 | +derivative of the original library, and the ordinary General Public License | |
| 76 | +treats it as such. | |
| 77 | + | |
| 78 | + Because of this blurred distinction, using the ordinary General | |
| 79 | +Public License for libraries did not effectively promote software | |
| 80 | +sharing, because most developers did not use the libraries. We | |
| 81 | +concluded that weaker conditions might promote sharing better. | |
| 82 | + | |
| 83 | + However, unrestricted linking of non-free programs would deprive the | |
| 84 | +users of those programs of all benefit from the free status of the | |
| 85 | +libraries themselves. This Library General Public License is intended to | |
| 86 | +permit developers of non-free programs to use free libraries, while | |
| 87 | +preserving your freedom as a user of such programs to change the free | |
| 88 | +libraries that are incorporated in them. (We have not seen how to achieve | |
| 89 | +this as regards changes in header files, but we have achieved it as regards | |
| 90 | +changes in the actual functions of the Library.) The hope is that this | |
| 91 | +will lead to faster development of free libraries. | |
| 92 | + | |
| 93 | + The precise terms and conditions for copying, distribution and | |
| 94 | +modification follow. Pay close attention to the difference between a | |
| 95 | +"work based on the library" and a "work that uses the library". The | |
| 96 | +former contains code derived from the library, while the latter only | |
| 97 | +works together with the library. | |
| 98 | + | |
| 99 | + Note that it is possible for a library to be covered by the ordinary | |
| 100 | +General Public License rather than by this special one. | |
| 101 | + | |
| 102 | + GNU LIBRARY GENERAL PUBLIC LICENSE | |
| 103 | + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |
| 104 | + | |
| 105 | + 0. This License Agreement applies to any software library which | |
| 106 | +contains a notice placed by the copyright holder or other authorized | |
| 107 | +party saying it may be distributed under the terms of this Library | |
| 108 | +General Public License (also called "this License"). Each licensee is | |
| 109 | +addressed as "you". | |
| 110 | + | |
| 111 | + A "library" means a collection of software functions and/or data | |
| 112 | +prepared so as to be conveniently linked with application programs | |
| 113 | +(which use some of those functions and data) to form executables. | |
| 114 | + | |
| 115 | + The "Library", below, refers to any such software library or work | |
| 116 | +which has been distributed under these terms. A "work based on the | |
| 117 | +Library" means either the Library or any derivative work under | |
| 118 | +copyright law: that is to say, a work containing the Library or a | |
| 119 | +portion of it, either verbatim or with modifications and/or translated | |
| 120 | +straightforwardly into another language. (Hereinafter, translation is | |
| 121 | +included without limitation in the term "modification".) | |
| 122 | + | |
| 123 | + "Source code" for a work means the preferred form of the work for | |
| 124 | +making modifications to it. For a library, complete source code means | |
| 125 | +all the source code for all modules it contains, plus any associated | |
| 126 | +interface definition files, plus the scripts used to control compilation | |
| 127 | +and installation of the library. | |
| 128 | + | |
| 129 | + Activities other than copying, distribution and modification are not | |
| 130 | +covered by this License; they are outside its scope. The act of | |
| 131 | +running a program using the Library is not restricted, and output from | |
| 132 | +such a program is covered only if its contents constitute a work based | |
| 133 | +on the Library (independent of the use of the Library in a tool for | |
| 134 | +writing it). Whether that is true depends on what the Library does | |
| 135 | +and what the program that uses the Library does. | |
| 136 | + | |
| 137 | + 1. You may copy and distribute verbatim copies of the Library's | |
| 138 | +complete source code as you receive it, in any medium, provided that | |
| 139 | +you conspicuously and appropriately publish on each copy an | |
| 140 | +appropriate copyright notice and disclaimer of warranty; keep intact | |
| 141 | +all the notices that refer to this License and to the absence of any | |
| 142 | +warranty; and distribute a copy of this License along with the | |
| 143 | +Library. | |
| 144 | + | |
| 145 | + You may charge a fee for the physical act of transferring a copy, | |
| 146 | +and you may at your option offer warranty protection in exchange for a | |
| 147 | +fee. | |
| 148 | + | |
| 149 | + 2. You may modify your copy or copies of the Library or any portion | |
| 150 | +of it, thus forming a work based on the Library, and copy and | |
| 151 | +distribute such modifications or work under the terms of Section 1 | |
| 152 | +above, provided that you also meet all of these conditions: | |
| 153 | + | |
| 154 | + a) The modified work must itself be a software library. | |
| 155 | + | |
| 156 | + b) You must cause the files modified to carry prominent notices | |
| 157 | + stating that you changed the files and the date of any change. | |
| 158 | + | |
| 159 | + c) You must cause the whole of the work to be licensed at no | |
| 160 | + charge to all third parties under the terms of this License. | |
| 161 | + | |
| 162 | + d) If a facility in the modified Library refers to a function or a | |
| 163 | + table of data to be supplied by an application program that uses | |
| 164 | + the facility, other than as an argument passed when the facility | |
| 165 | + is invoked, then you must make a good faith effort to ensure that, | |
| 166 | + in the event an application does not supply such function or | |
| 167 | + table, the facility still operates, and performs whatever part of | |
| 168 | + its purpose remains meaningful. | |
| 169 | + | |
| 170 | + (For example, a function in a library to compute square roots has | |
| 171 | + a purpose that is entirely well-defined independent of the | |
| 172 | + application. Therefore, Subsection 2d requires that any | |
| 173 | + application-supplied function or table used by this function must | |
| 174 | + be optional: if the application does not supply it, the square | |
| 175 | + root function must still compute square roots.) | |
| 176 | + | |
| 177 | +These requirements apply to the modified work as a whole. If | |
| 178 | +identifiable sections of that work are not derived from the Library, | |
| 179 | +and can be reasonably considered independent and separate works in | |
| 180 | +themselves, then this License, and its terms, do not apply to those | |
| 181 | +sections when you distribute them as separate works. But when you | |
| 182 | +distribute the same sections as part of a whole which is a work based | |
| 183 | +on the Library, the distribution of the whole must be on the terms of | |
| 184 | +this License, whose permissions for other licensees extend to the | |
| 185 | +entire whole, and thus to each and every part regardless of who wrote | |
| 186 | +it. | |
| 187 | + | |
| 188 | +Thus, it is not the intent of this section to claim rights or contest | |
| 189 | +your rights to work written entirely by you; rather, the intent is to | |
| 190 | +exercise the right to control the distribution of derivative or | |
| 191 | +collective works based on the Library. | |
| 192 | + | |
| 193 | +In addition, mere aggregation of another work not based on the Library | |
| 194 | +with the Library (or with a work based on the Library) on a volume of | |
| 195 | +a storage or distribution medium does not bring the other work under | |
| 196 | +the scope of this License. | |
| 197 | + | |
| 198 | + 3. You may opt to apply the terms of the ordinary GNU General Public | |
| 199 | +License instead of this License to a given copy of the Library. To do | |
| 200 | +this, you must alter all the notices that refer to this License, so | |
| 201 | +that they refer to the ordinary GNU General Public License, version 2, | |
| 202 | +instead of to this License. (If a newer version than version 2 of the | |
| 203 | +ordinary GNU General Public License has appeared, then you can specify | |
| 204 | +that version instead if you wish.) Do not make any other change in | |
| 205 | +these notices. | |
| 206 | + | |
| 207 | + Once this change is made in a given copy, it is irreversible for | |
| 208 | +that copy, so the ordinary GNU General Public License applies to all | |
| 209 | +subsequent copies and derivative works made from that copy. | |
| 210 | + | |
| 211 | + This option is useful when you wish to copy part of the code of | |
| 212 | +the Library into a program that is not a library. | |
| 213 | + | |
| 214 | + 4. You may copy and distribute the Library (or a portion or | |
| 215 | +derivative of it, under Section 2) in object code or executable form | |
| 216 | +under the terms of Sections 1 and 2 above provided that you accompany | |
| 217 | +it with the complete corresponding machine-readable source code, which | |
| 218 | +must be distributed under the terms of Sections 1 and 2 above on a | |
| 219 | +medium customarily used for software interchange. | |
| 220 | + | |
| 221 | + If distribution of object code is made by offering access to copy | |
| 222 | +from a designated place, then offering equivalent access to copy the | |
| 223 | +source code from the same place satisfies the requirement to | |
| 224 | +distribute the source code, even though third parties are not | |
| 225 | +compelled to copy the source along with the object code. | |
| 226 | + | |
| 227 | + 5. A program that contains no derivative of any portion of the | |
| 228 | +Library, but is designed to work with the Library by being compiled or | |
| 229 | +linked with it, is called a "work that uses the Library". Such a | |
| 230 | +work, in isolation, is not a derivative work of the Library, and | |
| 231 | +therefore falls outside the scope of this License. | |
| 232 | + | |
| 233 | + However, linking a "work that uses the Library" with the Library | |
| 234 | +creates an executable that is a derivative of the Library (because it | |
| 235 | +contains portions of the Library), rather than a "work that uses the | |
| 236 | +library". The executable is therefore covered by this License. | |
| 237 | +Section 6 states terms for distribution of such executables. | |
| 238 | + | |
| 239 | + When a "work that uses the Library" uses material from a header file | |
| 240 | +that is part of the Library, the object code for the work may be a | |
| 241 | +derivative work of the Library even though the source code is not. | |
| 242 | +Whether this is true is especially significant if the work can be | |
| 243 | +linked without the Library, or if the work is itself a library. The | |
| 244 | +threshold for this to be true is not precisely defined by law. | |
| 245 | + | |
| 246 | + If such an object file uses only numerical parameters, data | |
| 247 | +structure layouts and accessors, and small macros and small inline | |
| 248 | +functions (ten lines or less in length), then the use of the object | |
| 249 | +file is unrestricted, regardless of whether it is legally a derivative | |
| 250 | +work. (Executables containing this object code plus portions of the | |
| 251 | +Library will still fall under Section 6.) | |
| 252 | + | |
| 253 | + Otherwise, if the work is a derivative of the Library, you may | |
| 254 | +distribute the object code for the work under the terms of Section 6. | |
| 255 | +Any executables containing that work also fall under Section 6, | |
| 256 | +whether or not they are linked directly with the Library itself. | |
| 257 | + | |
| 258 | + 6. As an exception to the Sections above, you may also compile or | |
| 259 | +link a "work that uses the Library" with the Library to produce a | |
| 260 | +work containing portions of the Library, and distribute that work | |
| 261 | +under terms of your choice, provided that the terms permit | |
| 262 | +modification of the work for the customer's own use and reverse | |
| 263 | +engineering for debugging such modifications. | |
| 264 | + | |
| 265 | + You must give prominent notice with each copy of the work that the | |
| 266 | +Library is used in it and that the Library and its use are covered by | |
| 267 | +this License. You must supply a copy of this License. If the work | |
| 268 | +during execution displays copyright notices, you must include the | |
| 269 | +copyright notice for the Library among them, as well as a reference | |
| 270 | +directing the user to the copy of this License. Also, you must do one | |
| 271 | +of these things: | |
| 272 | + | |
| 273 | + a) Accompany the work with the complete corresponding | |
| 274 | + machine-readable source code for the Library including whatever | |
| 275 | + changes were used in the work (which must be distributed under | |
| 276 | + Sections 1 and 2 above); and, if the work is an executable linked | |
| 277 | + with the Library, with the complete machine-readable "work that | |
| 278 | + uses the Library", as object code and/or source code, so that the | |
| 279 | + user can modify the Library and then relink to produce a modified | |
| 280 | + executable containing the modified Library. (It is understood | |
| 281 | + that the user who changes the contents of definitions files in the | |
| 282 | + Library will not necessarily be able to recompile the application | |
| 283 | + to use the modified definitions.) | |
| 284 | + | |
| 285 | + b) Accompany the work with a written offer, valid for at | |
| 286 | + least three years, to give the same user the materials | |
| 287 | + specified in Subsection 6a, above, for a charge no more | |
| 288 | + than the cost of performing this distribution. | |
| 289 | + | |
| 290 | + c) If distribution of the work is made by offering access to copy | |
| 291 | + from a designated place, offer equivalent access to copy the above | |
| 292 | + specified materials from the same place. | |
| 293 | + | |
| 294 | + d) Verify that the user has already received a copy of these | |
| 295 | + materials or that you have already sent this user a copy. | |
| 296 | + | |
| 297 | + For an executable, the required form of the "work that uses the | |
| 298 | +Library" must include any data and utility programs needed for | |
| 299 | +reproducing the executable from it. However, as a special exception, | |
| 300 | +the source code distributed need not include anything that is normally | |
| 301 | +distributed (in either source or binary form) with the major | |
| 302 | +components (compiler, kernel, and so on) of the operating system on | |
| 303 | +which the executable runs, unless that component itself accompanies | |
| 304 | +the executable. | |
| 305 | + | |
| 306 | + It may happen that this requirement contradicts the license | |
| 307 | +restrictions of other proprietary libraries that do not normally | |
| 308 | +accompany the operating system. Such a contradiction means you cannot | |
| 309 | +use both them and the Library together in an executable that you | |
| 310 | +distribute. | |
| 311 | + | |
| 312 | + 7. You may place library facilities that are a work based on the | |
| 313 | +Library side-by-side in a single library together with other library | |
| 314 | +facilities not covered by this License, and distribute such a combined | |
| 315 | +library, provided that the separate distribution of the work based on | |
| 316 | +the Library and of the other library facilities is otherwise | |
| 317 | +permitted, and provided that you do these two things: | |
| 318 | + | |
| 319 | + a) Accompany the combined library with a copy of the same work | |
| 320 | + based on the Library, uncombined with any other library | |
| 321 | + facilities. This must be distributed under the terms of the | |
| 322 | + Sections above. | |
| 323 | + | |
| 324 | + b) Give prominent notice with the combined library of the fact | |
| 325 | + that part of it is a work based on the Library, and explaining | |
| 326 | + where to find the accompanying uncombined form of the same work. | |
| 327 | + | |
| 328 | + 8. You may not copy, modify, sublicense, link with, or distribute | |
| 329 | +the Library except as expressly provided under this License. Any | |
| 330 | +attempt otherwise to copy, modify, sublicense, link with, or | |
| 331 | +distribute the Library is void, and will automatically terminate your | |
| 332 | +rights under this License. However, parties who have received copies, | |
| 333 | +or rights, from you under this License will not have their licenses | |
| 334 | +terminated so long as such parties remain in full compliance. | |
| 335 | + | |
| 336 | + 9. You are not required to accept this License, since you have not | |
| 337 | +signed it. However, nothing else grants you permission to modify or | |
| 338 | +distribute the Library or its derivative works. These actions are | |
| 339 | +prohibited by law if you do not accept this License. Therefore, by | |
| 340 | +modifying or distributing the Library (or any work based on the | |
| 341 | +Library), you indicate your acceptance of this License to do so, and | |
| 342 | +all its terms and conditions for copying, distributing or modifying | |
| 343 | +the Library or works based on it. | |
| 344 | + | |
| 345 | + 10. Each time you redistribute the Library (or any work based on the | |
| 346 | +Library), the recipient automatically receives a license from the | |
| 347 | +original licensor to copy, distribute, link with or modify the Library | |
| 348 | +subject to these terms and conditions. You may not impose any further | |
| 349 | +restrictions on the recipients' exercise of the rights granted herein. | |
| 350 | +You are not responsible for enforcing compliance by third parties to | |
| 351 | +this License. | |
| 352 | + | |
| 353 | + 11. If, as a consequence of a court judgment or allegation of patent | |
| 354 | +infringement or for any other reason (not limited to patent issues), | |
| 355 | +conditions are imposed on you (whether by court order, agreement or | |
| 356 | +otherwise) that contradict the conditions of this License, they do not | |
| 357 | +excuse you from the conditions of this License. If you cannot | |
| 358 | +distribute so as to satisfy simultaneously your obligations under this | |
| 359 | +License and any other pertinent obligations, then as a consequence you | |
| 360 | +may not distribute the Library at all. For example, if a patent | |
| 361 | +license would not permit royalty-free redistribution of the Library by | |
| 362 | +all those who receive copies directly or indirectly through you, then | |
| 363 | +the only way you could satisfy both it and this License would be to | |
| 364 | +refrain entirely from distribution of the Library. | |
| 365 | + | |
| 366 | +If any portion of this section is held invalid or unenforceable under any | |
| 367 | +particular circumstance, the balance of the section is intended to apply, | |
| 368 | +and the section as a whole is intended to apply in other circumstances. | |
| 369 | + | |
| 370 | +It is not the purpose of this section to induce you to infringe any | |
| 371 | +patents or other property right claims or to contest validity of any | |
| 372 | +such claims; this section has the sole purpose of protecting the | |
| 373 | +integrity of the free software distribution system which is | |
| 374 | +implemented by public license practices. Many people have made | |
| 375 | +generous contributions to the wide range of software distributed | |
| 376 | +through that system in reliance on consistent application of that | |
| 377 | +system; it is up to the author/donor to decide if he or she is willing | |
| 378 | +to distribute software through any other system and a licensee cannot | |
| 379 | +impose that choice. | |
| 380 | + | |
| 381 | +This section is intended to make thoroughly clear what is believed to | |
| 382 | +be a consequence of the rest of this License. | |
| 383 | + | |
| 384 | + 12. If the distribution and/or use of the Library is restricted in | |
| 385 | +certain countries either by patents or by copyrighted interfaces, the | |
| 386 | +original copyright holder who places the Library under this License may add | |
| 387 | +an explicit geographical distribution limitation excluding those countries, | |
| 388 | +so that distribution is permitted only in or among countries not thus | |
| 389 | +excluded. In such case, this License incorporates the limitation as if | |
| 390 | +written in the body of this License. | |
| 391 | + | |
| 392 | + 13. The Free Software Foundation may publish revised and/or new | |
| 393 | +versions of the Library General Public License from time to time. | |
| 394 | +Such new versions will be similar in spirit to the present version, | |
| 395 | +but may differ in detail to address new problems or concerns. | |
| 396 | + | |
| 397 | +Each version is given a distinguishing version number. If the Library | |
| 398 | +specifies a version number of this License which applies to it and | |
| 399 | +"any later version", you have the option of following the terms and | |
| 400 | +conditions either of that version or of any later version published by | |
| 401 | +the Free Software Foundation. If the Library does not specify a | |
| 402 | +license version number, you may choose any version ever published by | |
| 403 | +the Free Software Foundation. | |
| 404 | + | |
| 405 | + 14. If you wish to incorporate parts of the Library into other free | |
| 406 | +programs whose distribution conditions are incompatible with these, | |
| 407 | +write to the author to ask for permission. For software which is | |
| 408 | +copyrighted by the Free Software Foundation, write to the Free | |
| 409 | +Software Foundation; we sometimes make exceptions for this. Our | |
| 410 | +decision will be guided by the two goals of preserving the free status | |
| 411 | +of all derivatives of our free software and of promoting the sharing | |
| 412 | +and reuse of software generally. | |
| 413 | + | |
| 414 | + NO WARRANTY | |
| 415 | + | |
| 416 | + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO | |
| 417 | +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. | |
| 418 | +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR | |
| 419 | +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY | |
| 420 | +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE | |
| 421 | +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
| 422 | +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE | |
| 423 | +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME | |
| 424 | +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. | |
| 425 | + | |
| 426 | + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN | |
| 427 | +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY | |
| 428 | +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU | |
| 429 | +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR | |
| 430 | +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE | |
| 431 | +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING | |
| 432 | +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A | |
| 433 | +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF | |
| 434 | +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | |
| 435 | +DAMAGES. | |
| 436 | + | |
| 437 | + END OF TERMS AND CONDITIONS | |
| 438 | + | |
| 439 | + Appendix: How to Apply These Terms to Your New Libraries | |
| 440 | + | |
| 441 | + If you develop a new library, and you want it to be of the greatest | |
| 442 | +possible use to the public, we recommend making it free software that | |
| 443 | +everyone can redistribute and change. You can do so by permitting | |
| 444 | +redistribution under these terms (or, alternatively, under the terms of the | |
| 445 | +ordinary General Public License). | |
| 446 | + | |
| 447 | + To apply these terms, attach the following notices to the library. It is | |
| 448 | +safest to attach them to the start of each source file to most effectively | |
| 449 | +convey the exclusion of warranty; and each file should have at least the | |
| 450 | +"copyright" line and a pointer to where the full notice is found. | |
| 451 | + | |
| 452 | + <one line to give the library's name and a brief idea of what it does.> | |
| 453 | + Copyright (C) <year> <name of author> | |
| 454 | + | |
| 455 | + This library is free software; you can redistribute it and/or | |
| 456 | + modify it under the terms of the GNU Library General Public | |
| 457 | + License as published by the Free Software Foundation; either | |
| 458 | + version 2 of the License, or (at your option) any later version. | |
| 459 | + | |
| 460 | + This library is distributed in the hope that it will be useful, | |
| 461 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 462 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 463 | + Library General Public License for more details. | |
| 464 | + | |
| 465 | + You should have received a copy of the GNU Library General Public | |
| 466 | + License along with this library; if not, write to the Free | |
| 467 | + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
| 468 | + | |
| 469 | +Also add information on how to contact you by electronic and paper mail. | |
| 470 | + | |
| 471 | +You should also get your employer (if you work as a programmer) or your | |
| 472 | +school, if any, to sign a "copyright disclaimer" for the library, if | |
| 473 | +necessary. Here is a sample; alter the names: | |
| 474 | + | |
| 475 | + Yoyodyne, Inc., hereby disclaims all copyright interest in the | |
| 476 | + library `Frob' (a library for tweaking knobs) written by James Random Hacker. | |
| 477 | + | |
| 478 | + <signature of Ty Coon>, 1 April 1990 | |
| 479 | + Ty Coon, President of Vice | |
| 480 | + | |
| 481 | +That's all there is to it! | ... | ... |
ChangeLog
0 → 100644
| 1 | +++ a/ChangeLog | ... | ... |
INSTALL
0 → 100644
| 1 | +++ a/INSTALL | |
| 1 | +Installation Instructions | |
| 2 | +************************* | |
| 3 | + | |
| 4 | +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004 Free | |
| 5 | +Software Foundation, Inc. | |
| 6 | + | |
| 7 | +This file is free documentation; the Free Software Foundation gives | |
| 8 | +unlimited permission to copy, distribute and modify it. | |
| 9 | + | |
| 10 | +Basic Installation | |
| 11 | +================== | |
| 12 | + | |
| 13 | +These are generic installation instructions. | |
| 14 | + | |
| 15 | + The `configure' shell script attempts to guess correct values for | |
| 16 | +various system-dependent variables used during compilation. It uses | |
| 17 | +those values to create a `Makefile' in each directory of the package. | |
| 18 | +It may also create one or more `.h' files containing system-dependent | |
| 19 | +definitions. Finally, it creates a shell script `config.status' that | |
| 20 | +you can run in the future to recreate the current configuration, and a | |
| 21 | +file `config.log' containing compiler output (useful mainly for | |
| 22 | +debugging `configure'). | |
| 23 | + | |
| 24 | + It can also use an optional file (typically called `config.cache' | |
| 25 | +and enabled with `--cache-file=config.cache' or simply `-C') that saves | |
| 26 | +the results of its tests to speed up reconfiguring. (Caching is | |
| 27 | +disabled by default to prevent problems with accidental use of stale | |
| 28 | +cache files.) | |
| 29 | + | |
| 30 | + If you need to do unusual things to compile the package, please try | |
| 31 | +to figure out how `configure' could check whether to do them, and mail | |
| 32 | +diffs or instructions to the address given in the `README' so they can | |
| 33 | +be considered for the next release. If you are using the cache, and at | |
| 34 | +some point `config.cache' contains results you don't want to keep, you | |
| 35 | +may remove or edit it. | |
| 36 | + | |
| 37 | + The file `configure.ac' (or `configure.in') is used to create | |
| 38 | +`configure' by a program called `autoconf'. You only need | |
| 39 | +`configure.ac' if you want to change it or regenerate `configure' using | |
| 40 | +a newer version of `autoconf'. | |
| 41 | + | |
| 42 | +The simplest way to compile this package is: | |
| 43 | + | |
| 44 | + 1. `cd' to the directory containing the package's source code and type | |
| 45 | + `./configure' to configure the package for your system. If you're | |
| 46 | + using `csh' on an old version of System V, you might need to type | |
| 47 | + `sh ./configure' instead to prevent `csh' from trying to execute | |
| 48 | + `configure' itself. | |
| 49 | + | |
| 50 | + Running `configure' takes awhile. While running, it prints some | |
| 51 | + messages telling which features it is checking for. | |
| 52 | + | |
| 53 | + 2. Type `make' to compile the package. | |
| 54 | + | |
| 55 | + 3. Optionally, type `make check' to run any self-tests that come with | |
| 56 | + the package. | |
| 57 | + | |
| 58 | + 4. Type `make install' to install the programs and any data files and | |
| 59 | + documentation. | |
| 60 | + | |
| 61 | + 5. You can remove the program binaries and object files from the | |
| 62 | + source code directory by typing `make clean'. To also remove the | |
| 63 | + files that `configure' created (so you can compile the package for | |
| 64 | + a different kind of computer), type `make distclean'. There is | |
| 65 | + also a `make maintainer-clean' target, but that is intended mainly | |
| 66 | + for the package's developers. If you use it, you may have to get | |
| 67 | + all sorts of other programs in order to regenerate files that came | |
| 68 | + with the distribution. | |
| 69 | + | |
| 70 | +Compilers and Options | |
| 71 | +===================== | |
| 72 | + | |
| 73 | +Some systems require unusual options for compilation or linking that the | |
| 74 | +`configure' script does not know about. Run `./configure --help' for | |
| 75 | +details on some of the pertinent environment variables. | |
| 76 | + | |
| 77 | + You can give `configure' initial values for configuration parameters | |
| 78 | +by setting variables in the command line or in the environment. Here | |
| 79 | +is an example: | |
| 80 | + | |
| 81 | + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix | |
| 82 | + | |
| 83 | + *Note Defining Variables::, for more details. | |
| 84 | + | |
| 85 | +Compiling For Multiple Architectures | |
| 86 | +==================================== | |
| 87 | + | |
| 88 | +You can compile the package for more than one kind of computer at the | |
| 89 | +same time, by placing the object files for each architecture in their | |
| 90 | +own directory. To do this, you must use a version of `make' that | |
| 91 | +supports the `VPATH' variable, such as GNU `make'. `cd' to the | |
| 92 | +directory where you want the object files and executables to go and run | |
| 93 | +the `configure' script. `configure' automatically checks for the | |
| 94 | +source code in the directory that `configure' is in and in `..'. | |
| 95 | + | |
| 96 | + If you have to use a `make' that does not support the `VPATH' | |
| 97 | +variable, you have to compile the package for one architecture at a | |
| 98 | +time in the source code directory. After you have installed the | |
| 99 | +package for one architecture, use `make distclean' before reconfiguring | |
| 100 | +for another architecture. | |
| 101 | + | |
| 102 | +Installation Names | |
| 103 | +================== | |
| 104 | + | |
| 105 | +By default, `make install' will install the package's files in | |
| 106 | +`/usr/local/bin', `/usr/local/man', etc. You can specify an | |
| 107 | +installation prefix other than `/usr/local' by giving `configure' the | |
| 108 | +option `--prefix=PREFIX'. | |
| 109 | + | |
| 110 | + You can specify separate installation prefixes for | |
| 111 | +architecture-specific files and architecture-independent files. If you | |
| 112 | +give `configure' the option `--exec-prefix=PREFIX', the package will | |
| 113 | +use PREFIX as the prefix for installing programs and libraries. | |
| 114 | +Documentation and other data files will still use the regular prefix. | |
| 115 | + | |
| 116 | + In addition, if you use an unusual directory layout you can give | |
| 117 | +options like `--bindir=DIR' to specify different values for particular | |
| 118 | +kinds of files. Run `configure --help' for a list of the directories | |
| 119 | +you can set and what kinds of files go in them. | |
| 120 | + | |
| 121 | + If the package supports it, you can cause programs to be installed | |
| 122 | +with an extra prefix or suffix on their names by giving `configure' the | |
| 123 | +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. | |
| 124 | + | |
| 125 | +Optional Features | |
| 126 | +================= | |
| 127 | + | |
| 128 | +Some packages pay attention to `--enable-FEATURE' options to | |
| 129 | +`configure', where FEATURE indicates an optional part of the package. | |
| 130 | +They may also pay attention to `--with-PACKAGE' options, where PACKAGE | |
| 131 | +is something like `gnu-as' or `x' (for the X Window System). The | |
| 132 | +`README' should mention any `--enable-' and `--with-' options that the | |
| 133 | +package recognizes. | |
| 134 | + | |
| 135 | + For packages that use the X Window System, `configure' can usually | |
| 136 | +find the X include and library files automatically, but if it doesn't, | |
| 137 | +you can use the `configure' options `--x-includes=DIR' and | |
| 138 | +`--x-libraries=DIR' to specify their locations. | |
| 139 | + | |
| 140 | +Specifying the System Type | |
| 141 | +========================== | |
| 142 | + | |
| 143 | +There may be some features `configure' cannot figure out automatically, | |
| 144 | +but needs to determine by the type of machine the package will run on. | |
| 145 | +Usually, assuming the package is built to be run on the _same_ | |
| 146 | +architectures, `configure' can figure that out, but if it prints a | |
| 147 | +message saying it cannot guess the machine type, give it the | |
| 148 | +`--build=TYPE' option. TYPE can either be a short name for the system | |
| 149 | +type, such as `sun4', or a canonical name which has the form: | |
| 150 | + | |
| 151 | + CPU-COMPANY-SYSTEM | |
| 152 | + | |
| 153 | +where SYSTEM can have one of these forms: | |
| 154 | + | |
| 155 | + OS KERNEL-OS | |
| 156 | + | |
| 157 | + See the file `config.sub' for the possible values of each field. If | |
| 158 | +`config.sub' isn't included in this package, then this package doesn't | |
| 159 | +need to know the machine type. | |
| 160 | + | |
| 161 | + If you are _building_ compiler tools for cross-compiling, you should | |
| 162 | +use the `--target=TYPE' option to select the type of system they will | |
| 163 | +produce code for. | |
| 164 | + | |
| 165 | + If you want to _use_ a cross compiler, that generates code for a | |
| 166 | +platform different from the build platform, you should specify the | |
| 167 | +"host" platform (i.e., that on which the generated programs will | |
| 168 | +eventually be run) with `--host=TYPE'. | |
| 169 | + | |
| 170 | +Sharing Defaults | |
| 171 | +================ | |
| 172 | + | |
| 173 | +If you want to set default values for `configure' scripts to share, you | |
| 174 | +can create a site shell script called `config.site' that gives default | |
| 175 | +values for variables like `CC', `cache_file', and `prefix'. | |
| 176 | +`configure' looks for `PREFIX/share/config.site' if it exists, then | |
| 177 | +`PREFIX/etc/config.site' if it exists. Or, you can set the | |
| 178 | +`CONFIG_SITE' environment variable to the location of the site script. | |
| 179 | +A warning: not all `configure' scripts look for a site script. | |
| 180 | + | |
| 181 | +Defining Variables | |
| 182 | +================== | |
| 183 | + | |
| 184 | +Variables not defined in a site shell script can be set in the | |
| 185 | +environment passed to `configure'. However, some packages may run | |
| 186 | +configure again during the build, and the customized values of these | |
| 187 | +variables may be lost. In order to avoid this problem, you should set | |
| 188 | +them in the `configure' command line, using `VAR=value'. For example: | |
| 189 | + | |
| 190 | + ./configure CC=/usr/local2/bin/gcc | |
| 191 | + | |
| 192 | +will cause the specified gcc to be used as the C compiler (unless it is | |
| 193 | +overridden in the site shell script). | |
| 194 | + | |
| 195 | +`configure' Invocation | |
| 196 | +====================== | |
| 197 | + | |
| 198 | +`configure' recognizes the following options to control how it operates. | |
| 199 | + | |
| 200 | +`--help' | |
| 201 | +`-h' | |
| 202 | + Print a summary of the options to `configure', and exit. | |
| 203 | + | |
| 204 | +`--version' | |
| 205 | +`-V' | |
| 206 | + Print the version of Autoconf used to generate the `configure' | |
| 207 | + script, and exit. | |
| 208 | + | |
| 209 | +`--cache-file=FILE' | |
| 210 | + Enable the cache: use and save the results of the tests in FILE, | |
| 211 | + traditionally `config.cache'. FILE defaults to `/dev/null' to | |
| 212 | + disable caching. | |
| 213 | + | |
| 214 | +`--config-cache' | |
| 215 | +`-C' | |
| 216 | + Alias for `--cache-file=config.cache'. | |
| 217 | + | |
| 218 | +`--quiet' | |
| 219 | +`--silent' | |
| 220 | +`-q' | |
| 221 | + Do not print messages saying which checks are being made. To | |
| 222 | + suppress all normal output, redirect it to `/dev/null' (any error | |
| 223 | + messages will still be shown). | |
| 224 | + | |
| 225 | +`--srcdir=DIR' | |
| 226 | + Look for the package's source code in directory DIR. Usually | |
| 227 | + `configure' can determine that directory automatically. | |
| 228 | + | |
| 229 | +`configure' also accepts some other, not widely useful, options. Run | |
| 230 | +`configure --help' for more details. | |
| 231 | + | ... | ... |
Makefile.am
0 → 100644
NEWS
0 → 100644
| 1 | +++ a/NEWS | ... | ... |
README
0 → 100644
| 1 | +++ a/README | |
| 1 | +Libmodbus is a library to send/receive data with a device which uses | |
| 2 | +ModBus protocol. This library can use a serial port or an Ethernet | |
| 3 | +connexion. | |
| 4 | + | |
| 5 | +The functions included in the library have been derived from the | |
| 6 | +Modicon Modbus Protocol Reference Guide which can be obtained from | |
| 7 | +Schneider at www.schneiderautomation.com. | |
| 8 | + | ... | ... |
autogen.sh
0 → 100755
| 1 | +++ a/autogen.sh | |
| 1 | +#!/bin/sh | |
| 2 | +# Run this to generate all the initial makefiles, etc. | |
| 3 | + | |
| 4 | +srcdir=`dirname $0` | |
| 5 | +test -z "$srcdir" && srcdir=. | |
| 6 | +ORIGDIR=`pwd` | |
| 7 | +cd $srcdir | |
| 8 | + | |
| 9 | +PROJECT=libGtkEntryMask | |
| 10 | + | |
| 11 | +DIE=0 | |
| 12 | + | |
| 13 | +have_libtool=false | |
| 14 | +if libtoolize --version < /dev/null > /dev/null 2>&1 ; then | |
| 15 | + libtool_version=`libtoolize --version | sed 's/^[^0-9]*\([0-9.][0-9.]*\).*/\1/'` | |
| 16 | + case $libtool_version in | |
| 17 | + 1.4*|1.5*) | |
| 18 | + have_libtool=true | |
| 19 | + ;; | |
| 20 | + esac | |
| 21 | +fi | |
| 22 | +if $have_libtool ; then : ; else | |
| 23 | + echo | |
| 24 | + echo "You must have libtool 1.4 installed to compile $PROJECT." | |
| 25 | + echo "Install the appropriate package for your distribution," | |
| 26 | + echo "or get the source tarball at http://ftp.gnu.org/gnu/libtool/" | |
| 27 | + DIE=1 | |
| 28 | +fi | |
| 29 | + | |
| 30 | +(autoconf --version) < /dev/null > /dev/null 2>&1 || { | |
| 31 | + echo | |
| 32 | + echo "You must have autoconf installed to compile $PROJECT." | |
| 33 | + echo "Install the appropriate package for your distribution," | |
| 34 | + echo "or get the source tarball at http://ftp.gnu.org/gnu/autoconf/" | |
| 35 | + DIE=1 | |
| 36 | +} | |
| 37 | + | |
| 38 | +if automake-1.7 --version < /dev/null > /dev/null 2>&1 ; then | |
| 39 | + AUTOMAKE=automake-1.7 | |
| 40 | + ACLOCAL=aclocal-1.7 | |
| 41 | +else | |
| 42 | + echo | |
| 43 | + echo "You must have automake 1.7.x installed to compile $PROJECT." | |
| 44 | + echo "Install the appropriate package for your distribution," | |
| 45 | + echo "or get the source tarball at http://ftp.gnu.org/gnu/automake/" | |
| 46 | + DIE=1 | |
| 47 | +fi | |
| 48 | + | |
| 49 | +if test "$DIE" -eq 1; then | |
| 50 | + exit 1 | |
| 51 | +fi | |
| 52 | + | |
| 53 | +if test -z "$AUTOGEN_SUBDIR_MODE"; then | |
| 54 | + if test -z "$*"; then | |
| 55 | + echo "I am going to run ./configure with no arguments - if you wish " | |
| 56 | + echo "to pass any to it, please specify them on the $0 command line." | |
| 57 | + fi | |
| 58 | +fi | |
| 59 | + | |
| 60 | +$ACLOCAL $ACLOCAL_FLAGS || exit 1 | |
| 61 | +libtoolize --force || exit 1 | |
| 62 | +$AUTOMAKE --add-missing || exit 1 | |
| 63 | +autoconf || exit 1 | |
| 64 | +cd $ORIGDIR | |
| 65 | + | |
| 66 | +if test -z "$AUTOGEN_SUBDIR_MODE"; then | |
| 67 | + $srcdir/configure --enable-maintainer-mode "$@" | |
| 68 | + | |
| 69 | + echo | |
| 70 | + echo "Now type 'make' to compile $PROJECT." | |
| 71 | +fi | ... | ... |
configure.ac
0 → 100644
| 1 | +++ a/configure.ac | |
| 1 | +# -*- Autoconf -*- | |
| 2 | +# Process this file with autoconf to produce a configure script. | |
| 3 | + | |
| 4 | +AC_PREREQ(2.59) | |
| 5 | +AC_INIT(libmodbus, 1.2, stephane.raimbault@free.fr) | |
| 6 | +AM_INIT_AUTOMAKE(libmodbus, 1.2.0) | |
| 7 | + | |
| 8 | +# Checks for programs. | |
| 9 | +AC_PROG_CC | |
| 10 | +AC_PROG_MAKE_SET | |
| 11 | +AC_PROG_LIBTOOL | |
| 12 | + | |
| 13 | +# Checks for libraries. | |
| 14 | +AM_PATH_GLIB_2_0(2.0.0,,AC_MSG_ERROR(libmodbus needs GLib 2.X)) | |
| 15 | + | |
| 16 | +# Checks for header files. | |
| 17 | +AC_HEADER_STDC | |
| 18 | +AC_CHECK_HEADERS([arpa/inet.h fcntl.h netinet/in.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h termio.h termios.h unistd.h]) | |
| 19 | + | |
| 20 | +# Checks for typedefs, structures, and compiler characteristics. | |
| 21 | +AC_C_CONST | |
| 22 | +AC_TYPE_SIZE_T | |
| 23 | +AC_HEADER_TIME | |
| 24 | + | |
| 25 | +# Checks for library functions. | |
| 26 | +AC_FUNC_MALLOC | |
| 27 | +AC_FUNC_SELECT_ARGTYPES | |
| 28 | +AC_CHECK_FUNCS([inet_ntoa memset select socket]) | |
| 29 | + | |
| 30 | +AC_CONFIG_FILES([ | |
| 31 | + Makefile | |
| 32 | + src/Makefile | |
| 33 | + ]) | |
| 34 | +AC_OUTPUT | ... | ... |
src/Makefile.am
0 → 100644
| 1 | +++ a/src/Makefile.am | |
| 1 | +lib_LTLIBRARIES = libmodbus.la | |
| 2 | +libmodbus_la_SOURCES = modbus.c modbus.h | |
| 3 | + | |
| 4 | +bin_PROGRAMS = test-modbus | |
| 5 | +test_modbus_SOURCES = test-modbus.c | |
| 6 | +test_modbus_INCLUDES = @GLIB_CFLAGS@ | |
| 7 | +test_modbus_LDADD = libmodbus.la @GLIB_LIBS@ | |
| 8 | + | |
| 9 | +INCLUDES = @GLIB_CFLAGS@ | |
| 10 | +LDADD = @GLIB_LIBS@ | |
| 11 | +CLEANFILES = *~ | |
| 12 | + | ... | ... |
src/modbus.c
0 → 100644
| 1 | +++ a/src/modbus.c | |
| 1 | +/* | |
| 2 | + Copyright (C) 2001-2005 Stéphane Raimbault <stephane.raimbault@free.fr> | |
| 3 | + | |
| 4 | + This library is free software; you can redistribute it and/or | |
| 5 | + modify it under the terms of the GNU Lesser General Public | |
| 6 | + License as published by the Free Software Foundation; either | |
| 7 | + version 2 of the License, or (at your option) any later version. | |
| 8 | + | |
| 9 | + This library is distributed in the hope that it will be useful, | |
| 10 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 12 | + Lesser General Public License for more details. | |
| 13 | + | |
| 14 | + You should have received a copy of the GNU Lesser General Public | |
| 15 | + License along with this library; if not, write to the Free Software | |
| 16 | + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | |
| 17 | + | |
| 18 | + The functions included here have been derived from the Modicon | |
| 19 | + Modbus Protocol Reference Guide which can be obtained from | |
| 20 | + Schneider at www.schneiderautomation.com. | |
| 21 | + | |
| 22 | + Documentation: | |
| 23 | + http://www.easysw.com/~mike/serial/serial.html | |
| 24 | +*/ | |
| 25 | + | |
| 26 | +#include <fcntl.h> | |
| 27 | +#include <stdio.h> | |
| 28 | +#include <string.h> | |
| 29 | +#include <stdlib.h> | |
| 30 | +#include <termio.h> | |
| 31 | +#include <sys/time.h> | |
| 32 | +#include <unistd.h> | |
| 33 | +#include <errno.h> | |
| 34 | +#include <glib.h> | |
| 35 | + | |
| 36 | +/* TCP */ | |
| 37 | +#include <sys/types.h> | |
| 38 | +#include <sys/socket.h> | |
| 39 | +#include <sys/ioctl.h> | |
| 40 | +#include <netinet/in.h> | |
| 41 | +#include <netinet/ip.h> | |
| 42 | +#include <netinet/tcp.h> | |
| 43 | + | |
| 44 | +#include "modbus.h" | |
| 45 | + | |
| 46 | +#define UNKNOWN_ERROR_MSG "Not defined in modbus specification" | |
| 47 | + | |
| 48 | +static const int SIZE_TAB_ERROR_MSG = 12; | |
| 49 | +static const char *TAB_ERROR_MSG[] = { | |
| 50 | + /* 0x00 */ UNKNOWN_ERROR_MSG, | |
| 51 | + /* 0x01 */ "Illegal function code", | |
| 52 | + /* 0x02 */ "Illegal data address", | |
| 53 | + /* 0x03 */ "Illegal data value", | |
| 54 | + /* 0x04 */ "Slave device or server failure", | |
| 55 | + /* 0x05 */ "Acknowledge", | |
| 56 | + /* 0x06 */ "Slave device or server busy", | |
| 57 | + /* 0x07 */ "Negative acknowledge", | |
| 58 | + /* 0x08 */ "Memory parity error", | |
| 59 | + /* 0x09 */ UNKNOWN_ERROR_MSG, | |
| 60 | + /* 0x0A */ "Gateway path unavailable", | |
| 61 | + /* 0x0B */ "Target device failed to respond" | |
| 62 | +}; | |
| 63 | + | |
| 64 | +/* Table of CRC values for high-order byte */ | |
| 65 | +static unsigned char table_crc_hi[] = { | |
| 66 | + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, | |
| 67 | + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, | |
| 68 | + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, | |
| 69 | + 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, | |
| 70 | + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, | |
| 71 | + 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, | |
| 72 | + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, | |
| 73 | + 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, | |
| 74 | + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, | |
| 75 | + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, | |
| 76 | + 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, | |
| 77 | + 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, | |
| 78 | + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, | |
| 79 | + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, | |
| 80 | + 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, | |
| 81 | + 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, | |
| 82 | + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, | |
| 83 | + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, | |
| 84 | + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, | |
| 85 | + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, | |
| 86 | + 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, | |
| 87 | + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, | |
| 88 | + 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, | |
| 89 | + 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, | |
| 90 | + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, | |
| 91 | + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 | |
| 92 | +}; | |
| 93 | + | |
| 94 | +/* Table of CRC values for low-order byte */ | |
| 95 | +static unsigned char table_crc_lo[] = { | |
| 96 | + 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, | |
| 97 | + 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, | |
| 98 | + 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, | |
| 99 | + 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, | |
| 100 | + 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, | |
| 101 | + 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, | |
| 102 | + 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, | |
| 103 | + 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, | |
| 104 | + 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, | |
| 105 | + 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, | |
| 106 | + 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, | |
| 107 | + 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, | |
| 108 | + 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, | |
| 109 | + 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, | |
| 110 | + 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, | |
| 111 | + 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, | |
| 112 | + 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, | |
| 113 | + 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, | |
| 114 | + 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, | |
| 115 | + 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, | |
| 116 | + 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, | |
| 117 | + 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, | |
| 118 | + 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, | |
| 119 | + 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, | |
| 120 | + 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, | |
| 121 | + 0x43, 0x83, 0x41, 0x81, 0x80, 0x40 | |
| 122 | +}; | |
| 123 | + | |
| 124 | +/* Local declaration */ | |
| 125 | +static int read_reg_response(modbus_param_t *mb_param, | |
| 126 | + int *data_dest, | |
| 127 | + unsigned char *query); | |
| 128 | + | |
| 129 | +static void error_treat(int ret, const char *message, modbus_param_t *mb_param) | |
| 130 | +{ | |
| 131 | + if (ret == -1) | |
| 132 | + perror(message); | |
| 133 | + g_print("\n\nERROR %s\n\n", message); | |
| 134 | + | |
| 135 | + if (mb_param->type_com == RTU) { | |
| 136 | + tcflush(mb_param->fd, TCIOFLUSH); | |
| 137 | + } else { | |
| 138 | + modbus_close(mb_param); | |
| 139 | + modbus_connect(mb_param); | |
| 140 | + } | |
| 141 | +} | |
| 142 | + | |
| 143 | +static unsigned int compute_response_size(modbus_param_t *mb_param, | |
| 144 | + unsigned char *query) | |
| 145 | +{ | |
| 146 | + int response_size_computed; | |
| 147 | + int offset; | |
| 148 | + | |
| 149 | + offset = mb_param->header_length; | |
| 150 | + | |
| 151 | + switch (query[offset + 1]) { | |
| 152 | + case 0x01: { | |
| 153 | + /* Header + nb values (code from force_multiple_coils) */ | |
| 154 | + int coil_count = (query[offset + 4] << 8) | query[offset + 5]; | |
| 155 | + response_size_computed = 3 + | |
| 156 | + (coil_count / 8) + ((coil_count % 8) ? 1 : 0); | |
| 157 | + } break; | |
| 158 | + case 0x03: | |
| 159 | + /* Header + 2 * nb values */ | |
| 160 | + response_size_computed = 3 + | |
| 161 | + 2 * (query[offset + 4] << 8 | query[offset + 5]); | |
| 162 | + break; | |
| 163 | + case 0x07: | |
| 164 | + response_size_computed = 4; | |
| 165 | + break; | |
| 166 | + default: | |
| 167 | + response_size_computed = 6; | |
| 168 | + } | |
| 169 | + | |
| 170 | + response_size_computed += offset + mb_param->checksum_size; | |
| 171 | + | |
| 172 | + return response_size_computed; | |
| 173 | +} | |
| 174 | + | |
| 175 | +/* The following functions construct the required query into | |
| 176 | + a modbus query packet */ | |
| 177 | +int build_request_packet_rtu(int slave, int function, int start_addr, | |
| 178 | + int count, unsigned char *packet) | |
| 179 | +{ | |
| 180 | + packet[0] = slave; | |
| 181 | + packet[1] = function; | |
| 182 | + packet[2] = start_addr >> 8; | |
| 183 | + packet[3] = start_addr & 0x00ff; | |
| 184 | + packet[4] = count >> 8; | |
| 185 | + packet[5] = count & 0x00ff; | |
| 186 | + | |
| 187 | + return PRESET_QUERY_SIZE_RTU; | |
| 188 | +} | |
| 189 | + | |
| 190 | +int build_request_packet_tcp(int slave, int function, int start_addr, | |
| 191 | + int count, unsigned char *packet) | |
| 192 | +{ | |
| 193 | + static unsigned short t_id = 0; | |
| 194 | + | |
| 195 | + /* Transaction ID */ | |
| 196 | + if (t_id < USHRT_MAX) | |
| 197 | + t_id++; | |
| 198 | + else | |
| 199 | + t_id = 0; | |
| 200 | + packet[0] = t_id >> 8; | |
| 201 | + packet[1] = t_id & 0x00ff; | |
| 202 | + | |
| 203 | + /* Protocol Modbus */ | |
| 204 | + packet[2] = 0; | |
| 205 | + packet[3] = 0; | |
| 206 | + | |
| 207 | + /* Length to fix later with set_packet_length_tcp (4 and 5) */ | |
| 208 | + | |
| 209 | + packet[6] = 0xFF; | |
| 210 | + packet[7] = function; | |
| 211 | + packet[8] = start_addr >> 8; | |
| 212 | + packet[9] = start_addr & 0x00ff; | |
| 213 | + packet[10] = count >> 8; | |
| 214 | + packet[11] = count & 0x00ff; | |
| 215 | + | |
| 216 | + return PRESET_QUERY_SIZE_TCP; | |
| 217 | +} | |
| 218 | + | |
| 219 | +void set_packet_length_tcp(unsigned char *packet, size_t packet_size) | |
| 220 | +{ | |
| 221 | + unsigned short mbap_length; | |
| 222 | + | |
| 223 | + /* Substract MBAP header length */ | |
| 224 | + mbap_length = packet_size - 6; | |
| 225 | + | |
| 226 | + packet[4] = mbap_length >> 8; | |
| 227 | + packet[5] = mbap_length & 0x00FF; | |
| 228 | +} | |
| 229 | + | |
| 230 | +int build_request_packet(modbus_param_t *mb_param, int slave, | |
| 231 | + int function, int start_addr, | |
| 232 | + int count, unsigned char *packet) | |
| 233 | +{ | |
| 234 | + if (mb_param->type_com == RTU) | |
| 235 | + return build_request_packet_rtu(slave, function, start_addr, | |
| 236 | + count, packet); | |
| 237 | + else | |
| 238 | + return build_request_packet_tcp(slave, function, start_addr, | |
| 239 | + count, packet); | |
| 240 | +} | |
| 241 | + | |
| 242 | +/* Fast CRC */ | |
| 243 | +static unsigned short crc16(unsigned char *buffer, | |
| 244 | + unsigned short buffer_length) | |
| 245 | +{ | |
| 246 | + unsigned char crc_hi = 0xFF; /* high CRC byte initialized */ | |
| 247 | + unsigned char crc_lo = 0xFF; /* low CRC byte initialized */ | |
| 248 | + unsigned int i; /* will index into CRC lookup */ | |
| 249 | + | |
| 250 | + /* pass through message buffer */ | |
| 251 | + while (buffer_length--) { | |
| 252 | + i = crc_hi ^ *buffer++; /* calculate the CRC */ | |
| 253 | + crc_hi = crc_lo ^ table_crc_hi[i]; | |
| 254 | + crc_lo = table_crc_lo[i]; | |
| 255 | + } | |
| 256 | + | |
| 257 | + return (crc_hi << 8 | crc_lo); | |
| 258 | +} | |
| 259 | + | |
| 260 | +/* Function to send a query out to a modbus slave */ | |
| 261 | +static int modbus_query(modbus_param_t *mb_param, unsigned char *query, | |
| 262 | + size_t query_size) | |
| 263 | +{ | |
| 264 | + int write_ret; | |
| 265 | + unsigned short s_crc; | |
| 266 | + int i; | |
| 267 | + | |
| 268 | + if (mb_param->type_com == RTU) { | |
| 269 | + s_crc = crc16(query, query_size); | |
| 270 | + query[query_size++] = s_crc >> 8; | |
| 271 | + query[query_size++] = s_crc & 0x00FF; | |
| 272 | + } else { | |
| 273 | + set_packet_length_tcp(query, query_size); | |
| 274 | + } | |
| 275 | + | |
| 276 | + if (mb_param->debug) { | |
| 277 | + g_print("\n"); | |
| 278 | + for (i = 0; i < query_size; i++) | |
| 279 | + g_print("[%.2X]", query[i]); | |
| 280 | + | |
| 281 | + g_print("\n"); | |
| 282 | + } | |
| 283 | + | |
| 284 | + if (mb_param->type_com == RTU) | |
| 285 | + write_ret = write(mb_param->fd, query, query_size); | |
| 286 | + else | |
| 287 | + write_ret = send(mb_param->fd, query, query_size, 0); | |
| 288 | + | |
| 289 | + /* Return the number of bytes written (0 to n) | |
| 290 | + or PORT_SOCKET_FAILURE on error */ | |
| 291 | + if ((write_ret == -1) || (write_ret != query_size)) { | |
| 292 | + error_treat(write_ret, "Write port/socket failure", mb_param); | |
| 293 | + write_ret = PORT_SOCKET_FAILURE; | |
| 294 | + } | |
| 295 | + | |
| 296 | + return write_ret; | |
| 297 | +} | |
| 298 | + | |
| 299 | +#define WAIT_DATA() \ | |
| 300 | +{ \ | |
| 301 | + while ((select_ret = select(mb_param->fd+1, &rfds, NULL, NULL, &tv)) == -1) { \ | |
| 302 | + if (errno == EINTR) { \ | |
| 303 | + g_print("A non blocked signal was caught\n"); \ | |
| 304 | + /* Necessary after an error */ \ | |
| 305 | + FD_ZERO(&rfds); \ | |
| 306 | + FD_SET(mb_param->fd, &rfds); \ | |
| 307 | + } else { \ | |
| 308 | + error_treat(select_ret, "Select failure", mb_param); \ | |
| 309 | + return SELECT_FAILURE; \ | |
| 310 | + } \ | |
| 311 | + } \ | |
| 312 | + \ | |
| 313 | + if (select_ret == 0) { \ | |
| 314 | + /* Call to error_treat is done later to manage exceptions */ \ | |
| 315 | + return COMM_TIME_OUT; \ | |
| 316 | + } \ | |
| 317 | +} | |
| 318 | + | |
| 319 | +/* Function to monitor for the reply from the modbus slave. | |
| 320 | + This function blocks for timeout seconds if there is no reply. | |
| 321 | + | |
| 322 | + Returns: | |
| 323 | + - error_code 0 == OK, < 0 == error | |
| 324 | + - (arg) total number of characters received. | |
| 325 | +*/ | |
| 326 | +int receive_response(modbus_param_t *mb_param, | |
| 327 | + int response_size_computed, | |
| 328 | + unsigned char *response, | |
| 329 | + int *response_size) | |
| 330 | +{ | |
| 331 | + int select_ret; | |
| 332 | + int read_ret; | |
| 333 | + fd_set rfds; | |
| 334 | + struct timeval tv; | |
| 335 | + int size_to_read; | |
| 336 | + unsigned char *p_response; | |
| 337 | + | |
| 338 | + if (mb_param->debug) | |
| 339 | + g_print("Waiting for response (%d)...\n", response_size_computed); | |
| 340 | + | |
| 341 | + /* Add a file descriptor to the set */ | |
| 342 | + FD_ZERO(&rfds); | |
| 343 | + FD_SET(mb_param->fd, &rfds); | |
| 344 | + | |
| 345 | + /* Wait for a response */ | |
| 346 | + tv.tv_sec = 0; | |
| 347 | + tv.tv_usec = TIME_OUT_BEGIN_OF_TRAME; | |
| 348 | + | |
| 349 | + WAIT_DATA(); | |
| 350 | + | |
| 351 | + /* Read the trame */ | |
| 352 | + (*response_size) = 0; | |
| 353 | + size_to_read = response_size_computed; | |
| 354 | + p_response = response; | |
| 355 | + | |
| 356 | + while (select_ret) { | |
| 357 | + if (mb_param->type_com == RTU) | |
| 358 | + read_ret = read(mb_param->fd, p_response, size_to_read); | |
| 359 | + else | |
| 360 | + read_ret = recv(mb_param->fd, p_response, size_to_read, 0); | |
| 361 | + | |
| 362 | + if (read_ret == -1) { | |
| 363 | + error_treat(read_ret, "Read port/socket failure", mb_param); | |
| 364 | + return PORT_SOCKET_FAILURE; | |
| 365 | + } else { | |
| 366 | + /* Sums bytes received */ | |
| 367 | + (*response_size) += read_ret; | |
| 368 | + | |
| 369 | + /* Display the hex code of each | |
| 370 | + * character received */ | |
| 371 | + if (mb_param->debug) { | |
| 372 | + int i; | |
| 373 | + for (i=0; i < read_ret; i++) | |
| 374 | + g_print("<%.2X>", p_response[i]); | |
| 375 | + } | |
| 376 | + /* Moves the pointer to receive other datas */ | |
| 377 | + p_response = &(p_response[read_ret]); | |
| 378 | + size_to_read = response_size_computed - (*response_size); | |
| 379 | + | |
| 380 | + if ((*response_size) > MAX_PACKET_SIZE) { | |
| 381 | + error_treat(0, "Too many datas", mb_param); | |
| 382 | + return TOO_MANY_DATAS; | |
| 383 | + } | |
| 384 | + } | |
| 385 | + | |
| 386 | + if (size_to_read > 0) { | |
| 387 | + /* If no character at the buffer wait | |
| 388 | + TIME_OUT_END_OF_TRAME before to generate an error. | |
| 389 | + */ | |
| 390 | + tv.tv_sec = 0; | |
| 391 | + tv.tv_usec = TIME_OUT_END_OF_TRAME; | |
| 392 | + | |
| 393 | + WAIT_DATA(); | |
| 394 | + } else { | |
| 395 | + /* All chars are received */ | |
| 396 | + select_ret = FALSE; | |
| 397 | + } | |
| 398 | + } | |
| 399 | + | |
| 400 | + if (mb_param->debug) | |
| 401 | + g_print("\n"); | |
| 402 | + | |
| 403 | + /* OK */ | |
| 404 | + return 0; | |
| 405 | +} | |
| 406 | + | |
| 407 | +static int check_crc16(modbus_param_t *mb_param, | |
| 408 | + unsigned char *response, | |
| 409 | + int response_size) | |
| 410 | +{ | |
| 411 | + int ret; | |
| 412 | + | |
| 413 | + if (mb_param->type_com == RTU) { | |
| 414 | + unsigned short crc_calc; | |
| 415 | + unsigned short crc_received; | |
| 416 | + unsigned char recv_crc_hi; | |
| 417 | + unsigned char recv_crc_lo; | |
| 418 | + | |
| 419 | + crc_calc = crc16(response, response_size - 2); | |
| 420 | + | |
| 421 | + recv_crc_hi = (unsigned) response[response_size - 2]; | |
| 422 | + recv_crc_lo = (unsigned) response[response_size - 1]; | |
| 423 | + | |
| 424 | + crc_received = response[response_size - 2]; | |
| 425 | + crc_received = (unsigned) crc_received << 8; | |
| 426 | + crc_received = crc_received | | |
| 427 | + (unsigned) response[response_size - 1]; | |
| 428 | + | |
| 429 | + /* Check CRC of response */ | |
| 430 | + if (crc_calc == crc_received) { | |
| 431 | + ret = TRUE; | |
| 432 | + } else { | |
| 433 | + char *message; | |
| 434 | + message = g_strdup_printf( | |
| 435 | + "invalid crc received %0X - crc_calc %0X", | |
| 436 | + crc_received, crc_calc); | |
| 437 | + error_treat(0, message, mb_param); | |
| 438 | + g_free(message); | |
| 439 | + ret = INVALID_CRC; | |
| 440 | + } | |
| 441 | + } else { | |
| 442 | + /* In TCP, CRC doesn't exist but it doesn't check | |
| 443 | + length because it's not really useful */ | |
| 444 | + ret = TRUE; | |
| 445 | + } | |
| 446 | + | |
| 447 | + return ret; | |
| 448 | +} | |
| 449 | + | |
| 450 | +/* Function to the correct response is returned and that the checksum | |
| 451 | + is correct. | |
| 452 | + | |
| 453 | + Returns: | |
| 454 | + - the numbers of values (bits or word) if success | |
| 455 | + - less than 0 for exception errors | |
| 456 | + | |
| 457 | + Note: All functions used for sending or receiving data via modbus | |
| 458 | + return these values. | |
| 459 | +*/ | |
| 460 | + | |
| 461 | +static int modbus_response(modbus_param_t *mb_param, | |
| 462 | + unsigned char *query, | |
| 463 | + unsigned char *response) | |
| 464 | +{ | |
| 465 | + int response_size; | |
| 466 | + int response_size_computed; | |
| 467 | + int offset = mb_param->header_length; | |
| 468 | + int error_code; | |
| 469 | + | |
| 470 | + response_size_computed = compute_response_size(mb_param, query); | |
| 471 | + error_code = receive_response(mb_param, response_size_computed, | |
| 472 | + response, &response_size); | |
| 473 | + if (error_code == 0) { | |
| 474 | + /* No error */ | |
| 475 | + int ret; | |
| 476 | + | |
| 477 | + ret = check_crc16(mb_param, response, response_size); | |
| 478 | + if (ret != TRUE) | |
| 479 | + return ret; | |
| 480 | + | |
| 481 | + /* Good response */ | |
| 482 | + switch (response[offset + 1]) { | |
| 483 | + case 0x01: | |
| 484 | + case 0x02: | |
| 485 | + /* Read functions 1 value = 1 byte */ | |
| 486 | + response_size = response[offset + 2]; | |
| 487 | + break; | |
| 488 | + case 0x03: | |
| 489 | + case 0x04: | |
| 490 | + /* Read functions 1 value = 2 bytes */ | |
| 491 | + response_size = response[offset + 2] / 2; | |
| 492 | + break; | |
| 493 | + case 0x0F: | |
| 494 | + case 0x10: | |
| 495 | + /* N Write functions */ | |
| 496 | + response_size = response[offset + 4] << 8 | | |
| 497 | + response[offset + 5]; | |
| 498 | + break; | |
| 499 | + case 0x11: | |
| 500 | + /* Report slave ID (bytes received) */ | |
| 501 | + break; | |
| 502 | + default: | |
| 503 | + /* 1 Write functions & others */ | |
| 504 | + response_size = 1; | |
| 505 | + } | |
| 506 | + | |
| 507 | + } else if (error_code == COMM_TIME_OUT && | |
| 508 | + response_size == offset + 3 + mb_param->checksum_size) { | |
| 509 | + /* Optimisation allowed because exception response is | |
| 510 | + the smallest trame in modbus protocol (3) so always | |
| 511 | + raise an timeout error */ | |
| 512 | + int ret; | |
| 513 | + | |
| 514 | + /* CRC */ | |
| 515 | + ret = check_crc16(mb_param, response, response_size); | |
| 516 | + if (ret != TRUE) | |
| 517 | + return ret; | |
| 518 | + | |
| 519 | + /* Check for exception response | |
| 520 | + 0x80 + function */ | |
| 521 | + if (0x80 + query[offset + 1] == response[offset + 1]) { | |
| 522 | + | |
| 523 | + if (response[offset + 2] < SIZE_TAB_ERROR_MSG) { | |
| 524 | + error_treat(0, | |
| 525 | + TAB_ERROR_MSG[response[offset + 2]], | |
| 526 | + mb_param); | |
| 527 | + /* Modbus error code (negative) */ | |
| 528 | + return -response[offset + 2]; | |
| 529 | + } else { | |
| 530 | + /* The chances are low to hit this | |
| 531 | + case but can avoid a vicious | |
| 532 | + segfault */ | |
| 533 | + char *message; | |
| 534 | + message = g_strdup_printf( | |
| 535 | + "Invalid exception code %d", | |
| 536 | + response[offset + 2]); | |
| 537 | + error_treat(0, message, mb_param); | |
| 538 | + g_free(message); | |
| 539 | + return INVALID_EXCEPTION_CODE; | |
| 540 | + } | |
| 541 | + } | |
| 542 | + } else if (error_code == COMM_TIME_OUT) { | |
| 543 | + error_treat(0, "Communication time out", mb_param); | |
| 544 | + return COMM_TIME_OUT; | |
| 545 | + } else { | |
| 546 | + return error_code; | |
| 547 | + } | |
| 548 | + | |
| 549 | + return response_size; | |
| 550 | +} | |
| 551 | + | |
| 552 | +/* Read IO status */ | |
| 553 | +static int read_io_status(modbus_param_t *mb_param, int slave, int function, | |
| 554 | + int start_addr, int count, int *data_dest) | |
| 555 | +{ | |
| 556 | + int query_size; | |
| 557 | + int query_ret; | |
| 558 | + int response_ret; | |
| 559 | + | |
| 560 | + unsigned char query[MIN_QUERY_SIZE]; | |
| 561 | + unsigned char response[MAX_PACKET_SIZE]; | |
| 562 | + | |
| 563 | + query_size = build_request_packet(mb_param, slave, function, | |
| 564 | + start_addr, count, query); | |
| 565 | + | |
| 566 | + query_ret = modbus_query(mb_param, query, query_size); | |
| 567 | + if (query_ret > 0) { | |
| 568 | + int i, temp, bit; | |
| 569 | + int pos = 0; | |
| 570 | + int processed = 0; | |
| 571 | + int offset; | |
| 572 | + int offset_length; | |
| 573 | + | |
| 574 | + response_ret = modbus_response(mb_param, query, response); | |
| 575 | + offset = mb_param->header_length; | |
| 576 | + | |
| 577 | + offset_length = offset + response_ret; | |
| 578 | + for (i = offset; i < offset_length; i++) { | |
| 579 | + /* Shift reg hi_byte to temp */ | |
| 580 | + temp = response[3 + i]; | |
| 581 | + | |
| 582 | + for (bit = 0x01; | |
| 583 | + (bit & 0xff) && (processed < count);) { | |
| 584 | + data_dest[pos++] = | |
| 585 | + (temp & bit) ? TRUE : FALSE; | |
| 586 | + processed++; | |
| 587 | + bit = bit << 1; | |
| 588 | + } | |
| 589 | + | |
| 590 | + } | |
| 591 | + } else { | |
| 592 | + response_ret = query_ret; | |
| 593 | + } | |
| 594 | + | |
| 595 | + return response_ret; | |
| 596 | +} | |
| 597 | + | |
| 598 | +/* Reads the boolean status of coils and sets the array elements | |
| 599 | + in the destination to TRUE or FALSE */ | |
| 600 | +int read_coil_status(modbus_param_t *mb_param, int slave, int start_addr, | |
| 601 | + int count, int *data_dest) | |
| 602 | +{ | |
| 603 | + int function = 0x01; | |
| 604 | + int status; | |
| 605 | + | |
| 606 | + status = read_io_status(mb_param, slave, function, start_addr, | |
| 607 | + count, data_dest); | |
| 608 | + | |
| 609 | + if (status > 0) | |
| 610 | + status = count; | |
| 611 | + | |
| 612 | + return status; | |
| 613 | +} | |
| 614 | + | |
| 615 | +/* Same as read_coil_status but reads the slaves input table */ | |
| 616 | +int read_input_status(modbus_param_t *mb_param, int slave, int start_addr, | |
| 617 | + int count, int *data_dest) | |
| 618 | +{ | |
| 619 | + int function = 0x02; | |
| 620 | + int status; | |
| 621 | + | |
| 622 | + status = read_io_status(mb_param, slave, function, start_addr, | |
| 623 | + count, data_dest); | |
| 624 | + | |
| 625 | + if (status > 0) | |
| 626 | + status = count; | |
| 627 | + | |
| 628 | + return status; | |
| 629 | +} | |
| 630 | + | |
| 631 | +/* Read the data from a modbus slave and put that data into an array */ | |
| 632 | +static int read_registers(modbus_param_t *mb_param, int slave, int function, | |
| 633 | + int start_addr, int count, int *data_dest) | |
| 634 | +{ | |
| 635 | + int query_size; | |
| 636 | + int status; | |
| 637 | + int query_ret; | |
| 638 | + unsigned char query[MIN_QUERY_SIZE]; | |
| 639 | + | |
| 640 | + query_size = build_request_packet(mb_param, slave, function, | |
| 641 | + start_addr, count, query); | |
| 642 | + | |
| 643 | + query_ret = modbus_query(mb_param, query, query_size); | |
| 644 | + if (query_ret > 0) | |
| 645 | + status = read_reg_response(mb_param, data_dest, query); | |
| 646 | + else | |
| 647 | + status = query_ret; | |
| 648 | + | |
| 649 | + return status; | |
| 650 | +} | |
| 651 | + | |
| 652 | +/* Read the holding registers in a slave and put the data into an | |
| 653 | + array */ | |
| 654 | +int read_holding_registers(modbus_param_t *mb_param, int slave, | |
| 655 | + int start_addr, int count, int *data_dest) | |
| 656 | +{ | |
| 657 | + int function = 0x03; | |
| 658 | + int status; | |
| 659 | + | |
| 660 | + if (count > MAX_READ_HOLD_REGS) { | |
| 661 | + g_print("WARNING Too many holding registers requested\n"); | |
| 662 | + count = MAX_READ_HOLD_REGS; | |
| 663 | + } | |
| 664 | + | |
| 665 | + status = read_registers(mb_param, slave, function, | |
| 666 | + start_addr, count, data_dest); | |
| 667 | + return status; | |
| 668 | +} | |
| 669 | + | |
| 670 | +/* Read the input registers in a slave and put the data into | |
| 671 | + an array */ | |
| 672 | +int read_input_registers(modbus_param_t *mb_param, int slave, | |
| 673 | + int start_addr, int count, int *data_dest) | |
| 674 | +{ | |
| 675 | + int function = 0x04; | |
| 676 | + int status; | |
| 677 | + | |
| 678 | + if (count > MAX_READ_INPUT_REGS) { | |
| 679 | + g_print("WARNING Too many input registers requested\n"); | |
| 680 | + count = MAX_READ_INPUT_REGS; | |
| 681 | + } | |
| 682 | + | |
| 683 | + status = read_registers(mb_param, slave, function, | |
| 684 | + start_addr, count, data_dest); | |
| 685 | + | |
| 686 | + return status; | |
| 687 | +} | |
| 688 | + | |
| 689 | +/* Reads the response data from a slave and puts the data into an | |
| 690 | + array */ | |
| 691 | +static int read_reg_response(modbus_param_t *mb_param, int *data_dest, | |
| 692 | + unsigned char *query) | |
| 693 | +{ | |
| 694 | + unsigned char response[MAX_PACKET_SIZE]; | |
| 695 | + int response_ret; | |
| 696 | + int offset; | |
| 697 | + int i; | |
| 698 | + | |
| 699 | + response_ret = modbus_response(mb_param, query, response); | |
| 700 | + | |
| 701 | + offset = mb_param->header_length; | |
| 702 | + | |
| 703 | + /* If response_ret is negative, the loop is jumped ! */ | |
| 704 | + for (i = 0; i < response_ret; i++) { | |
| 705 | + /* shift reg hi_byte to temp OR with lo_byte */ | |
| 706 | + data_dest[i] = response[offset + 3 + (i << 1)] << 8 | | |
| 707 | + response[offset + 4 + (i << 1)]; | |
| 708 | + } | |
| 709 | + | |
| 710 | + return response_ret; | |
| 711 | +} | |
| 712 | + | |
| 713 | +/* Gets the raw data from the input stream */ | |
| 714 | +static int preset_response(modbus_param_t *mb_param, unsigned char *query) | |
| 715 | +{ | |
| 716 | + int ret; | |
| 717 | + unsigned char response[MAX_PACKET_SIZE]; | |
| 718 | + | |
| 719 | + ret = modbus_response(mb_param, query, response); | |
| 720 | + | |
| 721 | + return ret; | |
| 722 | +} | |
| 723 | + | |
| 724 | +/* Sends a value to a register in a slave */ | |
| 725 | +static int set_single(modbus_param_t *mb_param, int slave, int function, | |
| 726 | + int addr, int value) | |
| 727 | +{ | |
| 728 | + int status; | |
| 729 | + int query_size; | |
| 730 | + int query_ret; | |
| 731 | + unsigned char query[MAX_PACKET_SIZE]; | |
| 732 | + | |
| 733 | + query_size = build_request_packet(mb_param, slave, function, | |
| 734 | + addr, value, query); | |
| 735 | + | |
| 736 | + query_ret = modbus_query(mb_param, query, query_size); | |
| 737 | + if (query_ret > 0) | |
| 738 | + status = preset_response(mb_param, query); | |
| 739 | + else | |
| 740 | + status = query_ret; | |
| 741 | + | |
| 742 | + return status; | |
| 743 | +} | |
| 744 | + | |
| 745 | + | |
| 746 | +/* Turn on or off a single coil on the slave device */ | |
| 747 | +int force_single_coil(modbus_param_t *mb_param, int slave, | |
| 748 | + int coil_addr, int state) | |
| 749 | +{ | |
| 750 | + int function = 0x05; | |
| 751 | + int status; | |
| 752 | + | |
| 753 | + if (state) | |
| 754 | + state = 0xFF00; | |
| 755 | + | |
| 756 | + status = set_single(mb_param, slave, function, coil_addr, state); | |
| 757 | + | |
| 758 | + return status; | |
| 759 | +} | |
| 760 | + | |
| 761 | +/* Sets a value in one holding register in the slave device */ | |
| 762 | +int preset_single_register(modbus_param_t *mb_param, int slave, | |
| 763 | + int reg_addr, int value) | |
| 764 | +{ | |
| 765 | + int function = 0x06; | |
| 766 | + int status; | |
| 767 | + | |
| 768 | + status = set_single(mb_param, slave, function, reg_addr, value); | |
| 769 | + | |
| 770 | + return status; | |
| 771 | +} | |
| 772 | + | |
| 773 | +/* Takes an array of ints and sets or resets the coils on a slave | |
| 774 | + appropriatly */ | |
| 775 | +int force_multiple_coils(modbus_param_t *mb_param, int slave, | |
| 776 | + int start_addr, int coil_count, | |
| 777 | + int *data_src) | |
| 778 | +{ | |
| 779 | + int function = 0x0F; | |
| 780 | + int i; | |
| 781 | + int byte_count; | |
| 782 | + int query_size; | |
| 783 | + int coil_check = 0; | |
| 784 | + int status; | |
| 785 | + int query_ret; | |
| 786 | + | |
| 787 | + unsigned char query[MAX_PACKET_SIZE]; | |
| 788 | + | |
| 789 | + if (coil_count > MAX_WRITE_COILS) { | |
| 790 | + g_print("WARNING Writing to too many coils\n"); | |
| 791 | + coil_count = MAX_WRITE_COILS; | |
| 792 | + } | |
| 793 | + | |
| 794 | + query_size = build_request_packet(mb_param, slave, function, | |
| 795 | + start_addr, coil_count, query); | |
| 796 | + byte_count = (coil_count / 8) + ((coil_count % 8) ? 1 : 0); | |
| 797 | + query[query_size++] = byte_count; | |
| 798 | + | |
| 799 | + for (i = 0; i < byte_count; i++) { | |
| 800 | + int bit; | |
| 801 | + int pos = 0; | |
| 802 | + | |
| 803 | + bit = 0x01; | |
| 804 | + query[query_size] = 0; | |
| 805 | + | |
| 806 | + while ((bit & 0xFF) && (coil_check++ < coil_count)) { | |
| 807 | + if (data_src[pos++]) | |
| 808 | + query[query_size] |= bit; | |
| 809 | + else | |
| 810 | + query[query_size] &=~ bit; | |
| 811 | + | |
| 812 | + bit = bit << 1; | |
| 813 | + } | |
| 814 | + query_size++; | |
| 815 | + } | |
| 816 | + | |
| 817 | + query_ret = modbus_query(mb_param, query, query_size); | |
| 818 | + if (query_ret > 0) | |
| 819 | + status = preset_response(mb_param, query); | |
| 820 | + else | |
| 821 | + status = query_ret; | |
| 822 | + | |
| 823 | + return status; | |
| 824 | +} | |
| 825 | + | |
| 826 | +/* Copy the values in an array to an array on the slave */ | |
| 827 | +int preset_multiple_registers(modbus_param_t *mb_param, int slave, | |
| 828 | + int start_addr, int reg_count, int *data_src) | |
| 829 | +{ | |
| 830 | + int function = 0x10; | |
| 831 | + int i; | |
| 832 | + int query_size; | |
| 833 | + int byte_count; | |
| 834 | + int status; | |
| 835 | + int query_ret; | |
| 836 | + | |
| 837 | + unsigned char query[MAX_PACKET_SIZE]; | |
| 838 | + | |
| 839 | + if (reg_count > MAX_WRITE_REGS) { | |
| 840 | + g_print("WARNING Trying to write to too many registers\n"); | |
| 841 | + reg_count = MAX_WRITE_REGS; | |
| 842 | + } | |
| 843 | + | |
| 844 | + query_size = build_request_packet(mb_param, slave, function, | |
| 845 | + start_addr, reg_count, query); | |
| 846 | + byte_count = reg_count * 2; | |
| 847 | + query[query_size++] = byte_count; | |
| 848 | + | |
| 849 | + for (i = 0; i < reg_count; i++) { | |
| 850 | + query[query_size++] = data_src[i] >> 8; | |
| 851 | + query[query_size++] = data_src[i] & 0x00FF; | |
| 852 | + } | |
| 853 | + | |
| 854 | + query_ret = modbus_query(mb_param, query, query_size); | |
| 855 | + if (query_ret > 0) | |
| 856 | + status = preset_response(mb_param, query); | |
| 857 | + else | |
| 858 | + status = query_ret; | |
| 859 | + | |
| 860 | + return status; | |
| 861 | +} | |
| 862 | + | |
| 863 | +/* Returns the slave id ! */ | |
| 864 | +int report_slave_id(modbus_param_t *mb_param, int slave, | |
| 865 | + unsigned char *data_dest) | |
| 866 | +{ | |
| 867 | + int function = 0x11; | |
| 868 | + int query_size; | |
| 869 | + int query_ret; | |
| 870 | + int response_ret; | |
| 871 | + | |
| 872 | + unsigned char query[MIN_QUERY_SIZE]; | |
| 873 | + unsigned char response[MAX_PACKET_SIZE]; | |
| 874 | + | |
| 875 | + query_size = build_request_packet(mb_param, slave, function, | |
| 876 | + 0, 0, query); | |
| 877 | + | |
| 878 | + /* start_addr and count are not used */ | |
| 879 | + query_size -= 4; | |
| 880 | + | |
| 881 | + query_ret = modbus_query(mb_param, query, query_size); | |
| 882 | + if (query_ret > 0) { | |
| 883 | + int i; | |
| 884 | + int offset; | |
| 885 | + int offset_length; | |
| 886 | + | |
| 887 | + /* Byte count, slave id, run indicator status, | |
| 888 | + additional data */ | |
| 889 | + response_ret = modbus_response(mb_param, query, response); | |
| 890 | + | |
| 891 | + offset = mb_param->header_length; | |
| 892 | + offset_length = offset + response_ret; | |
| 893 | + | |
| 894 | + for (i = offset; i < offset_length; i++) | |
| 895 | + data_dest[i] = response[i]; | |
| 896 | + } else { | |
| 897 | + response_ret = query_ret; | |
| 898 | + } | |
| 899 | + | |
| 900 | + return response_ret; | |
| 901 | +} | |
| 902 | + | |
| 903 | +/* Initialises the modbus_param_t structure for RTU */ | |
| 904 | +void modbus_init_rtu(modbus_param_t *mb_param, char *device, | |
| 905 | + int baud_i, char *parity, int data_bit, | |
| 906 | + int stop_bit) | |
| 907 | +{ | |
| 908 | + memset(mb_param, 0, sizeof(modbus_param_t)); | |
| 909 | + strcpy(mb_param->device, device); | |
| 910 | + mb_param->baud_i = baud_i; | |
| 911 | + strcpy(mb_param->parity, parity); | |
| 912 | + mb_param->debug = FALSE; | |
| 913 | + mb_param->data_bit = data_bit; | |
| 914 | + mb_param->stop_bit = stop_bit; | |
| 915 | + mb_param->type_com = RTU; | |
| 916 | + mb_param->header_length = HEADER_LENGTH_RTU; | |
| 917 | + mb_param->checksum_size = CHECKSUM_SIZE_RTU; | |
| 918 | +} | |
| 919 | + | |
| 920 | +/* Initialises the modbus_param_t structure for TCP */ | |
| 921 | +void modbus_init_tcp(modbus_param_t *mb_param, char *ip) | |
| 922 | +{ | |
| 923 | + memset(mb_param, 0, sizeof(modbus_param_t)); | |
| 924 | + strncpy(mb_param->ip, ip, sizeof(char)*16); | |
| 925 | + mb_param->type_com = TCP; | |
| 926 | + mb_param->header_length = HEADER_LENGTH_TCP; | |
| 927 | + mb_param->checksum_size = CHECKSUM_SIZE_TCP; | |
| 928 | +} | |
| 929 | + | |
| 930 | + | |
| 931 | +/* This function sets up a serial port for RTU communications to | |
| 932 | + modbus */ | |
| 933 | +static int modbus_connect_rtu(modbus_param_t *mb_param) | |
| 934 | +{ | |
| 935 | + struct termios tios; | |
| 936 | + speed_t baud_rate; | |
| 937 | + | |
| 938 | + if (mb_param->debug) { | |
| 939 | + g_print("Opening %s at %d bauds (%s)\n", | |
| 940 | + mb_param->device, mb_param->baud_i, mb_param->parity); | |
| 941 | + } | |
| 942 | + | |
| 943 | + /* The O_NOCTTY flag tells UNIX that this program doesn't want | |
| 944 | + to be the "controlling terminal" for that port. If you | |
| 945 | + don't specify this then any input (such as keyboard abort | |
| 946 | + signals and so forth) will affect your process | |
| 947 | + | |
| 948 | + Timeouts are ignored in canonical input mode or when the | |
| 949 | + NDELAY option is set on the file via open or fcntl */ | |
| 950 | + mb_param->fd = open(mb_param->device, O_RDWR | O_NOCTTY | O_NDELAY); | |
| 951 | + if (mb_param->fd < 0) { | |
| 952 | + perror("open"); | |
| 953 | + g_print("ERROR Opening device %s (no : %d)\n", | |
| 954 | + mb_param->device, errno); | |
| 955 | + return -1; | |
| 956 | + } | |
| 957 | + | |
| 958 | + /* Save */ | |
| 959 | + tcgetattr(mb_param->fd, &(mb_param->old_tios)); | |
| 960 | + | |
| 961 | + memset(&tios, 0, sizeof(struct termios)); | |
| 962 | + | |
| 963 | + /* C_ISPEED Input baud (new interface) | |
| 964 | + C_OSPEED Output baud (new interface) | |
| 965 | + */ | |
| 966 | + switch (mb_param->baud_i) { | |
| 967 | + case 110: | |
| 968 | + baud_rate = B110; | |
| 969 | + break; | |
| 970 | + case 300: | |
| 971 | + baud_rate = B300; | |
| 972 | + break; | |
| 973 | + case 600: | |
| 974 | + baud_rate = B600; | |
| 975 | + break; | |
| 976 | + case 1200: | |
| 977 | + baud_rate = B1200; | |
| 978 | + break; | |
| 979 | + case 2400: | |
| 980 | + baud_rate = B2400; | |
| 981 | + break; | |
| 982 | + case 4800: | |
| 983 | + baud_rate = B4800; | |
| 984 | + break; | |
| 985 | + case 9600: | |
| 986 | + baud_rate = B9600; | |
| 987 | + break; | |
| 988 | + case 19200: | |
| 989 | + baud_rate = B19200; | |
| 990 | + break; | |
| 991 | + case 38400: | |
| 992 | + baud_rate = B38400; | |
| 993 | + break; | |
| 994 | + case 57600: | |
| 995 | + baud_rate = B57600; | |
| 996 | + break; | |
| 997 | + case 115200: | |
| 998 | + baud_rate = B115200; | |
| 999 | + break; | |
| 1000 | + default: | |
| 1001 | + baud_rate = B9600; | |
| 1002 | + g_print("WARNING Unknown baud rate %d for %s (B9600 used)\n", | |
| 1003 | + mb_param->baud_i, mb_param->device); | |
| 1004 | + } | |
| 1005 | + | |
| 1006 | + /* Set the baud rate */ | |
| 1007 | + if ((cfsetispeed(&tios, baud_rate) < 0) || | |
| 1008 | + (cfsetospeed(&tios, baud_rate) < 0)) { | |
| 1009 | + perror("cfsetispeed/cfsetospeed\n"); | |
| 1010 | + return -1; | |
| 1011 | + } | |
| 1012 | + | |
| 1013 | + /* C_CFLAG Control options | |
| 1014 | + CLOCAL Local line - do not change "owner" of port | |
| 1015 | + CREAD Enable receiver | |
| 1016 | + */ | |
| 1017 | + tios.c_cflag |= (CREAD | CLOCAL); | |
| 1018 | + /* CSIZE, HUPCL, CRTSCTS (hardware flow control) */ | |
| 1019 | + | |
| 1020 | + /* Set data bits (5, 6, 7, 8 bits) | |
| 1021 | + CSIZE Bit mask for data bits | |
| 1022 | + */ | |
| 1023 | + tios.c_cflag &= ~CSIZE; | |
| 1024 | + switch (mb_param->data_bit) { | |
| 1025 | + case 5: | |
| 1026 | + tios.c_cflag |= CS5; | |
| 1027 | + break; | |
| 1028 | + case 6: | |
| 1029 | + tios.c_cflag |= CS6; | |
| 1030 | + break; | |
| 1031 | + case 7: | |
| 1032 | + tios.c_cflag |= CS7; | |
| 1033 | + break; | |
| 1034 | + case 8: | |
| 1035 | + default: | |
| 1036 | + tios.c_cflag |= CS8; | |
| 1037 | + break; | |
| 1038 | + } | |
| 1039 | + | |
| 1040 | + /* Stop bit (1 or 2) */ | |
| 1041 | + if (mb_param->stop_bit == 1) | |
| 1042 | + tios.c_cflag &=~ CSTOPB; | |
| 1043 | + else /* 2 */ | |
| 1044 | + tios.c_cflag |= CSTOPB; | |
| 1045 | + | |
| 1046 | + /* PARENB Enable parity bit | |
| 1047 | + PARODD Use odd parity instead of even */ | |
| 1048 | + if (strncmp(mb_param->parity, "none", 4) == 0) { | |
| 1049 | + tios.c_cflag &=~ PARENB; | |
| 1050 | + } else if (strncmp(mb_param->parity, "even", 4) == 0) { | |
| 1051 | + tios.c_cflag |= PARENB; | |
| 1052 | + tios.c_cflag &=~ PARODD; | |
| 1053 | + } else { | |
| 1054 | + /* odd */ | |
| 1055 | + tios.c_cflag |= PARENB; | |
| 1056 | + tios.c_cflag |= PARODD; | |
| 1057 | + } | |
| 1058 | + | |
| 1059 | + /* Read your man page for the meaning of all this (man | |
| 1060 | + termios). Its a bit to involved to comment here :) */ | |
| 1061 | + tios.c_line = 0; | |
| 1062 | + | |
| 1063 | + /* C_LFLAG Line options | |
| 1064 | + | |
| 1065 | + ISIG Enable SIGINTR, SIGSUSP, SIGDSUSP, and SIGQUIT signals | |
| 1066 | + ICANON Enable canonical input (else raw) | |
| 1067 | + XCASE Map uppercase \lowercase (obsolete) | |
| 1068 | + ECHO Enable echoing of input characters | |
| 1069 | + ECHOE Echo erase character as BS-SP-BS | |
| 1070 | + ECHOK Echo NL after kill character | |
| 1071 | + ECHONL Echo NL | |
| 1072 | + NOFLSH Disable flushing of input buffers after | |
| 1073 | + interrupt or quit characters | |
| 1074 | + IEXTEN Enable extended functions | |
| 1075 | + ECHOCTL Echo control characters as ^char and delete as ~? | |
| 1076 | + ECHOPRT Echo erased character as character erased | |
| 1077 | + ECHOKE BS-SP-BS entire line on line kill | |
| 1078 | + FLUSHO Output being flushed | |
| 1079 | + PENDIN Retype pending input at next read or input char | |
| 1080 | + TOSTOP Send SIGTTOU for background output | |
| 1081 | + | |
| 1082 | + Canonical input is line-oriented. Input characters are put | |
| 1083 | + into a buffer which can be edited interactively by the user | |
| 1084 | + until a CR (carriage return) or LF (line feed) character is | |
| 1085 | + received. | |
| 1086 | + | |
| 1087 | + Raw input is unprocessed. Input characters are passed | |
| 1088 | + through exactly as they are received, when they are | |
| 1089 | + received. Generally you'll deselect the ICANON, ECHO, | |
| 1090 | + ECHOE, and ISIG options when using raw input | |
| 1091 | + */ | |
| 1092 | + | |
| 1093 | + /* Raw input */ | |
| 1094 | + tios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); | |
| 1095 | + | |
| 1096 | + /* C_IFLAG Input options | |
| 1097 | + | |
| 1098 | + Constant Description | |
| 1099 | + INPCK Enable parity check | |
| 1100 | + IGNPAR Ignore parity errors | |
| 1101 | + PARMRK Mark parity errors | |
| 1102 | + ISTRIP Strip parity bits | |
| 1103 | + IXON Enable software flow control (outgoing) | |
| 1104 | + IXOFF Enable software flow control (incoming) | |
| 1105 | + IXANY Allow any character to start flow again | |
| 1106 | + IGNBRK Ignore break condition | |
| 1107 | + BRKINT Send a SIGINT when a break condition is detected | |
| 1108 | + INLCR Map NL to CR | |
| 1109 | + IGNCR Ignore CR | |
| 1110 | + ICRNL Map CR to NL | |
| 1111 | + IUCLC Map uppercase to lowercase | |
| 1112 | + IMAXBEL Echo BEL on input line too long | |
| 1113 | + */ | |
| 1114 | + if (strncmp(mb_param->parity, "none", 4) == 0) { | |
| 1115 | + tios.c_iflag &= ~INPCK; | |
| 1116 | + } else { | |
| 1117 | + tios.c_iflag |= INPCK; | |
| 1118 | + } | |
| 1119 | + | |
| 1120 | + /* Software flow control is disabled */ | |
| 1121 | + tios.c_iflag &= ~(IXON | IXOFF | IXANY); | |
| 1122 | + | |
| 1123 | + /* C_OFLAG Output options | |
| 1124 | + OPOST Postprocess output (not set = raw output) | |
| 1125 | + ONLCR Map NL to CR-NL | |
| 1126 | + | |
| 1127 | + ONCLR ant others needs OPOST to be enabled | |
| 1128 | + */ | |
| 1129 | + | |
| 1130 | + /* Raw ouput */ | |
| 1131 | + tios.c_oflag &=~ OPOST; | |
| 1132 | + | |
| 1133 | + /* C_CC Control characters | |
| 1134 | + VMIN Minimum number of characters to read | |
| 1135 | + VTIME Time to wait for data (tenths of seconds) | |
| 1136 | + | |
| 1137 | + UNIX serial interface drivers provide the ability to | |
| 1138 | + specify character and packet timeouts. Two elements of the | |
| 1139 | + c_cc array are used for timeouts: VMIN and VTIME. Timeouts | |
| 1140 | + are ignored in canonical input mode or when the NDELAY | |
| 1141 | + option is set on the file via open or fcntl. | |
| 1142 | + | |
| 1143 | + VMIN specifies the minimum number of characters to read. If | |
| 1144 | + it is set to 0, then the VTIME value specifies the time to | |
| 1145 | + wait for every character read. Note that this does not mean | |
| 1146 | + that a read call for N bytes will wait for N characters to | |
| 1147 | + come in. Rather, the timeout will apply to the first | |
| 1148 | + character and the read call will return the number of | |
| 1149 | + characters immediately available (up to the number you | |
| 1150 | + request). | |
| 1151 | + | |
| 1152 | + If VMIN is non-zero, VTIME specifies the time to wait for | |
| 1153 | + the first character read. If a character is read within the | |
| 1154 | + time given, any read will block (wait) until all VMIN | |
| 1155 | + characters are read. That is, once the first character is | |
| 1156 | + read, the serial interface driver expects to receive an | |
| 1157 | + entire packet of characters (VMIN bytes total). If no | |
| 1158 | + character is read within the time allowed, then the call to | |
| 1159 | + read returns 0. This method allows you to tell the serial | |
| 1160 | + driver you need exactly N bytes and any read call will | |
| 1161 | + return 0 or N bytes. However, the timeout only applies to | |
| 1162 | + the first character read, so if for some reason the driver | |
| 1163 | + misses one character inside the N byte packet then the read | |
| 1164 | + call could block forever waiting for additional input | |
| 1165 | + characters. | |
| 1166 | + | |
| 1167 | + VTIME specifies the amount of time to wait for incoming | |
| 1168 | + characters in tenths of seconds. If VTIME is set to 0 (the | |
| 1169 | + default), reads will block (wait) indefinitely unless the | |
| 1170 | + NDELAY option is set on the port with open or fcntl. | |
| 1171 | + */ | |
| 1172 | + /* Unused because we use open with the NDELAY option */ | |
| 1173 | + tios.c_cc[VMIN] = 0; | |
| 1174 | + tios.c_cc[VTIME] = 0; | |
| 1175 | + | |
| 1176 | + if (tcsetattr(mb_param->fd, TCSANOW, &tios) < 0) { | |
| 1177 | + perror("tcsetattr\n"); | |
| 1178 | + return -1; | |
| 1179 | + } | |
| 1180 | + | |
| 1181 | + return 0; | |
| 1182 | +} | |
| 1183 | + | |
| 1184 | +static int modbus_connect_tcp(modbus_param_t *mb_param) | |
| 1185 | +{ | |
| 1186 | + int ret; | |
| 1187 | + int option; | |
| 1188 | + struct sockaddr_in addr; | |
| 1189 | + | |
| 1190 | + addr.sin_family = AF_INET; | |
| 1191 | + addr.sin_port = htons(MODBUS_TCP_PORT); | |
| 1192 | + addr.sin_addr.s_addr = inet_addr(mb_param->ip); | |
| 1193 | + | |
| 1194 | + mb_param->fd = socket(AF_INET, SOCK_STREAM, 0); | |
| 1195 | + if (mb_param->fd < 0) { | |
| 1196 | + return mb_param->fd; | |
| 1197 | + } | |
| 1198 | + | |
| 1199 | + /* Set the TCP no delay flag */ | |
| 1200 | + /* SOL_TCP = IPPROTO_TCP */ | |
| 1201 | + option = 1; | |
| 1202 | + ret = setsockopt(mb_param->fd, SOL_TCP, TCP_NODELAY, | |
| 1203 | + (const void *)&option, sizeof(int)); | |
| 1204 | + if (ret < 0) { | |
| 1205 | + perror("setsockopt"); | |
| 1206 | + close(mb_param->fd); | |
| 1207 | + return ret; | |
| 1208 | + } | |
| 1209 | + | |
| 1210 | + /* Set the IP low delay option */ | |
| 1211 | + option = IPTOS_LOWDELAY; | |
| 1212 | + ret = setsockopt(mb_param->fd, SOL_TCP, IP_TOS, | |
| 1213 | + (const void *)&option, sizeof(int)); | |
| 1214 | + if (ret < 0) { | |
| 1215 | + perror("setsockopt"); | |
| 1216 | + close(mb_param->fd); | |
| 1217 | + return ret; | |
| 1218 | + } | |
| 1219 | + | |
| 1220 | + if (mb_param->debug) { | |
| 1221 | + g_print("Connecting to %s\n", mb_param->ip); | |
| 1222 | + } | |
| 1223 | + | |
| 1224 | + ret = connect(mb_param->fd, (struct sockaddr *)&addr, | |
| 1225 | + sizeof(struct sockaddr_in)); | |
| 1226 | + if (ret < 0) { | |
| 1227 | + perror("connect"); | |
| 1228 | + close(mb_param->fd); | |
| 1229 | + return ret; | |
| 1230 | + } | |
| 1231 | + | |
| 1232 | + return 0; | |
| 1233 | +} | |
| 1234 | + | |
| 1235 | +int modbus_connect(modbus_param_t *mb_param) | |
| 1236 | +{ | |
| 1237 | + int ret; | |
| 1238 | + | |
| 1239 | + if (mb_param->type_com == RTU) | |
| 1240 | + ret = modbus_connect_rtu(mb_param); | |
| 1241 | + else | |
| 1242 | + ret = modbus_connect_tcp(mb_param); | |
| 1243 | + | |
| 1244 | + return ret; | |
| 1245 | +} | |
| 1246 | + | |
| 1247 | +void modbus_listen_tcp(modbus_param_t *mb_param) | |
| 1248 | +{ | |
| 1249 | + int ret; | |
| 1250 | + int new_socket; | |
| 1251 | + struct sockaddr_in addr; | |
| 1252 | + int addrlen; | |
| 1253 | + | |
| 1254 | + addr.sin_family = AF_INET; | |
| 1255 | + /* The modbus port is < 1024 | |
| 1256 | + This program must be made setuid root. */ | |
| 1257 | + addr.sin_port = htons(MODBUS_TCP_PORT); | |
| 1258 | + addr.sin_addr.s_addr = INADDR_ANY; | |
| 1259 | + memset(&(addr.sin_zero), '\0', 8); | |
| 1260 | + | |
| 1261 | + new_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); | |
| 1262 | + if (new_socket < 0) { | |
| 1263 | + perror("socket"); | |
| 1264 | + exit(1); | |
| 1265 | + } else { | |
| 1266 | + g_print("Socket OK\n"); | |
| 1267 | + } | |
| 1268 | + | |
| 1269 | + ret = bind(new_socket, (struct sockaddr *)&addr, | |
| 1270 | + sizeof(struct sockaddr_in)); | |
| 1271 | + if (ret < 0) { | |
| 1272 | + perror("bind"); | |
| 1273 | + close(new_socket); | |
| 1274 | + exit(1); | |
| 1275 | + } else { | |
| 1276 | + g_print("Bind OK\n"); | |
| 1277 | + } | |
| 1278 | + | |
| 1279 | + ret = listen(new_socket, 1); | |
| 1280 | + if (ret != 0) { | |
| 1281 | + perror("listen"); | |
| 1282 | + close(new_socket); | |
| 1283 | + exit(1); | |
| 1284 | + } else { | |
| 1285 | + g_print("Listen OK\n"); | |
| 1286 | + } | |
| 1287 | + | |
| 1288 | + addrlen = sizeof(struct sockaddr_in); | |
| 1289 | + mb_param->fd = accept(new_socket, (struct sockaddr *)&addr, &addrlen); | |
| 1290 | + if (ret < 0) { | |
| 1291 | + perror("accept"); | |
| 1292 | + close(new_socket); | |
| 1293 | + exit(1); | |
| 1294 | + } else { | |
| 1295 | + unsigned char response[MAX_PACKET_SIZE]; | |
| 1296 | + int response_size; | |
| 1297 | + | |
| 1298 | + g_print("The client %s is connected\n", | |
| 1299 | + inet_ntoa(addr.sin_addr)); | |
| 1300 | + | |
| 1301 | + receive_response(mb_param, MAX_PACKET_SIZE, | |
| 1302 | + response, &response_size); | |
| 1303 | + } | |
| 1304 | + | |
| 1305 | + close(new_socket); | |
| 1306 | +} | |
| 1307 | + | |
| 1308 | +/* Close the file descriptor */ | |
| 1309 | +static void modbus_close_rtu(modbus_param_t *mb_param) | |
| 1310 | +{ | |
| 1311 | + if (tcsetattr(mb_param->fd, TCSANOW, &(mb_param->old_tios)) < 0) | |
| 1312 | + perror("tcsetattr"); | |
| 1313 | + | |
| 1314 | + close(mb_param->fd); | |
| 1315 | +} | |
| 1316 | + | |
| 1317 | +static void modbus_close_tcp(modbus_param_t *mb_param) | |
| 1318 | +{ | |
| 1319 | + shutdown(mb_param->fd, SHUT_RDWR); | |
| 1320 | + close(mb_param->fd); | |
| 1321 | +} | |
| 1322 | + | |
| 1323 | +void modbus_close(modbus_param_t *mb_param) | |
| 1324 | +{ | |
| 1325 | + if (mb_param->type_com == RTU) | |
| 1326 | + modbus_close_rtu(mb_param); | |
| 1327 | + else | |
| 1328 | + modbus_close_tcp(mb_param); | |
| 1329 | +} | |
| 1330 | + | |
| 1331 | +void modbus_set_debug(modbus_param_t *mb_param, int boolean) | |
| 1332 | +{ | |
| 1333 | + mb_param->debug = boolean; | |
| 1334 | +} | ... | ... |
src/modbus.h
0 → 100644
| 1 | +++ a/src/modbus.h | |
| 1 | +/* | |
| 2 | + Copyright (C) 2001-2005 Stéphane Raimbault <stephane.raimbault@free.fr> | |
| 3 | + | |
| 4 | + This library is free software; you can redistribute it and/or | |
| 5 | + modify it under the terms of the GNU Lesser General Public | |
| 6 | + License as published by the Free Software Foundation; either | |
| 7 | + version 2 of the License, or (at your option) any later version. | |
| 8 | + | |
| 9 | + This library is distributed in the hope that it will be useful, | |
| 10 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 12 | + Lesser General Public License for more details. | |
| 13 | + | |
| 14 | + You should have received a copy of the GNU Lesser General Public | |
| 15 | + License along with this library; if not, write to the Free Software | |
| 16 | + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | |
| 17 | + | |
| 18 | + These library of functions are designed to enable a program send and | |
| 19 | + receive data from a device that communicates using the Modbus protocol. | |
| 20 | +*/ | |
| 21 | + | |
| 22 | +#ifndef _MODBUS_H_ | |
| 23 | +#define _MODBUS_H_ | |
| 24 | + | |
| 25 | +#include <termios.h> | |
| 26 | +#include <arpa/inet.h> | |
| 27 | + | |
| 28 | +#define MODBUS_TCP_PORT 502 | |
| 29 | + | |
| 30 | +#define HEADER_LENGTH_RTU 0 | |
| 31 | +#define PRESET_QUERY_SIZE_RTU 6 | |
| 32 | + | |
| 33 | +#define HEADER_LENGTH_TCP 6 | |
| 34 | +#define PRESET_QUERY_SIZE_TCP 12 | |
| 35 | + | |
| 36 | +#define CHECKSUM_SIZE_RTU 2 | |
| 37 | +#define CHECKSUM_SIZE_TCP 0 | |
| 38 | + | |
| 39 | +/* 8 + HEADER_LENGTH_TCP */ | |
| 40 | +#define MIN_QUERY_SIZE 14 | |
| 41 | + | |
| 42 | +/* MIN_RESPONSE_LENGTH + MAX(MAX*) */ | |
| 43 | +#define MAX_PACKET_SIZE 261 | |
| 44 | + | |
| 45 | +#define MAX_READ_STATUS 800 | |
| 46 | +#define MAX_READ_HOLD_REGS 100 | |
| 47 | +#define MAX_READ_INPUT_REGS 100 | |
| 48 | +#define MAX_WRITE_COILS 800 | |
| 49 | +#define MAX_WRITE_REGS 100 | |
| 50 | + | |
| 51 | +#define REPORT_SLAVE_ID_SIZE 75 | |
| 52 | + | |
| 53 | +/* Time out between trames in microsecond */ | |
| 54 | +#define TIME_OUT_BEGIN_OF_TRAME 500000 | |
| 55 | +#define TIME_OUT_END_OF_TRAME 500000 | |
| 56 | + | |
| 57 | +#ifndef FALSE | |
| 58 | +#define FALSE 0 | |
| 59 | +#endif | |
| 60 | + | |
| 61 | +#ifndef TRUE | |
| 62 | +#define TRUE 1 | |
| 63 | +#endif | |
| 64 | + | |
| 65 | +/* Protocol exceptions */ | |
| 66 | +#define ILLEGAL_FUNCTION -0x01 | |
| 67 | +#define ILLEGAL_DATA_ADDRESS -0x02 | |
| 68 | +#define ILLEGAL_DATA_VALUE -0x03 | |
| 69 | +#define SLAVE_DEVICE_FAILURE -0x04 | |
| 70 | +#define SERVER_FAILURE -0x04 | |
| 71 | +#define ACKNOWLEDGE -0x05 | |
| 72 | +#define SLAVE_DEVICE_BUSY -0x06 | |
| 73 | +#define SERVER_BUSY -0x06 | |
| 74 | +#define NEGATIVE_ACKNOWLEDGE -0x07 | |
| 75 | +#define MEMORY_PARITY_ERROR -0x08 | |
| 76 | +#define GATEWAY_PROBLEM_PATH -0x0A | |
| 77 | +#define GATEWAY_PROBLEM_TARGET -0x0B | |
| 78 | + | |
| 79 | +/* Local */ | |
| 80 | +#define COMM_TIME_OUT -0x0C | |
| 81 | +#define PORT_SOCKET_FAILURE -0x0D | |
| 82 | +#define SELECT_FAILURE -0x0E | |
| 83 | +#define TOO_MANY_DATAS -0x0F | |
| 84 | +#define INVALID_CRC -0x10 | |
| 85 | +#define INVALID_EXCEPTION_CODE -0x11 | |
| 86 | + | |
| 87 | +typedef enum { RTU, TCP } type_com_t; | |
| 88 | + | |
| 89 | +typedef struct _modbus_param_t { | |
| 90 | + /* Communication : RTU or TCP */ | |
| 91 | + type_com_t type_com; | |
| 92 | + /* Device: "/dev/ttyS0" */ | |
| 93 | + char device[11]; | |
| 94 | + /* Bauds: 19200 */ | |
| 95 | + int baud_i; | |
| 96 | + /* Parity: "even", "odd", "none" */ | |
| 97 | + char parity[5]; | |
| 98 | + /* Data bit */ | |
| 99 | + int data_bit; | |
| 100 | + /* Stop bit */ | |
| 101 | + int stop_bit; | |
| 102 | + /* Save old termios settings */ | |
| 103 | + struct termios old_tios; | |
| 104 | + /* Descriptor (tty or socket) */ | |
| 105 | + int fd; | |
| 106 | + /* Flag debug */ | |
| 107 | + int debug; | |
| 108 | + /* IP address */ | |
| 109 | + char ip[16]; | |
| 110 | + /* Header length used for offset */ | |
| 111 | + int header_length; | |
| 112 | + /* Checksum size RTU = 2 and TCP = 0 */ | |
| 113 | + int checksum_size; | |
| 114 | +} modbus_param_t; | |
| 115 | + | |
| 116 | +/* All functions used for sending or receiving data return : | |
| 117 | + - the numbers of values (bits or word) if success (0 or more) | |
| 118 | + - less than 0 for exceptions errors | |
| 119 | +*/ | |
| 120 | + | |
| 121 | +/* Reads the boolean status of coils and sets the array elements in | |
| 122 | + the destination to TRUE or FALSE */ | |
| 123 | +int read_coil_status(modbus_param_t *mb_param, int slave, | |
| 124 | + int start_addr, int count, int *dest); | |
| 125 | + | |
| 126 | +/* Same as read_coil_status but reads the slaves input table */ | |
| 127 | +int read_input_status(modbus_param_t *mb_param, int slave, | |
| 128 | + int start_addr, int count, int *dest); | |
| 129 | + | |
| 130 | +/* Read the holding registers in a slave and put the data into an | |
| 131 | + array */ | |
| 132 | +int read_holding_registers(modbus_param_t *mb_param, int slave, | |
| 133 | + int start_addr, int count, int *dest); | |
| 134 | + | |
| 135 | + | |
| 136 | +/* Read the input registers in a slave and put the data into an | |
| 137 | + array */ | |
| 138 | +int read_input_registers(modbus_param_t *mb_param, int slave, | |
| 139 | + int start_addr, int count, int *dest); | |
| 140 | + | |
| 141 | +/* Turn on or off a single coil on the slave device */ | |
| 142 | +int force_single_coil(modbus_param_t *mb_param, int slave, | |
| 143 | + int coil_addr, int state); | |
| 144 | + | |
| 145 | +/* Sets a value in one holding register in the slave device */ | |
| 146 | +int preset_single_register(modbus_param_t *mb_param, int slave, | |
| 147 | + int reg_addr, int value); | |
| 148 | + | |
| 149 | +/* Takes an array of ints and sets or resets the coils on a slave | |
| 150 | + appropriatly */ | |
| 151 | +int force_multiple_coils(modbus_param_t *mb_param, int slave, | |
| 152 | + int start_addr, int coil_count, int *data); | |
| 153 | + | |
| 154 | +/* Copy the values in an array to an array on the slave */ | |
| 155 | +int preset_multiple_registers(modbus_param_t *mb_param, int slave, | |
| 156 | + int start_addr, int reg_count, int *data); | |
| 157 | + | |
| 158 | +/* Returns some useful information about the modbus controller */ | |
| 159 | +int report_slave_id(modbus_param_t *mb_param, int slave, | |
| 160 | + unsigned char *dest); | |
| 161 | + | |
| 162 | +/* Initialises a parameters structure | |
| 163 | + - device : "/dev/ttyS0" | |
| 164 | + - baud : 19200 | |
| 165 | + - parity : "even", "odd" or "none" | |
| 166 | + - data_bits : 5, 6, 7, 8 | |
| 167 | + - stop_bits : 1, 2 | |
| 168 | +*/ | |
| 169 | +void modbus_init_rtu(modbus_param_t *mb_param, char *device, | |
| 170 | + int baud, char *parity, int data_bit, | |
| 171 | + int stop_bit); | |
| 172 | +/* Initialises a parameters structure for TCP | |
| 173 | + - ip : "192.168.0.5" */ | |
| 174 | +void modbus_init_tcp(modbus_param_t *mb_param, char *ip_address); | |
| 175 | + | |
| 176 | + | |
| 177 | +/* This function sets up a serial port for RTU communications to | |
| 178 | + modbus or a TCP connexion */ | |
| 179 | +int modbus_connect(modbus_param_t *mb_param); | |
| 180 | + | |
| 181 | +/* This function closes the serial port and restores the previous port | |
| 182 | + configuration or close the TCP connexion */ | |
| 183 | +void modbus_close(modbus_param_t *mb_param); | |
| 184 | + | |
| 185 | +/* Set in debug mode */ | |
| 186 | +void modbus_set_debug(modbus_param_t *mb_param, int boolean); | |
| 187 | + | |
| 188 | +/* Useful for a 'daemon' */ | |
| 189 | +void modbus_listen_tcp(modbus_param_t *mb_param); | |
| 190 | + | |
| 191 | +/* Non implemented : | |
| 192 | + - read_exception_status() | |
| 193 | +*/ | |
| 194 | + | |
| 195 | +/* Find out what a master is trying to ask this slave device */ | |
| 196 | +int get_slave_query_tcp(modbus_param_t *mb_param, int *slave_addr, int *query, | |
| 197 | + int *start_addr, int *point_count, int *data); | |
| 198 | + | |
| 199 | +#endif /* _MODBUS_H_ */ | ... | ... |
src/test-modbus.c
0 → 100644
| 1 | +++ a/src/test-modbus.c | |
| 1 | +/* | |
| 2 | + Copyright (C) 2001-2005 Stéphane Raimbault <stephane.raimbault@free.fr> | |
| 3 | + | |
| 4 | + This library is free software; you can redistribute it and/or | |
| 5 | + modify it under the terms of the GNU Lesser General Public | |
| 6 | + License as published by the Free Software Foundation; either | |
| 7 | + version 2 of the License, or (at your option) any later version. | |
| 8 | + | |
| 9 | + This library is distributed in the hope that it will be useful, | |
| 10 | + but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 12 | + Lesser General Public License for more details. | |
| 13 | + | |
| 14 | + You should have received a copy of the GNU Lesser General Public | |
| 15 | + License along with this library; if not, write to the Free Software | |
| 16 | + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | |
| 17 | + | |
| 18 | + These library of functions are designed to enable a program send and | |
| 19 | + receive data from a device that communicates using the Modbus protocol. | |
| 20 | +*/ | |
| 21 | + | |
| 22 | +#include <stdio.h> | |
| 23 | +#include <unistd.h> | |
| 24 | +#include <string.h> | |
| 25 | +#include <stdlib.h> | |
| 26 | + | |
| 27 | +#include <modbus.h> | |
| 28 | + | |
| 29 | +#define LOOP 1 | |
| 30 | +#define SLAVE 1 | |
| 31 | +#define ADDR_MIN 100 | |
| 32 | +#define ADDR_MAX 150 | |
| 33 | +#define FIELDS 50 | |
| 34 | + | |
| 35 | +int main(void) | |
| 36 | +{ | |
| 37 | + int ok, fail; | |
| 38 | + int loop_nb; | |
| 39 | + int addr; | |
| 40 | + int field_nb; | |
| 41 | + int *tab_rq; | |
| 42 | + int *tab_rq_bits; | |
| 43 | + int *tab_rp; | |
| 44 | + modbus_param_t mb_param; | |
| 45 | + | |
| 46 | + /* RTU parity : none, even, odd */ | |
| 47 | +/* modbus_init_rtu(&mb_param, "/dev/ttyS0", 19200, "none", 8, 1); */ | |
| 48 | + | |
| 49 | + /* TCP */ | |
| 50 | + modbus_init_tcp(&mb_param, "192.168.0.100"); | |
| 51 | + modbus_set_debug(&mb_param, TRUE); | |
| 52 | + | |
| 53 | + modbus_connect(&mb_param); | |
| 54 | + | |
| 55 | + tab_rq = (int *) malloc(FIELDS * sizeof(int)); | |
| 56 | + tab_rq_bits = (int *) malloc(FIELDS * sizeof(int)); | |
| 57 | + tab_rp = (int *) malloc(FIELDS * sizeof(int)); | |
| 58 | + | |
| 59 | + loop_nb = ok = fail = 0; | |
| 60 | + while (loop_nb++ < LOOP) { | |
| 61 | + for (addr=ADDR_MIN; addr <= ADDR_MAX; addr++) { | |
| 62 | + for (field_nb=1; field_nb<=FIELDS; field_nb++) { | |
| 63 | + int i; | |
| 64 | + | |
| 65 | + /* Random numbers (short) */ | |
| 66 | + for (i=0; i<field_nb; i++) { | |
| 67 | + tab_rq[i] = (int) (16536.0*rand()/(RAND_MAX+1.0)); | |
| 68 | + tab_rq_bits[i] = (i) % 2; | |
| 69 | + } | |
| 70 | + | |
| 71 | + /* SINGLE COIL */ | |
| 72 | + ok = force_single_coil(&mb_param, SLAVE, addr, tab_rq_bits[0]); | |
| 73 | + if (ok != 1) { | |
| 74 | + printf("ERROR force_single_coil (%d)\n", ok); | |
| 75 | + printf("Slave = %d, address = %d, value = %d\n", | |
| 76 | + SLAVE, addr, tab_rq_bits[0]); | |
| 77 | + fail++; | |
| 78 | + } else { | |
| 79 | + ok = read_coil_status(&mb_param, SLAVE, addr, 1, tab_rp); | |
| 80 | + if (ok != 1 || tab_rq_bits[0] != tab_rp[0]) { | |
| 81 | + printf("ERROR read_coil_status single (%d)\n", ok); | |
| 82 | + printf("Slave = %d, address = %d\n", | |
| 83 | + SLAVE, addr); | |
| 84 | + fail++; | |
| 85 | + } | |
| 86 | + } | |
| 87 | + | |
| 88 | + /* MULTIPLE COILS */ | |
| 89 | + ok = force_multiple_coils(&mb_param, SLAVE, addr, field_nb, tab_rq_bits); | |
| 90 | + if (ok != field_nb) { | |
| 91 | + printf("ERROR force_multiple_coils (%d)\n", ok); | |
| 92 | + printf("Slave = %d, address = %d, field_nb = %d\n", | |
| 93 | + SLAVE, addr, field_nb); | |
| 94 | + fail++; | |
| 95 | + } else { | |
| 96 | + ok = read_coil_status(&mb_param, SLAVE, addr, | |
| 97 | + field_nb, tab_rp); | |
| 98 | + if (ok != field_nb) { | |
| 99 | + printf("ERROR read_coil_status\n"); | |
| 100 | + printf("Slave = %d, address = %d, field_nb = %d\n", | |
| 101 | + SLAVE, addr, field_nb); | |
| 102 | + fail++; | |
| 103 | + } else { | |
| 104 | + for (i=0; i<field_nb; i++) { | |
| 105 | + if (tab_rp[i] != tab_rq_bits[i]) { | |
| 106 | + printf("ERROR read_coil_status "); | |
| 107 | + printf("(%d != %d)\n", tab_rp[i], tab_rq_bits[i]); | |
| 108 | + printf("Slave = %d, address = %d\n", | |
| 109 | + SLAVE, addr); | |
| 110 | + fail++; | |
| 111 | + } | |
| 112 | + } | |
| 113 | + } | |
| 114 | + } | |
| 115 | + | |
| 116 | + /* SINGLE REGISTER */ | |
| 117 | + ok = preset_single_register(&mb_param, SLAVE, addr, tab_rq[0]); | |
| 118 | + if (ok != 1) { | |
| 119 | + printf("ERROR preset_single_register (%d)\n", ok); | |
| 120 | + printf("Slave = %d, address = %d, value = %d\n", | |
| 121 | + SLAVE, addr, tab_rq[0]); | |
| 122 | + fail++; | |
| 123 | + } else { | |
| 124 | + ok = read_holding_registers(&mb_param, SLAVE, | |
| 125 | + addr, 1, tab_rp); | |
| 126 | + if (ok != 1) { | |
| 127 | + printf("ERROR read_holding_registers single (%d)\n", ok); | |
| 128 | + printf("Slave = %d, address = %d\n", | |
| 129 | + SLAVE, addr); | |
| 130 | + fail++; | |
| 131 | + } else { | |
| 132 | + if (tab_rq[0] != tab_rp[0]) { | |
| 133 | + printf("ERROR read_holding_registers single "); | |
| 134 | + printf("(%d != %d)\n", | |
| 135 | + tab_rq[0], tab_rp[0]); | |
| 136 | + printf("Slave = %d, address = %d\n", | |
| 137 | + SLAVE, addr); | |
| 138 | + fail++; | |
| 139 | + } | |
| 140 | + } | |
| 141 | + } | |
| 142 | + | |
| 143 | + /* MULTIPLE REGISTERS */ | |
| 144 | + ok = preset_multiple_registers(&mb_param, SLAVE, | |
| 145 | + addr, field_nb, tab_rq); | |
| 146 | + if (ok != field_nb) { | |
| 147 | + printf("ERROR preset_multiple_registers (%d)\n", ok); | |
| 148 | + printf("Slave = %d, address = %d, field_nb = %d\n", | |
| 149 | + SLAVE, addr, field_nb); | |
| 150 | + fail++; | |
| 151 | + } else { | |
| 152 | + ok = read_holding_registers(&mb_param, SLAVE, | |
| 153 | + addr, field_nb, tab_rp); | |
| 154 | + if (ok != field_nb) { | |
| 155 | + printf("ERROR read_holding_registers (%d)\n", ok); | |
| 156 | + printf("Slave = %d, address = %d, field_nb = %d\n", | |
| 157 | + SLAVE, addr, field_nb); | |
| 158 | + fail++; | |
| 159 | + } else { | |
| 160 | + for (i=0; i<field_nb; i++) { | |
| 161 | + if (tab_rq[i] != tab_rp[i]) { | |
| 162 | + printf("ERROR read_holding_registers "); | |
| 163 | + printf("(%d != %d)\n", | |
| 164 | + tab_rq[i], tab_rp[i]); | |
| 165 | + printf("Slave = %d, address = %d\n", | |
| 166 | + SLAVE, addr); | |
| 167 | + fail++; | |
| 168 | + } | |
| 169 | + } | |
| 170 | + } | |
| 171 | + } | |
| 172 | + } | |
| 173 | + | |
| 174 | + if (fail) | |
| 175 | + printf("Address : %d - Fails sum : %d\n", addr, fail); | |
| 176 | + else | |
| 177 | + printf("Address : %d - OK\n", addr); | |
| 178 | + } | |
| 179 | + } | |
| 180 | + | |
| 181 | + free(tab_rp); | |
| 182 | + free(tab_rq); | |
| 183 | + free(tab_rq_bits); | |
| 184 | + modbus_close(&mb_param); | |
| 185 | + | |
| 186 | + return 0; | |
| 187 | +} | |
| 188 | + | ... | ... |