├── AUTHORS ├── BUGS ├── COPYING ├── ChangeLog ├── Doxyfile ├── INSTALL ├── Makefile.am ├── NEWS ├── README ├── README.debian ├── TODO ├── artnet ├── Makefile.am ├── artnet.c ├── artnet.h ├── common.h ├── misc.c ├── misc.h ├── network.c ├── packets.h ├── private.h ├── receive.c ├── tod.c ├── tod.h └── transmit.c ├── config.h.in ├── configure.in ├── debian ├── Makefile.am ├── changelog ├── compat ├── control ├── copyright ├── docs ├── libartnet-dev.install ├── libartnet1.install ├── libartnet1.postinst ├── libartnet1.postrm └── rules ├── libartnet.config ├── libartnet.creator ├── libartnet.files ├── libartnet.includes └── libartnet.pc.in /AUTHORS: -------------------------------------------------------------------------------- 1 | 2 | Author: 3 | 4 | Simon Newton 5 | 6 | Bug Reports & Patches: 7 | 8 | Samuli Valo 9 | Justin Cormack 10 | nico (Win32 port) 11 | -------------------------------------------------------------------------------- /BUGS: -------------------------------------------------------------------------------- 1 | 2 | * ip address set to 2.0.0.99 in ArtPollReply 3 | * mac address set to 00-00-00-00-00-00-00-00 in ArtPollReply 4 | * ArtInput (on Receive Tab) is broadcast to (2.255.255.255), spec says broadcasting is not allowed. Open both Viewers, windows discovers linux one, then switch to recv tab and check boxes 5 | 6 | 7 | 8 | * Missing "Art-Net\0" for RDM packet 9 | 10 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 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 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 489 | 490 | Also add information on how to contact you by electronic and paper mail. 491 | 492 | You should also get your employer (if you work as a programmer) or your 493 | school, if any, to sign a "copyright disclaimer" for the library, if 494 | necessary. Here is a sample; alter the names: 495 | 496 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 497 | library `Frob' (a library for tweaking knobs) written by James Random Hacker. 498 | 499 | , 1 April 1990 500 | Ty Coon, President of Vice 501 | 502 | That's all there is to it! 503 | 504 | 505 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 4/11/2007 Simon Newton < 2 | * Removed artnet_init 3 | * cleaned up code style 4 | * removed #defines 5 | * implemented Artnet II 6 | 7 | 25/12/2006 Simon Newton < 8 | 9 | * minor code cleanup, removed a bunch of magic numbers 10 | 11 | 24/12/2006 Simon Newton < 12 | 13 | * bug fix for OS X 14 | 15 | 12/6/2006 Simon Newton < 16 | 17 | * applied patches to network.c from Justin Cormack to skip interfaces 18 | without addresses 19 | 20 | 12/6/2006 Simon Newton < 21 | 22 | * added functions to set the oem and esta codes 23 | 24 | 9/5/2006 Simon Newton < 25 | 26 | * changed to using a single descriptor bound to *.6454 27 | 28 | 18/4/2006 Simon Newton < 29 | 30 | * Received ESTA Manufacturer ID 31 | 32 | 17/4/2006 Simon Newton < 33 | 34 | * Fixed ArtPollReply length bug 35 | 36 | 16/9/2005 Simon Newton < 37 | 38 | * Fixed compile issues on OS X 39 | 40 | 28/8/2005 Simon Newton 41 | 42 | * Fixed error handling in net_start 43 | 44 | 26/8/2005 Simon Newton 45 | 46 | * Fixed get_ifaces to return hw addrs correctly for aliased ifaces 47 | 48 | 12/8/2005 Simon Newton 49 | 50 | * Changed to a new error reporting scheme 51 | * Applied patch from Samuli Valo to fix get_ifaces on x86-64 52 | 53 | 7/05/2005 Simon Newton 54 | 55 | * fixed bug in number of ports reported 56 | * included tod.h and misc.h :) 57 | * fixed typo with IPV6 58 | * removed static path for pkgconfig data 59 | 60 | 30/04/2005 Simon Newton 61 | 62 | * minor cleanup, now reports numb of ports correctly 63 | 64 | 30/04/2005 Simon Newton 65 | 66 | * started adding RDM support 67 | 68 | 25/04/2005 Simon Newton 69 | 70 | * fixed the inet_aton bug 71 | 72 | 18/04/2005 Simon Newton 73 | 74 | * Added the endian conversion functions 75 | 76 | 12/04/2005 Simon Newton 77 | 78 | * More OSX fixes 79 | 80 | 9/04/2005 Simon Newton 81 | 82 | * Fixed the seg fault if no network interfaces are present 83 | 84 | 18/3/2005 Simon Newton 85 | 86 | * added artnet_destroy 87 | 88 | 17/3/2005 Simon Newton 89 | 90 | * added c++ linking support 91 | 92 | 16/3/2005 Simon Newton 93 | 94 | * merged bugfixes from multicast branch to trunk 95 | 96 | 27/2/2005 Simon Newton 97 | 98 | * split examples from the library 99 | * depricated artnet_init 100 | 101 | 23/2/2005 Simon Newton 102 | 103 | * added basic node joining support 104 | 105 | 12/2/2005 Simon Newton 106 | 107 | * Fixed compiler warnings 108 | * Fixed minor problems relating to a node's ip address 109 | 110 | 11/2/2005 Simon Newton 111 | 112 | * Changed the licence to the LGPL 113 | * Added new "debug" parameter to artnet_init() 114 | * Fixed LTP bug (L = latest not lowest as I orginally thought) 115 | * Added firmware receive support - new example program artnet_firmware_node 116 | * Added firmware send support - new example program artnet_firmware_server 117 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Installation Instructions 2 | ************************* 3 | 4 | Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, 5 | 2006 Free 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 | Briefly, the shell commands `./configure; make; make install' should 14 | configure, build, and install this package. The following 15 | more-detailed instructions are generic; see the `README' file for 16 | instructions specific to this package. 17 | 18 | The `configure' shell script attempts to guess correct values for 19 | various system-dependent variables used during compilation. It uses 20 | those values to create a `Makefile' in each directory of the package. 21 | It may also create one or more `.h' files containing system-dependent 22 | definitions. Finally, it creates a shell script `config.status' that 23 | you can run in the future to recreate the current configuration, and a 24 | file `config.log' containing compiler output (useful mainly for 25 | debugging `configure'). 26 | 27 | It can also use an optional file (typically called `config.cache' 28 | and enabled with `--cache-file=config.cache' or simply `-C') that saves 29 | the results of its tests to speed up reconfiguring. Caching is 30 | disabled by default to prevent problems with accidental use of stale 31 | cache files. 32 | 33 | If you need to do unusual things to compile the package, please try 34 | to figure out how `configure' could check whether to do them, and mail 35 | diffs or instructions to the address given in the `README' so they can 36 | be considered for the next release. If you are using the cache, and at 37 | some point `config.cache' contains results you don't want to keep, you 38 | may remove or edit it. 39 | 40 | The file `configure.ac' (or `configure.in') is used to create 41 | `configure' by a program called `autoconf'. You need `configure.ac' if 42 | you want to change it or regenerate `configure' using a newer version 43 | of `autoconf'. 44 | 45 | The simplest way to compile this package is: 46 | 47 | 1. `cd' to the directory containing the package's source code and type 48 | `./configure' to configure the package for your system. 49 | 50 | Running `configure' might take a while. While running, it prints 51 | some 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=c99 CFLAGS=-g 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 can use GNU `make'. `cd' to the 91 | directory where you want the object files and executables to go and run 92 | the `configure' script. `configure' automatically checks for the 93 | source code in the directory that `configure' is in and in `..'. 94 | 95 | With a non-GNU `make', it is safer to compile the package for one 96 | architecture at a time in the source code directory. After you have 97 | installed the package for one architecture, use `make distclean' before 98 | reconfiguring for another architecture. 99 | 100 | Installation Names 101 | ================== 102 | 103 | By default, `make install' installs the package's commands under 104 | `/usr/local/bin', include files under `/usr/local/include', etc. You 105 | can specify an installation prefix other than `/usr/local' by giving 106 | `configure' the option `--prefix=PREFIX'. 107 | 108 | You can specify separate installation prefixes for 109 | architecture-specific files and architecture-independent files. If you 110 | pass the option `--exec-prefix=PREFIX' to `configure', the package uses 111 | PREFIX as the prefix for installing programs and libraries. 112 | Documentation and other data files still use the regular prefix. 113 | 114 | In addition, if you use an unusual directory layout you can give 115 | options like `--bindir=DIR' to specify different values for particular 116 | kinds of files. Run `configure --help' for a list of the directories 117 | you can set and what kinds of files go in them. 118 | 119 | If the package supports it, you can cause programs to be installed 120 | with an extra prefix or suffix on their names by giving `configure' the 121 | option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. 122 | 123 | Optional Features 124 | ================= 125 | 126 | Some packages pay attention to `--enable-FEATURE' options to 127 | `configure', where FEATURE indicates an optional part of the package. 128 | They may also pay attention to `--with-PACKAGE' options, where PACKAGE 129 | is something like `gnu-as' or `x' (for the X Window System). The 130 | `README' should mention any `--enable-' and `--with-' options that the 131 | package recognizes. 132 | 133 | For packages that use the X Window System, `configure' can usually 134 | find the X include and library files automatically, but if it doesn't, 135 | you can use the `configure' options `--x-includes=DIR' and 136 | `--x-libraries=DIR' to specify their locations. 137 | 138 | Specifying the System Type 139 | ========================== 140 | 141 | There may be some features `configure' cannot figure out automatically, 142 | but needs to determine by the type of machine the package will run on. 143 | Usually, assuming the package is built to be run on the _same_ 144 | architectures, `configure' can figure that out, but if it prints a 145 | message saying it cannot guess the machine type, give it the 146 | `--build=TYPE' option. TYPE can either be a short name for the system 147 | type, such as `sun4', or a canonical name which has the form: 148 | 149 | CPU-COMPANY-SYSTEM 150 | 151 | where SYSTEM can have one of these forms: 152 | 153 | OS KERNEL-OS 154 | 155 | See the file `config.sub' for the possible values of each field. If 156 | `config.sub' isn't included in this package, then this package doesn't 157 | need to know the machine type. 158 | 159 | If you are _building_ compiler tools for cross-compiling, you should 160 | use the option `--target=TYPE' to select the type of system they will 161 | produce code for. 162 | 163 | If you want to _use_ a cross compiler, that generates code for a 164 | platform different from the build platform, you should specify the 165 | "host" platform (i.e., that on which the generated programs will 166 | eventually be run) with `--host=TYPE'. 167 | 168 | Sharing Defaults 169 | ================ 170 | 171 | If you want to set default values for `configure' scripts to share, you 172 | can create a site shell script called `config.site' that gives default 173 | values for variables like `CC', `cache_file', and `prefix'. 174 | `configure' looks for `PREFIX/share/config.site' if it exists, then 175 | `PREFIX/etc/config.site' if it exists. Or, you can set the 176 | `CONFIG_SITE' environment variable to the location of the site script. 177 | A warning: not all `configure' scripts look for a site script. 178 | 179 | Defining Variables 180 | ================== 181 | 182 | Variables not defined in a site shell script can be set in the 183 | environment passed to `configure'. However, some packages may run 184 | configure again during the build, and the customized values of these 185 | variables may be lost. In order to avoid this problem, you should set 186 | them in the `configure' command line, using `VAR=value'. For example: 187 | 188 | ./configure CC=/usr/local2/bin/gcc 189 | 190 | causes the specified `gcc' to be used as the C compiler (unless it is 191 | overridden in the site shell script). 192 | 193 | Unfortunately, this technique does not work for `CONFIG_SHELL' due to 194 | an Autoconf bug. Until the bug is fixed you can use this workaround: 195 | 196 | CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash 197 | 198 | `configure' Invocation 199 | ====================== 200 | 201 | `configure' recognizes the following options to control how it operates. 202 | 203 | `--help' 204 | `-h' 205 | Print a summary of the options to `configure', and exit. 206 | 207 | `--version' 208 | `-V' 209 | Print the version of Autoconf used to generate the `configure' 210 | script, and exit. 211 | 212 | `--cache-file=FILE' 213 | Enable the cache: use and save the results of the tests in FILE, 214 | traditionally `config.cache'. FILE defaults to `/dev/null' to 215 | disable caching. 216 | 217 | `--config-cache' 218 | `-C' 219 | Alias for `--cache-file=config.cache'. 220 | 221 | `--quiet' 222 | `--silent' 223 | `-q' 224 | Do not print messages saying which checks are being made. To 225 | suppress all normal output, redirect it to `/dev/null' (any error 226 | messages will still be shown). 227 | 228 | `--srcdir=DIR' 229 | Look for the package's source code in directory DIR. Usually 230 | `configure' can determine that directory automatically. 231 | 232 | `configure' also accepts some other, not widely useful, options. Run 233 | `configure --help' for more details. 234 | 235 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | auxdir = @ac_aux_dir@ 3 | AUX_DIST = $(auxdir)/install-sh $(auxdir)/missing \ 4 | $(auxdir)/mkinstalldirs 5 | 6 | SUBDIRS = artnet debian 7 | 8 | EXTRA_DIST = libartnet.pc.in Doxyfile README.debian 9 | 10 | pkgconfigdir = $(libdir)/pkgconfig 11 | pkgconfig_DATA = libartnet.pc 12 | 13 | ACLOCAL = aclocal -I $(auxdir) 14 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | 21/07/2009 libartnet-1.1.0 2 | 3 | Added win32 support 4 | 5 | 13/12/2008 libartnet-1.0.7 6 | 7 | Subnet programming fix 8 | 9 | 03/11/2006 libartnet-1.0.6 10 | 11 | ArtNet II support 12 | 13 | 24/12/2006 libartnet-1.0.4 14 | 15 | Fixed the compile time error for OS X 16 | 17 | 12/6/2006 libartnet-1.0.3 18 | 19 | Fixed the segfault caused by interfaces without addresses 20 | 21 | 12/6/2006 libartnet-1.0.3 22 | 23 | Added esta and oem functions 24 | 25 | 17/4/2006 libartnet-1.0.2 26 | 27 | Introduced compatability mode for devices like the Martin Ether2DMX which 28 | send to 255.255.255.255 29 | 30 | 17/4/2006 libartnet-1.0.1 31 | 32 | Fixed the ArtPollReply length bug 33 | 34 | 30/3/2006 libartnet-1.0.0 35 | 36 | Version 1.0 release 37 | 38 | 16/9/2005 libartnet-0.1.14-rc4 39 | 40 | Now compiles on OS X (again) 41 | 42 | 28/8/2005 libartnet-0.1.14-rc3 43 | 44 | Bug fixes to net_start 45 | 46 | 23/8/2005 libartnet-0.1.14-rc2 47 | 48 | Bug fixes to get_ifaces 49 | 50 | 23/8/2005 libartnet-0.1.14-rc1 51 | 52 | A new error reporting system is in use. Calls to most artnet functions 53 | return a true value on error. The error string can be accessed with 54 | artnet_strerror() 55 | 56 | Applied patch from Samuli Valo to use getifaddrs. (Should now work 57 | on x86-64) (prob broken on OS X) 58 | 59 | 7/04/2005 libartnet-0.1.13 60 | 61 | Fixed the fact that 0.1.12 wouldn't compile :) 62 | 63 | 3/04/2005 libartnet-0.1.12 64 | 65 | Minor cleanups 66 | The number of ports are now reported correctly 67 | 68 | 3/04/2005 libartnet-0.1.11 69 | 70 | Added basic RDM support, see the artnet_rdm_output (in the artnet-examples) 71 | package for details. 72 | 73 | Issues: 74 | * Not sure about the ArtTodData implementation, it doesn't work with 75 | ArtNetView with more than 200 uids. 76 | 77 | 25/04/2005 libartnet-0.1.10 78 | 79 | Fixed the inet_aton bug 80 | 81 | 18/04/2005 libartnet-0.1.9 82 | 83 | Mac OS X basic support working (can send/receive dmx data) 84 | 85 | 12/04/2005 libartnet-0.1.8 86 | 87 | Mac OS X fixes merged in 88 | 89 | 18/03/2005 libartnet-0.1.7 90 | 91 | Added artnet_destroy function 92 | 93 | 17/03/2005 libartnet-0.1.6 94 | 95 | Added support for C++ linking (needed for Q Light) 96 | 97 | 16/03/2005 libartnet-0.1.5 98 | 99 | Merged bugfixes from multicast branch to trunk 100 | 101 | 12/03/2005 libartnet-0.1.4 102 | 103 | Split examples from library 104 | Fixed header install path 105 | Added node join support 106 | Depricated artnet_init in favour of artnet_new 107 | 108 | 12/2/2005 libartnet-0.1.3 109 | 110 | Fixed compiler warnings 111 | Fixed minor problems relating to a node's ip address 112 | 113 | 11/02/2005 libartnet-0.1.2 114 | 115 | Now includes support for Firmware send/receive. 116 | 117 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | Libartnet is an implementation of the ArtNet protocol. ArtNet allows the 3 | transmission of DMX and related data over IP networks. 4 | 5 | For installation notes see the INSTALL file. 6 | -------------------------------------------------------------------------------- /README.debian: -------------------------------------------------------------------------------- 1 | 2 | To build a .deb: 3 | 4 | $ tar -zxf libartnet_1.1.0-1.tar.gz 5 | $ cd libartnet_1.1.0-1 6 | $ debuild -us -uc # don't sign the package 7 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | 2 | 3 | to get reply working: 4 | fix video.remote 5 | fix stop / start procedure 6 | 7 | -------------------------------------------------------------------------------- /artnet/Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | INCLUDES = -I$(top_builddir) -I$(top_srcdir) 3 | AM_CFLAGS = -Wall -Werror -Wformat -W 4 | 5 | lib_LTLIBRARIES = libartnet.la 6 | libartnet_la_SOURCES = artnet.c private.h misc.c network.c receive.c \ 7 | transmit.c tod.c 8 | libartnet_la_LDFLAGS = -version-info 1:0:0 9 | 10 | if USING_WIN32 11 | libartnet_la_LDFLAGS += -no-undefined -liphlpapi -lnetapi32 -lws2_32 -ldpnet 12 | endif 13 | 14 | EXTRA_DIST = tod.h misc.h 15 | 16 | pkginclude_HEADERS = artnet.h packets.h common.h 17 | pkgincludedir = $(includedir)/artnet 18 | -------------------------------------------------------------------------------- /artnet/artnet.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library; if not, write to the Free Software 14 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | * 16 | * artnet.h 17 | * Interface to libartnet 18 | * Copyright (C) 2004-2007 Simon Newton 19 | */ 20 | 21 | #ifndef ARTNET_HEADER_H 22 | #define ARTNET_HEADER_H 23 | 24 | #include 25 | // order is important here for osx 26 | #include 27 | 28 | #ifndef WIN32 29 | #include 30 | #else 31 | #include 32 | typedef unsigned long in_addr_t; 33 | #endif 34 | 35 | #include 36 | 37 | /* the external storage class is "extern" in UNIX; in MSW it's ugly. */ 38 | #ifndef EXTERN 39 | #ifdef MSW 40 | #define EXTERN __declspec(dllexport) extern 41 | #else 42 | #define EXTERN extern 43 | #endif /* MSW */ 44 | #endif 45 | 46 | #ifdef __cplusplus 47 | extern "C" { 48 | #endif 49 | 50 | EXTERN int ARTNET_ADDRESS_NO_CHANGE; 51 | 52 | /** 53 | * An enum for setting the behaviour of a port. 54 | * Ports can either input data (DMX -> ArtNet) or 55 | * output (ArtNet -> DMX) data. 56 | */ 57 | typedef enum { 58 | ARTNET_ENABLE_INPUT = 0x40, /**< Enables the input for this port */ 59 | ARTNET_ENABLE_OUTPUT = 0x80 /**< Enables the output for this port */ 60 | } artnet_port_settings_t; 61 | 62 | 63 | typedef enum { 64 | ARTNET_PC_NONE = 0x00, 65 | ARTNET_PC_CANCEL = 0x01, 66 | ARTNET_PC_LED_NORMAL = 0x02, 67 | ARTNET_PC_LED_MUTE = 0x03, 68 | ARTNET_PC_LED_LOCATE = 0x04, 69 | ARTNET_PC_RESET = 0x05, 70 | ARTNET_PC_MERGE_LTP_O = 0x10, 71 | ARTNET_PC_MERGE_LTP_1 = 0x11, 72 | ARTNET_PC_MERGE_LTP_2 = 0x12, 73 | ARTNET_PC_MERGE_LTP_3 = 0x13, 74 | ARTNET_PC_MERGE_HTP_0 = 0x50, 75 | ARTNET_PC_MERGE_HTP_1 = 0x51, 76 | ARTNET_PC_MERGE_HTP_2 = 0x52, 77 | ARTNET_PC_MERGE_HTP_3 = 0x53, 78 | ARTNET_PC_CLR_0 = 0x93, 79 | ARTNET_PC_CLR_1 = 0x93, 80 | ARTNET_PC_CLR_2 = 0x93, 81 | ARTNET_PC_CLR_3 = 0x93, 82 | } artnet_port_command_t; 83 | 84 | 85 | /* 86 | * An enum for the type of data transmitted on a port. 87 | * As far as I know, only DMX-512 is supported 88 | */ 89 | typedef enum { 90 | ARTNET_PORT_DMX = 0x00, /**< Data is DMX-512 */ 91 | ARTNET_PORT_MIDI = 0x01, /**< Data is MIDI */ 92 | ARTNET_PORT_AVAB = 0x02, /**< Data is Avab */ 93 | ARTNET_PORT_CMX = 0x03, /**< Data is Colortran CMX */ 94 | ARTNET_PORT_ADB = 0x04, /**< Data is ABD 62.5 */ 95 | ARTNET_PORT_ARTNET = 0x05 /**< Data is ArtNet */ 96 | } artnet_port_data_code; 97 | 98 | 99 | // defines the status of the firmware transfer 100 | typedef enum { 101 | ARTNET_FIRMWARE_BLOCKGOOD = 0x00, 102 | ARTNET_FIRMWARE_ALLGOOD = 0x01, 103 | ARTNET_FIRMWARE_FAIL = 0xff, 104 | } artnet_firmware_status_code; 105 | 106 | // tod actions 107 | typedef enum { 108 | ARTNET_TOD_FULL = 0x00, 109 | ARTNET_TOD_FLUSH = 0x01, 110 | } artnet_tod_command_code; 111 | 112 | 113 | /** 114 | * An enum for refering to a particular input or output port. 115 | */ 116 | typedef enum { 117 | ARTNET_INPUT_PORT = 1, /**< The input port */ 118 | ARTNET_OUTPUT_PORT, /**< The output port */ 119 | } artnet_port_dir_t; 120 | 121 | 122 | /* 123 | * Enum describing the type of node 124 | */ 125 | typedef enum { 126 | ARTNET_SRV, /**< An ArtNet server (transmitts DMX data) */ 127 | ARTNET_NODE, /**< An ArtNet node (dmx reciever) */ 128 | ARTNET_MSRV, /**< A Media Server */ 129 | ARTNET_ROUTE, /**< No Effect currently */ 130 | ARTNET_BACKUP, /**< No Effect currently */ 131 | ARTNET_RAW /**< Raw Node - used for diagnostics */ 132 | } artnet_node_type; 133 | 134 | 135 | /* 136 | * Enum for the talk-to-me value 137 | * These values can be &'ed togeather, so for example to set private replies 138 | * and auto replying use : 139 | * (ARTNET_TTM_PRIVATE & ARTNET_TTM_AUTO) 140 | */ 141 | typedef enum { 142 | ARTNET_TTM_DEFAULT = 0xFF, /**< default, ArtPollReplies are broadcast, and nodes won't send a ArtPollReply when conditions change */ 143 | ARTNET_TTM_PRIVATE = 0xFE, /**< ArtPollReplies aren't broadcast */ 144 | ARTNET_TTM_AUTO = 0xFD /**< ArtPollReplies are send when node conditions chang */ 145 | } artnet_ttm_value_t; 146 | 147 | /** 148 | * Enums for the application defined handlers 149 | */ 150 | typedef enum { 151 | ARTNET_RECV_HANDLER, /**< Called on reciept of any ArtNet packet */ 152 | ARTNET_SEND_HANDLER, /**< Called on transmission of any ArtNet packet */ 153 | ARTNET_POLL_HANDLER, /**< Called on reciept of an ArtPoll packet */ 154 | ARTNET_REPLY_HANDLER, /**< Called on reciept of an ArtPollReply packet */ 155 | ARTNET_DMX_HANDLER, /**< Called on reciept of an ArtDMX packet */ 156 | ARTNET_ADDRESS_HANDLER, /**< Called on reciept of an ArtAddress packet */ 157 | ARTNET_INPUT_HANDLER, /**< Called on reciept of an ArtInput packet */ 158 | ARTNET_TOD_REQUEST_HANDLER, /**< Called on reciept of an ArtTodRequest packet */ 159 | ARTNET_TOD_DATA_HANDLER, /**< Called on reciept of an ArtTodData packet */ 160 | ARTNET_TOD_CONTROL_HANDLER, /**< Called on reciept of an ArtTodControl packet */ 161 | ARTNET_RDM_HANDLER, /**< Called on reciept of an ArtRdm packet */ 162 | ARTNET_IPPROG_HANDLER, /**< Called on reciept of an ArtIPProg packet */ 163 | ARTNET_FIRMWARE_HANDLER, /**< Called on reciept of an ArtFirmware packet */ 164 | ARTNET_FIRMWARE_REPLY_HANDLER, /**< Called on reciept of an ArtFirmwareReply packet */ 165 | } artnet_handler_name_t; 166 | 167 | 168 | /* 169 | * Describes a remote ArtNet node that has been discovered 170 | */ 171 | typedef struct artnet_node_entry_s { 172 | uint8_t ip[ARTNET_IP_SIZE]; /**< The IP address, Network byte ordered*/ 173 | int16_t ver; /**< The firmware version */ 174 | int16_t sub; /**< The subnet address */ 175 | int16_t oem; /**< The OEM value */ 176 | uint8_t ubea; /**< The UBEA version */ 177 | uint8_t status; 178 | uint8_t etsaman[ARTNET_ESTA_SIZE]; /**< The ESTA Manufacturer code */ 179 | uint8_t shortname[ARTNET_SHORT_NAME_LENGTH]; /**< The short node name */ 180 | uint8_t longname[ARTNET_LONG_NAME_LENGTH]; /**< The long node name */ 181 | uint8_t nodereport[ARTNET_REPORT_LENGTH]; /**< The node report */ 182 | int16_t numbports; /**< The number of ports */ 183 | uint8_t porttypes[ARTNET_MAX_PORTS]; /**< The type of ports */ 184 | uint8_t goodinput[ARTNET_MAX_PORTS]; 185 | uint8_t goodoutput[ARTNET_MAX_PORTS]; 186 | uint8_t swin[ARTNET_MAX_PORTS]; 187 | uint8_t swout[ARTNET_MAX_PORTS]; 188 | uint8_t swvideo; 189 | uint8_t swmacro; 190 | uint8_t swremote; 191 | uint8_t style; 192 | uint8_t mac[ARTNET_MAC_SIZE]; /**< The MAC address of the node */ 193 | } artnet_node_entry_t; 194 | 195 | /** A pointer to an artnet_node_entry_t */ 196 | typedef artnet_node_entry_t *artnet_node_entry; 197 | 198 | typedef struct { 199 | char short_name[ARTNET_SHORT_NAME_LENGTH]; 200 | char long_name[ARTNET_LONG_NAME_LENGTH]; 201 | uint8_t subnet; 202 | uint8_t in_ports[ARTNET_MAX_PORTS]; 203 | uint8_t out_ports[ARTNET_MAX_PORTS]; 204 | } artnet_node_config_t; 205 | 206 | 207 | /** The local ArtNet node */ 208 | typedef void *artnet_node; 209 | 210 | /** A list of remote ArtNet nodes */ 211 | typedef void *artnet_node_list; 212 | 213 | // node control functions 214 | EXTERN artnet_node artnet_new(const char *ip, int verbose); 215 | EXTERN int artnet_setoem(artnet_node vn, uint8_t hi, uint8_t lo); 216 | EXTERN int artnet_setesta(artnet_node vn, char hi, char lo); 217 | EXTERN int artnet_set_bcast_limit(artnet_node vn, int limit); 218 | EXTERN int artnet_start(artnet_node n); 219 | EXTERN int artnet_read(artnet_node n, int timeout); 220 | EXTERN int artnet_stop(artnet_node n); 221 | EXTERN int artnet_destroy(artnet_node n); 222 | 223 | int artnet_join(artnet_node vn1, artnet_node vn2); 224 | 225 | // handler functions 226 | // these need to be cleaned up into a generic interface 227 | EXTERN int artnet_set_handler(artnet_node vn, 228 | artnet_handler_name_t handler, 229 | int (*fh)(artnet_node n, void *pp, void *d), 230 | void* data); 231 | EXTERN int artnet_set_dmx_handler(artnet_node vn, 232 | int (*fh)(artnet_node n, int port, void *d), 233 | void *data); 234 | EXTERN int artnet_set_program_handler(artnet_node vn, 235 | int (*fh)(artnet_node n, void *d), 236 | void *data); 237 | EXTERN int artnet_set_firmware_handler(artnet_node vn, 238 | int (*fh)(artnet_node n, int ubea, uint16_t *data, int length, void *d), 239 | void *data); 240 | EXTERN int artnet_set_rdm_handler(artnet_node vn, 241 | int (*fh)(artnet_node n, int address, uint8_t *rdm, int length, void *d), 242 | void *data); 243 | EXTERN int artnet_set_rdm_initiate_handler(artnet_node vn, 244 | int (*fh)(artnet_node n, int port, void *d), 245 | void *data); 246 | EXTERN int artnet_set_rdm_tod_handler(artnet_node vn, 247 | int (*fh)(artnet_node n, int port, void *d), 248 | void *data); 249 | 250 | // send functions 251 | EXTERN int artnet_send_poll(artnet_node n, 252 | const char *ip, 253 | artnet_ttm_value_t talk_to_me); 254 | EXTERN int artnet_send_poll_reply(artnet_node n); 255 | EXTERN int artnet_send_dmx(artnet_node n, 256 | int port_id, 257 | int16_t length, 258 | const uint8_t *data); 259 | EXTERN int artnet_raw_send_dmx(artnet_node vn, 260 | uint8_t uni, 261 | int16_t length, 262 | const uint8_t *data); 263 | EXTERN int artnet_send_address(artnet_node n, 264 | artnet_node_entry e, 265 | const char *shortName, 266 | const char *longName, 267 | uint8_t inAddr[ARTNET_MAX_PORTS], 268 | uint8_t outAddr[ARTNET_MAX_PORTS], 269 | uint8_t subAddr, 270 | artnet_port_command_t cmd); 271 | EXTERN int artnet_send_input(artnet_node n, 272 | artnet_node_entry e, 273 | uint8_t settings[ARTNET_MAX_PORTS]); 274 | EXTERN int artnet_send_firmware(artnet_node vn, 275 | artnet_node_entry e, 276 | int ubea, 277 | uint16_t *data, 278 | int length, 279 | int (*fh)(artnet_node n, artnet_firmware_status_code code, void *d), 280 | void *user_data); 281 | EXTERN int artnet_send_firmware_reply(artnet_node vn, 282 | artnet_node_entry e, 283 | artnet_firmware_status_code code); 284 | 285 | // rdm functions 286 | EXTERN int artnet_send_tod_request(artnet_node vn); 287 | EXTERN int artnet_send_tod_control(artnet_node vn, 288 | uint8_t address, 289 | artnet_tod_command_code action); 290 | EXTERN int artnet_send_tod_data(artnet_node vn, int port); 291 | EXTERN int artnet_send_rdm(artnet_node vn, 292 | uint8_t address, 293 | uint8_t *data, 294 | int length); 295 | EXTERN int artnet_add_rdm_device(artnet_node vn, 296 | int port, 297 | uint8_t uid[ARTNET_RDM_UID_WIDTH]); 298 | EXTERN int artnet_add_rdm_devices(artnet_node vn, 299 | int port, 300 | uint8_t *uid, 301 | int count); 302 | EXTERN int artnet_remove_rdm_device(artnet_node vn, 303 | int port, 304 | uint8_t uid[ARTNET_RDM_UID_WIDTH]); 305 | 306 | // recv functions 307 | EXTERN uint8_t *artnet_read_dmx(artnet_node n, int port_id, int *length); 308 | 309 | // state changing functions 310 | EXTERN int artnet_set_node_type(artnet_node n, artnet_node_type type); 311 | EXTERN int artnet_set_short_name(artnet_node vn, const char *name); 312 | EXTERN int artnet_set_long_name(artnet_node n, const char *name); 313 | 314 | //port manipulation functions 315 | EXTERN int artnet_set_port_type(artnet_node n, 316 | int id, 317 | artnet_port_settings_t settings, 318 | artnet_port_data_code data); 319 | EXTERN int artnet_set_port_addr(artnet_node n, 320 | int id, 321 | artnet_port_dir_t dir, 322 | uint8_t addr); 323 | EXTERN int artnet_set_subnet_addr(artnet_node n, uint8_t subnet); 324 | EXTERN int artnet_get_universe_addr(artnet_node n, 325 | int id, 326 | artnet_port_dir_t dir); 327 | 328 | //node list functions 329 | EXTERN artnet_node_list artnet_get_nl(artnet_node n); 330 | EXTERN artnet_node_entry artnet_nl_first(artnet_node_list nl); 331 | EXTERN artnet_node_entry artnet_nl_next(artnet_node_list nl); 332 | EXTERN int artnet_nl_get_length(artnet_node_list nl); 333 | 334 | // misc 335 | EXTERN int artnet_dump_config(artnet_node n); 336 | EXTERN int artnet_get_config(artnet_node n, artnet_node_config_t *config); 337 | EXTERN int artnet_get_sd(artnet_node n); 338 | EXTERN int artnet_set_fdset(artnet_node vn, fd_set *fdset); 339 | 340 | char *artnet_strerror(); 341 | 342 | #ifdef __cplusplus 343 | } 344 | #endif 345 | 346 | #endif 347 | -------------------------------------------------------------------------------- /artnet/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library; if not, write to the Free Software 14 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | * 16 | * common.c 17 | * Constants required for both internally and externally 18 | * Copyright (C) 2004-2006 Simon Newton 19 | */ 20 | 21 | #ifndef ARTNET_COMMON_H 22 | #define ARTNET_COMMON_H 23 | 24 | /* 25 | * libartnet error codes 26 | */ 27 | enum { 28 | ARTNET_EOK = 0, 29 | ARTNET_ENET = -1, // network error 30 | ARTNET_EMEM = -2, // memory error 31 | ARTNET_EARG = -3, // argument error 32 | ARTNET_ESTATE = -4, // state error 33 | ARTNET_EACTION = -5, // invalid action 34 | }; 35 | 36 | 37 | /* 38 | * The maximum ports per node built into the ArtNet protocol. 39 | * This is always 4. Don't change it unless you really know what your doing 40 | */ 41 | enum { ARTNET_MAX_PORTS = 4 }; 42 | 43 | /** 44 | * The length of the short name field. Always 18 45 | */ 46 | enum { ARTNET_SHORT_NAME_LENGTH = 18 }; 47 | 48 | /** 49 | * The length of the long name field. Always 64 50 | */ 51 | enum { ARTNET_LONG_NAME_LENGTH = 64 }; 52 | 53 | /** 54 | * The length of the report field. Always 64 55 | */ 56 | enum { ARTNET_REPORT_LENGTH = 64 }; 57 | 58 | /** 59 | * The length of the DMX field. Always 512 60 | */ 61 | enum { ARTNET_DMX_LENGTH = 512 }; 62 | 63 | /* 64 | * Number of bytes in a RDM UID 65 | */ 66 | enum { ARTNET_RDM_UID_WIDTH = 6 }; 67 | 68 | /* 69 | * Length of the hardware address 70 | */ 71 | enum { ARTNET_MAC_SIZE = 6 }; 72 | 73 | /* 74 | * Length of the ESTA field 75 | */ 76 | enum { ARTNET_ESTA_SIZE = 2 }; 77 | 78 | /* 79 | * Length of the IP field 80 | */ 81 | enum { ARTNET_IP_SIZE = 4 }; 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /artnet/misc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library; if not, write to the Free Software 14 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | * 16 | * misc.c 17 | * Misc code for libartnet (almost nothing these days) 18 | * Copyright (C) 2004-2005 Simon Newton 19 | */ 20 | 21 | #include 22 | #include 23 | #include "private.h" 24 | 25 | // static buffer for the error strings 26 | char artnet_errstr[256]; 27 | 28 | /* 29 | * Libartnet error function 30 | * This writes the error string to artnet_errstr, which can be accessed 31 | * using artnet_strerror(); 32 | */ 33 | void artnet_error(const char *fmt, ...) { 34 | va_list ap; 35 | va_start(ap, fmt); 36 | vsnprintf(artnet_errstr, sizeof(artnet_errstr), fmt, ap); 37 | va_end(ap); 38 | } 39 | 40 | 41 | /* 42 | * Converts 4 bytes in big endian order to a 32 bit int 43 | */ 44 | int32_t artnet_misc_nbytes_to_32(uint8_t bytes[4]) { 45 | return (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]; 46 | } 47 | 48 | /* 49 | * Converts an int to an arrany of 4 bytes in big endian format 50 | */ 51 | void artnet_misc_int_to_bytes(int data, uint8_t *bytes) { 52 | bytes[3] = (data & 0x000000FF); 53 | bytes[2] = (data & 0x0000FF00) >> 8; 54 | bytes[1] = (data & 0x00FF0000) >> 16; 55 | bytes[0] = (data & 0xFF000000) >> 24; 56 | } 57 | -------------------------------------------------------------------------------- /artnet/misc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library; if not, write to the Free Software 14 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | * 16 | * misc.h 17 | * Header file for misc.c 18 | * Copyright (C) 2004-2005 Simon Newton 19 | */ 20 | 21 | #ifndef ARTNET_MISC_H 22 | #define ARTNET_MISC_H 23 | 24 | #include 25 | #include 26 | 27 | extern char artnet_errstr[256]; 28 | void artnet_error(const char *fmt, ...); 29 | int32_t artnet_misc_nbytes_to_32(uint8_t bytes[4]); 30 | void artnet_misc_int_to_bytes(int data, uint8_t *bytes); 31 | 32 | // check if the node is null and return an error 33 | #define check_nullnode(node) if (node == NULL) { \ 34 | artnet_error("%s : argument 1 (artnet_node) was null" , __FUNCTION__ ); \ 35 | return ARTNET_EARG; \ 36 | } 37 | 38 | #define artnet_error_malloc() artnet_error("%s : malloc error %s" , __FUNCTION__, strerror(errno) ) 39 | #define artnet_error_realloc() artnet_error("%s : realloc error %s" , __FUNCTION__, strerror(errno) ) 40 | #define artnet_error_nullnode() artnet_error("%s : argument 1 (artnet_node) was null" , __FUNCTION__ ) 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /artnet/network.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library; if not, write to the Free Software 14 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | * 16 | * network.c 17 | * Network code for libartnet 18 | * Copyright (C) 2004-2007 Simon Newton 19 | * 20 | */ 21 | 22 | #include 23 | 24 | #ifndef WIN32 25 | #include // socket before net/if.h for mac 26 | #include 27 | #include 28 | #else 29 | typedef int socklen_t; 30 | #include 31 | #include 32 | #include 33 | #endif 34 | 35 | #include 36 | 37 | #include "private.h" 38 | 39 | #ifdef HAVE_GETIFADDRS 40 | #ifdef HAVE_LINUX_IF_PACKET_H 41 | #define USE_GETIFADDRS 42 | #endif 43 | #endif 44 | 45 | #ifdef USE_GETIFADDRS 46 | #include 47 | #include // required by if_packet 48 | #include 49 | #endif 50 | 51 | 52 | enum { INITIAL_IFACE_COUNT = 10 }; 53 | enum { IFACE_COUNT_INC = 5 }; 54 | enum { IFNAME_SIZE = 32 }; // 32 sounds a reasonable size 55 | 56 | typedef struct iface_s { 57 | struct sockaddr_in ip_addr; 58 | struct sockaddr_in bcast_addr; 59 | int8_t hw_addr[ARTNET_MAC_SIZE]; 60 | char if_name[IFNAME_SIZE]; 61 | struct iface_s *next; 62 | } iface_t; 63 | 64 | unsigned long LOOPBACK_IP = 0x7F000001; 65 | 66 | 67 | /* 68 | * Free memory used by the iface's list 69 | * @param head a pointer to the head of the list 70 | */ 71 | static void free_ifaces(iface_t *head) { 72 | iface_t *ift, *ift_next; 73 | 74 | for (ift = head; ift != NULL; ift = ift_next) { 75 | ift_next = ift->next; 76 | free(ift); 77 | } 78 | } 79 | 80 | 81 | /* 82 | * Add a new interface to an interface list 83 | * @param head pointer to the head of the list 84 | * @param tail pointer to the end of the list 85 | * @return a new iface_t or void 86 | */ 87 | static iface_t *new_iface(iface_t **head, iface_t **tail) { 88 | iface_t *iface = (iface_t*) calloc(1, sizeof(iface_t)); 89 | 90 | if (!iface) { 91 | artnet_error("%s: calloc error %s" , __FUNCTION__, strerror(errno)); 92 | return NULL; 93 | } 94 | memset(iface, 0, sizeof(iface_t)); 95 | 96 | if (!*head) { 97 | *head = *tail = iface; 98 | } else { 99 | (*tail)->next = iface; 100 | *tail = iface; 101 | } 102 | return iface; 103 | } 104 | 105 | 106 | #ifdef WIN32 107 | 108 | /* 109 | * Set if_head to point to a list of iface_t structures which represent the 110 | * interfaces on this machine 111 | * @param ift_head the address of the pointer to the head of the list 112 | */ 113 | static int get_ifaces(iface_t **if_head) { 114 | iface_t *if_tail, *iface; 115 | PIP_ADAPTER_INFO pAdapter = NULL; 116 | PIP_ADAPTER_INFO pAdapterInfo; 117 | IP_ADDR_STRING *ipAddress; 118 | ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO); 119 | unsigned long net, mask; 120 | if_tail = NULL; 121 | 122 | while (1) { 123 | pAdapterInfo = (IP_ADAPTER_INFO*) malloc(ulOutBufLen); 124 | if (!pAdapterInfo) { 125 | artnet_error("Error allocating memory needed for GetAdaptersinfo"); 126 | return ARTNET_EMEM; 127 | } 128 | 129 | DWORD status = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen); 130 | if (status == NO_ERROR) 131 | break; 132 | 133 | free(pAdapterInfo); 134 | if (status != ERROR_BUFFER_OVERFLOW) { 135 | printf("GetAdaptersInfo failed with error: %d\n", (int) status); 136 | return ARTNET_ENET; 137 | } 138 | } 139 | 140 | for (pAdapter = pAdapterInfo; 141 | pAdapter && pAdapter < pAdapterInfo + ulOutBufLen; 142 | pAdapter = pAdapter->Next) { 143 | 144 | if(pAdapter->Type != MIB_IF_TYPE_ETHERNET) 145 | continue; 146 | 147 | for (ipAddress = &pAdapter->IpAddressList; ipAddress; 148 | ipAddress = ipAddress->Next) { 149 | 150 | net = inet_addr(ipAddress->IpAddress.String); 151 | if (net) { 152 | // Windows doesn't seem to have the notion of an interface being 'up' 153 | // so we check if this interface has an address assigned. 154 | iface = new_iface(if_head, &if_tail); 155 | if (!iface) 156 | continue; 157 | 158 | mask = inet_addr(ipAddress->IpMask.String); 159 | strncpy(iface->if_name, pAdapter->AdapterName, IFNAME_SIZE); 160 | memcpy(iface->hw_addr, pAdapter->Address, ARTNET_MAC_SIZE); 161 | iface->ip_addr.sin_addr.s_addr = net; 162 | iface->bcast_addr.sin_addr.s_addr = ( 163 | (net & mask) | (0xFFFFFFFF ^ mask)); 164 | } 165 | } 166 | } 167 | 168 | free(pAdapterInfo); 169 | return (ARTNET_EOK); 170 | } 171 | 172 | # else // not WIN32 173 | 174 | #ifdef USE_GETIFADDRS 175 | 176 | /* 177 | * Check if we are interested in this interface 178 | * @param ifa a pointer to a ifaddr struct 179 | */ 180 | static void add_iface_if_needed(iface_t **head, iface_t **tail, 181 | struct ifaddrs *ifa) { 182 | 183 | // skip down, loopback and non inet interfaces 184 | if (!ifa || !ifa->ifa_addr) return; 185 | if (!(ifa->ifa_flags & IFF_UP)) return; 186 | if (ifa->ifa_flags & IFF_LOOPBACK) return; 187 | if (ifa->ifa_addr->sa_family != AF_INET) return; 188 | 189 | iface_t *iface = new_iface(head, tail); 190 | struct sockaddr_in *sin = (struct sockaddr_in*) ifa->ifa_addr; 191 | iface->ip_addr.sin_addr = sin->sin_addr; 192 | strncpy(iface->if_name, ifa->ifa_name, IFNAME_SIZE - 1); 193 | 194 | if (ifa->ifa_flags & IFF_BROADCAST) { 195 | sin = (struct sockaddr_in *) ifa->ifa_broadaddr; 196 | iface->bcast_addr.sin_addr = sin->sin_addr; 197 | } 198 | } 199 | 200 | 201 | /* 202 | * Set if_head to point to a list of iface_t structures which represent the 203 | * interfaces on this machine 204 | * @param ift_head the address of the pointer to the head of the list 205 | */ 206 | static int get_ifaces(iface_t **if_head) { 207 | struct ifaddrs *ifa_list, *ifa_iter; 208 | iface_t *if_tail, *if_iter; 209 | struct sockaddr_ll *sll; 210 | char *if_name, *cptr; 211 | *if_head = if_tail = NULL; 212 | 213 | if (getifaddrs(&ifa_list) != 0) { 214 | artnet_error("Error getting interfaces: %s", strerror(errno)); 215 | return ARTNET_ENET; 216 | } 217 | 218 | for (ifa_iter = ifa_list; ifa_iter; ifa_iter = ifa_iter->ifa_next) 219 | add_iface_if_needed(if_head, &if_tail, ifa_iter); 220 | 221 | // Match up the interfaces with the corrosponding AF_PACKET interface 222 | // to fetch the hw addresses 223 | // 224 | // TODO: Will probably not work on OS X, it should 225 | // return AF_LINK -type sockaddr 226 | for (if_iter = *if_head; if_iter; if_iter = if_iter->next) { 227 | if_name = strdup(if_iter->if_name); 228 | 229 | // if this is an alias, get mac of real interface 230 | if ((cptr = strchr(if_name, ':'))) 231 | *cptr = 0; 232 | 233 | // Find corresponding iface_t structure 234 | for (ifa_iter = ifa_list; ifa_iter; ifa_iter = ifa_iter->ifa_next) { 235 | if ((!ifa_iter->ifa_addr) || ifa_iter->ifa_addr->sa_family != AF_PACKET) 236 | continue; 237 | 238 | if (strncmp(if_name, ifa_iter->ifa_name, IFNAME_SIZE) == 0) { 239 | // Found matching hw-address 240 | sll = (struct sockaddr_ll*) ifa_iter->ifa_addr; 241 | memcpy(if_iter->hw_addr, sll->sll_addr, ARTNET_MAC_SIZE); 242 | break; 243 | } 244 | } 245 | free(if_name); 246 | } 247 | freeifaddrs(ifa_list); 248 | return 0; 249 | } 250 | 251 | #else // no GETIFADDRS 252 | 253 | /* 254 | * Set if_head to point to a list of iface_t structures which represent the 255 | * interfaces on this machine 256 | * @param ift_head the address of the pointer to the head of the list 257 | */ 258 | static int get_ifaces(iface_t **if_head) { 259 | struct ifconf ifc; 260 | struct ifreq *ifr, ifrcopy; 261 | struct sockaddr_in *sin; 262 | int len, lastlen, flags; 263 | char *buf, *ptr; 264 | iface_t *if_tail, *iface; 265 | int ret = ARTNET_EOK; 266 | int sd; 267 | 268 | *if_head = if_tail = NULL; 269 | 270 | // create socket to get iface config 271 | sd = socket(PF_INET, SOCK_DGRAM, 0); 272 | 273 | if (sd < 0) { 274 | artnet_error("%s : Could not create socket %s", __FUNCTION__, strerror(errno)); 275 | ret = ARTNET_ENET; 276 | goto e_return; 277 | } 278 | 279 | // first use ioctl to get a listing of interfaces 280 | lastlen = 0; 281 | len = INITIAL_IFACE_COUNT * sizeof(struct ifreq); 282 | 283 | for (;;) { 284 | buf = malloc(len); 285 | 286 | if (buf == NULL) { 287 | artnet_error_malloc(); 288 | ret = ARTNET_EMEM; 289 | goto e_free; 290 | } 291 | 292 | ifc.ifc_len = len; 293 | ifc.ifc_buf = buf; 294 | if (ioctl(sd, SIOCGIFCONF, &ifc) < 0) { 295 | if (errno != EINVAL || lastlen != 0) { 296 | artnet_error("%s : ioctl error %s", __FUNCTION__, strerror(errno)); 297 | ret = ARTNET_ENET; 298 | goto e_free; 299 | } 300 | } else { 301 | if (ifc.ifc_len == lastlen) 302 | break; 303 | lastlen = ifc.ifc_len; 304 | } 305 | len += IFACE_COUNT_INC * sizeof(struct ifreq); 306 | free(buf); 307 | } 308 | 309 | // loop through each iface 310 | for (ptr = buf; ptr < buf + ifc.ifc_len;) { 311 | ifr = (struct ifreq*) ptr; 312 | 313 | // work out length here 314 | #ifdef HAVE_SOCKADDR_SA_LEN 315 | len = max(sizeof(struct sockaddr), ifr->ifr_addr.sa_len); 316 | #else 317 | switch (ifr->ifr_addr.sa_family) { 318 | #ifdef IPV6 319 | case AF_INET6: 320 | len = sizeof(struct sockaddr_in6); 321 | break; 322 | #endif 323 | case AF_INET: 324 | default: 325 | len = sizeof(SA); 326 | break; 327 | } 328 | #endif 329 | 330 | ptr += sizeof(ifr->ifr_name) + len; 331 | 332 | // look for AF_INET interfaces 333 | if (ifr->ifr_addr.sa_family == AF_INET) { 334 | ifrcopy = *ifr; 335 | if (ioctl(sd, SIOCGIFFLAGS, &ifrcopy) < 0) { 336 | artnet_error("%s : ioctl error %s" , __FUNCTION__, strerror(errno)); 337 | ret = ARTNET_ENET; 338 | goto e_free_list; 339 | } 340 | 341 | flags = ifrcopy.ifr_flags; 342 | if ((flags & IFF_UP) == 0) 343 | continue; //skip down interfaces 344 | 345 | if ((flags & IFF_LOOPBACK)) 346 | continue; //skip lookback 347 | 348 | iface = new_iface(if_head, &if_tail); 349 | if (!iface) 350 | goto e_free_list; 351 | 352 | sin = (struct sockaddr_in *) &ifr->ifr_addr; 353 | iface->ip_addr.sin_addr = sin->sin_addr; 354 | 355 | // fetch bcast address 356 | #ifdef SIOCGIFBRDADDR 357 | if (flags & IFF_BROADCAST) { 358 | if (ioctl(sd, SIOCGIFBRDADDR, &ifrcopy) < 0) { 359 | artnet_error("%s : ioctl error %s" , __FUNCTION__, strerror(errno)); 360 | ret = ARTNET_ENET; 361 | goto e_free_list; 362 | } 363 | 364 | sin = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr; 365 | iface->bcast_addr.sin_addr = sin->sin_addr; 366 | } 367 | #endif 368 | // fetch hardware address 369 | #ifdef SIOCGIFHWADDR 370 | if (flags & SIOCGIFHWADDR) { 371 | if (ioctl(sd, SIOCGIFHWADDR, &ifrcopy) < 0) { 372 | artnet_error("%s : ioctl error %s", __FUNCTION__, strerror(errno)); 373 | ret = ARTNET_ENET; 374 | goto e_free_list; 375 | } 376 | memcpy(&iface->hw_addr, ifrcopy.ifr_hwaddr.sa_data, ARTNET_MAC_SIZE); 377 | } 378 | #endif 379 | 380 | /* ok, if that all failed we should prob try and use sysctl to work out the bcast 381 | * and hware addresses 382 | * i'll leave that for another day 383 | */ 384 | } 385 | } 386 | free(buf); 387 | return ARTNET_EOK; 388 | 389 | e_free_list: 390 | free_ifaces(*if_head); 391 | e_free: 392 | free(buf); 393 | close(sd); 394 | e_return: 395 | return ret; 396 | } 397 | 398 | #endif // GETIFADDRS 399 | #endif // not WIN32 400 | 401 | 402 | /* 403 | * Scan for interfaces, and work out which one the user wanted to use. 404 | */ 405 | int artnet_net_init(node n, const char *preferred_ip) { 406 | iface_t *ift, *ift_head = NULL; 407 | struct in_addr wanted_ip; 408 | 409 | int found = FALSE; 410 | int i; 411 | int ret = ARTNET_EOK; 412 | 413 | if ((ret = get_ifaces(&ift_head))) 414 | goto e_return; 415 | 416 | if (n->state.verbose) { 417 | printf("#### INTERFACES FOUND ####\n"); 418 | for (ift = ift_head; ift != NULL; ift = ift->next) { 419 | printf("IP: %s\n", inet_ntoa(ift->ip_addr.sin_addr)); 420 | printf(" bcast: %s\n" , inet_ntoa(ift->bcast_addr.sin_addr)); 421 | printf(" hwaddr: "); 422 | for (i = 0; i < ARTNET_MAC_SIZE; i++) { 423 | if (i) 424 | printf(":"); 425 | printf("%02x", (uint8_t) ift->hw_addr[i]); 426 | } 427 | printf("\n"); 428 | } 429 | printf("#########################\n"); 430 | } 431 | 432 | if (preferred_ip) { 433 | // search through list of interfaces for one with the correct address 434 | ret = artnet_net_inet_aton(preferred_ip, &wanted_ip); 435 | if (ret) 436 | goto e_cleanup; 437 | 438 | for (ift = ift_head; ift != NULL; ift = ift->next) { 439 | if (ift->ip_addr.sin_addr.s_addr == wanted_ip.s_addr) { 440 | found = TRUE; 441 | n->state.ip_addr = ift->ip_addr.sin_addr; 442 | n->state.bcast_addr = ift->bcast_addr.sin_addr; 443 | memcpy(&n->state.hw_addr, &ift->hw_addr, ARTNET_MAC_SIZE); 444 | break; 445 | } 446 | } 447 | if (!found) { 448 | artnet_error("Cannot find ip %s", preferred_ip); 449 | ret = ARTNET_ENET; 450 | goto e_cleanup; 451 | } 452 | } else { 453 | if (ift_head) { 454 | // pick first address 455 | // copy ip address, bcast address and hardware address 456 | n->state.ip_addr = ift_head->ip_addr.sin_addr; 457 | n->state.bcast_addr = ift_head->bcast_addr.sin_addr; 458 | memcpy(&n->state.hw_addr, &ift_head->hw_addr, ARTNET_MAC_SIZE); 459 | } else { 460 | artnet_error("No interfaces found!"); 461 | ret = ARTNET_ENET; 462 | } 463 | } 464 | 465 | e_cleanup: 466 | free_ifaces(ift_head); 467 | e_return : 468 | return ret; 469 | } 470 | 471 | 472 | /* 473 | * Start listening on the socket 474 | */ 475 | int artnet_net_start(node n) { 476 | int sock; 477 | struct sockaddr_in servAddr; 478 | int true_flag = TRUE; 479 | node tmp; 480 | 481 | // only attempt to bind if we are the group master 482 | if (n->peering.master == TRUE) { 483 | 484 | #ifdef WIN32 485 | // check winsock version 486 | WSADATA wsaData; 487 | WORD wVersionRequested = MAKEWORD(2, 2); 488 | if (WSAStartup(wVersionRequested, &wsaData) != 0) 489 | return (-1); 490 | if (wsaData.wVersion != wVersionRequested) 491 | return (-2); 492 | #endif 493 | 494 | // create socket 495 | sock = socket(PF_INET, SOCK_DGRAM, 0); 496 | 497 | if (sock < 0) { 498 | artnet_error("Could not create socket %s", artnet_net_last_error()); 499 | return ARTNET_ENET; 500 | } 501 | 502 | memset(&servAddr, 0x00, sizeof(servAddr)); 503 | servAddr.sin_family = AF_INET; 504 | servAddr.sin_port = htons(ARTNET_PORT); 505 | servAddr.sin_addr.s_addr = htonl(INADDR_ANY); 506 | 507 | if (n->state.verbose) 508 | printf("Binding to %s \n", inet_ntoa(servAddr.sin_addr)); 509 | 510 | // bind sockets 511 | if (bind(sock, (SA *) &servAddr, sizeof(servAddr)) == -1) { 512 | artnet_error("Failed to bind to socket %s", artnet_net_last_error()); 513 | artnet_net_close(sock); 514 | return ARTNET_ENET; 515 | } 516 | 517 | // allow bcasting 518 | if (setsockopt(sock, 519 | SOL_SOCKET, 520 | SO_BROADCAST, 521 | (char*) &true_flag, // char* for win32 522 | sizeof(int)) == -1) { 523 | artnet_error("Failed to bind to socket %s", artnet_net_last_error()); 524 | artnet_net_close(sock); 525 | return ARTNET_ENET; 526 | } 527 | 528 | #ifdef WIN32 529 | // ### LH - 22.08.2008 530 | // make it possible to reuse port, if SO_REUSEADDR 531 | // exists on operating system 532 | 533 | // NEVER USE SO_EXCLUSIVEADDRUSE, as that freezes the application 534 | // on WinXP, if port is in use ! 535 | if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &true_flag, 536 | sizeof(true_flag)) < 0) { 537 | 538 | artnet_error("Set reuse failed", artnet_net_last_error()); 539 | artnet_net_close(sock); 540 | return ARTNET_ENET; 541 | } 542 | 543 | u_long true = 1; 544 | if (SOCKET_ERROR == ioctlsocket(sock, FIONBIO, &true)) { 545 | 546 | artnet_error("ioctlsocket", artnet_net_last_error()); 547 | artnet_net_close(sock); 548 | return ARTNET_ENET; 549 | } 550 | #endif 551 | 552 | n->sd = sock; 553 | // Propagate the socket to all our peers 554 | for (tmp = n->peering.peer; tmp && tmp != n; tmp = tmp->peering.peer) 555 | tmp->sd = sock; 556 | } 557 | return ARTNET_EOK; 558 | } 559 | 560 | 561 | /* 562 | * Receive a packet. 563 | */ 564 | int artnet_net_recv(node n, artnet_packet p, int delay) { 565 | ssize_t len; 566 | struct sockaddr_in cliAddr; 567 | socklen_t cliLen = sizeof(cliAddr); 568 | fd_set rset; 569 | struct timeval tv; 570 | int maxfdp1 = n->sd + 1; 571 | 572 | FD_ZERO(&rset); 573 | FD_SET((unsigned int) n->sd, &rset); 574 | 575 | tv.tv_usec = 0; 576 | tv.tv_sec = delay; 577 | p->length = 0; 578 | 579 | switch (select(maxfdp1, &rset, NULL, NULL, &tv)) { 580 | case 0: 581 | // timeout 582 | return RECV_NO_DATA; 583 | break; 584 | case -1: 585 | if ( errno != EINTR) { 586 | artnet_error("Select error %s", artnet_net_last_error()); 587 | return ARTNET_ENET; 588 | } 589 | return ARTNET_EOK; 590 | break; 591 | default: 592 | break; 593 | } 594 | 595 | // need a check here for the amount of data read 596 | // should prob allow an extra byte after data, and pass the size as sizeof(Data) +1 597 | // then check the size read and if equal to size(data)+1 we have an error 598 | len = recvfrom(n->sd, 599 | (char*) &(p->data), // char* for win32 600 | sizeof(p->data), 601 | 0, 602 | (SA*) &cliAddr, 603 | &cliLen); 604 | if (len < 0) { 605 | artnet_error("Recvfrom error %s", artnet_net_last_error()); 606 | return ARTNET_ENET; 607 | } 608 | 609 | if (cliAddr.sin_addr.s_addr == n->state.ip_addr.s_addr || 610 | ntohl(cliAddr.sin_addr.s_addr) == LOOPBACK_IP) { 611 | p->length = 0; 612 | return ARTNET_EOK; 613 | } 614 | 615 | p->length = len; 616 | memcpy(&(p->from), &cliAddr.sin_addr, sizeof(struct in_addr)); 617 | // should set to in here if we need it 618 | return ARTNET_EOK; 619 | } 620 | 621 | 622 | /* 623 | * Send a packet. 624 | */ 625 | int artnet_net_send(node n, artnet_packet p) { 626 | struct sockaddr_in addr; 627 | int ret; 628 | 629 | if (n->state.mode != ARTNET_ON) 630 | return ARTNET_EACTION; 631 | 632 | addr.sin_family = AF_INET; 633 | addr.sin_port = htons(ARTNET_PORT); 634 | addr.sin_addr = p->to; 635 | p->from = n->state.ip_addr; 636 | 637 | if (n->state.verbose) 638 | printf("sending to %s\n" , inet_ntoa(addr.sin_addr)); 639 | 640 | ret = sendto(n->sd, 641 | (char*) &p->data, // char* required for win32 642 | p->length, 643 | 0, 644 | (SA*) &addr, 645 | sizeof(addr)); 646 | if (ret == -1) { 647 | artnet_error("Sendto failed: %s", artnet_net_last_error()); 648 | n->state.report_code = ARTNET_RCUDPFAIL; 649 | return ARTNET_ENET; 650 | 651 | } else if (p->length != ret) { 652 | artnet_error("failed to send full datagram"); 653 | n->state.report_code = ARTNET_RCSOCKETWR1; 654 | return ARTNET_ENET; 655 | } 656 | 657 | if (n->callbacks.send.fh) { 658 | get_type(p); 659 | n->callbacks.send.fh(n, p, n->callbacks.send.data); 660 | } 661 | return ARTNET_EOK; 662 | } 663 | 664 | 665 | /* 666 | int artnet_net_reprogram(node n) { 667 | iface_t *ift_head, *ift; 668 | int i; 669 | 670 | ift_head = get_ifaces(n->sd[0]); 671 | 672 | for (ift = ift_head;ift != NULL; ift = ift->next ) { 673 | printf("IP: %s\n", inet_ntoa(ift->ip_addr.sin_addr) ); 674 | printf(" bcast: %s\n" , inet_ntoa(ift->bcast_addr.sin_addr) ); 675 | printf(" hwaddr: "); 676 | for(i = 0; i < 6; i++ ) { 677 | printf("%hhx:", ift->hw_addr[i] ); 678 | } 679 | printf("\n"); 680 | } 681 | 682 | free_ifaces(ift_head); 683 | 684 | }*/ 685 | 686 | 687 | int artnet_net_set_fdset(node n, fd_set *fdset) { 688 | FD_SET((unsigned int) n->sd, fdset); 689 | return ARTNET_EOK; 690 | } 691 | 692 | 693 | /* 694 | * Close a socket 695 | */ 696 | int artnet_net_close(int sock) { 697 | #ifdef WIN32 698 | shutdown(sock, SD_BOTH); 699 | closesocket(sock); 700 | //WSACancelBlockingCall(); 701 | WSACleanup(); 702 | #else 703 | if (close(sock)) { 704 | artnet_error(artnet_net_last_error()); 705 | return ARTNET_ENET; 706 | } 707 | #endif 708 | return ARTNET_EOK; 709 | } 710 | 711 | 712 | /* 713 | * Convert a string to an in_addr 714 | */ 715 | int artnet_net_inet_aton(const char *ip_address, struct in_addr *address) { 716 | #ifdef HAVE_INET_ATON 717 | if (!inet_aton(ip_address, address)) { 718 | #else 719 | in_addr_t *addr = (in_addr_t*) address; 720 | if ((*addr = inet_addr(ip_address)) == INADDR_NONE) { 721 | #endif 722 | artnet_error("IP conversion from %s failed", ip_address); 723 | return ARTNET_EARG; 724 | } 725 | return ARTNET_EOK; 726 | } 727 | 728 | 729 | /* 730 | * 731 | */ 732 | const char *artnet_net_last_error() { 733 | #ifdef WIN32 734 | static char error_str[10]; 735 | int error = WSAGetLastError(); 736 | snprintf(error_str, sizeof(error_str), "%d", error); 737 | return error_str; 738 | #else 739 | return strerror(errno); 740 | #endif 741 | } 742 | 743 | -------------------------------------------------------------------------------- /artnet/packets.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library; if not, write to the Free Software 14 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | * 16 | * packets.h 17 | * Datagram definitions for libartnet 18 | * Copyright (C) 2004-2005 Simon Newton 19 | */ 20 | 21 | 22 | #ifndef ARTNET_PACKETS_H 23 | #define ARTNET_PACKETS_H 24 | 25 | #include 26 | #include 27 | 28 | #ifndef WIN32 29 | #include 30 | #endif 31 | 32 | #include 33 | 34 | enum { ARTNET_MAX_RDM_ADCOUNT = 32 }; 35 | 36 | enum { ARTNET_MAX_UID_COUNT = 200 }; 37 | 38 | // according to the rdm spec, this should be 278 bytes 39 | // we'll set to 512 here, the firmware datagram is still bigger 40 | enum { ARTNET_MAX_RDM_DATA = 512 }; 41 | 42 | enum { ARTNET_FIRMWARE_SIZE = 512 }; 43 | 44 | enum artnet_packet_type_e { 45 | ARTNET_POLL = 0x2000, 46 | ARTNET_REPLY = 0x2100, 47 | ARTNET_DMX = 0x5000, 48 | ARTNET_ADDRESS = 0x6000, 49 | ARTNET_INPUT = 0x7000, 50 | ARTNET_TODREQUEST = 0x8000, 51 | ARTNET_TODDATA = 0x8100, 52 | ARTNET_TODCONTROL = 0x8200, 53 | ARTNET_RDM = 0x8300, 54 | ARTNET_VIDEOSTEUP = 0xa010, 55 | ARTNET_VIDEOPALETTE = 0xa020, 56 | ARTNET_VIDEODATA = 0xa040, 57 | ARTNET_MACMASTER = 0xf000, 58 | ARTNET_MACSLAVE = 0xf100, 59 | ARTNET_FIRMWAREMASTER = 0xf200, 60 | ARTNET_FIRMWAREREPLY = 0xf300, 61 | ARTNET_IPPROG = 0xf800, 62 | ARTNET_IPREPLY = 0xf900, 63 | ARTNET_MEDIA = 0x9000, 64 | ARTNET_MEDIAPATCH = 0x9200, 65 | ARTNET_MEDIACONTROLREPLY = 0x9300 66 | }__attribute__((packed)); 67 | 68 | typedef enum artnet_packet_type_e artnet_packet_type_t; 69 | 70 | 71 | struct artnet_poll_s { 72 | uint8_t id[8]; 73 | uint16_t opCode; 74 | uint8_t verH; 75 | uint8_t ver; 76 | uint8_t ttm; 77 | uint8_t pad; 78 | } __attribute__((packed)); 79 | 80 | typedef struct artnet_poll_s artnet_poll_t; 81 | 82 | struct artnet_reply_s { 83 | uint8_t id[8]; 84 | uint16_t opCode; 85 | uint8_t ip[4]; 86 | uint16_t port; 87 | uint8_t verH; 88 | uint8_t ver; 89 | uint8_t subH; 90 | uint8_t sub; 91 | uint8_t oemH; 92 | uint8_t oem; 93 | uint8_t ubea; 94 | uint8_t status; 95 | uint8_t etsaman[2]; 96 | uint8_t shortname[ARTNET_SHORT_NAME_LENGTH]; 97 | uint8_t longname[ARTNET_LONG_NAME_LENGTH]; 98 | uint8_t nodereport[ARTNET_REPORT_LENGTH]; 99 | uint8_t numbportsH; 100 | uint8_t numbports; 101 | uint8_t porttypes[ARTNET_MAX_PORTS]; 102 | uint8_t goodinput[ARTNET_MAX_PORTS]; 103 | uint8_t goodoutput[ARTNET_MAX_PORTS]; 104 | uint8_t swin[ARTNET_MAX_PORTS]; 105 | uint8_t swout[ARTNET_MAX_PORTS]; 106 | uint8_t swvideo; 107 | uint8_t swmacro; 108 | uint8_t swremote; 109 | uint8_t sp1; 110 | uint8_t sp2; 111 | uint8_t sp3; 112 | uint8_t style; 113 | uint8_t mac[ARTNET_MAC_SIZE]; 114 | uint8_t filler[32]; 115 | } __attribute__((packed)); 116 | 117 | typedef struct artnet_reply_s artnet_reply_t; 118 | 119 | struct artnet_ipprog_s { 120 | uint8_t id[8]; 121 | uint16_t OpCode; 122 | uint8_t ProVerH; 123 | uint8_t ProVer; 124 | uint8_t Filler1; 125 | uint8_t Filler2; 126 | uint8_t Command; 127 | uint8_t Filler4; 128 | uint8_t ProgIpHi; 129 | uint8_t ProgIp2; 130 | uint8_t ProgIp1; 131 | uint8_t ProgIpLo; 132 | uint8_t ProgSmHi; 133 | uint8_t ProgSm2; 134 | uint8_t ProgSm1; 135 | uint8_t ProgSmLo; 136 | uint8_t ProgPortHi; 137 | uint8_t ProgPortLo; 138 | uint8_t Spare1; 139 | uint8_t Spare2; 140 | uint8_t Spare3; 141 | uint8_t Spare4; 142 | uint8_t Spare5; 143 | uint8_t Spare6; 144 | uint8_t Spare7; 145 | uint8_t Spare8; 146 | 147 | } __attribute__((packed)); 148 | 149 | typedef struct artnet_ipprog_s artnet_ipprog_t; 150 | 151 | struct artnet_ipprog_reply_s { 152 | uint8_t id[8]; 153 | uint16_t OpCode; 154 | uint8_t ProVerH; 155 | uint8_t ProVer; 156 | uint8_t Filler1; 157 | uint8_t Filler2; 158 | uint8_t Filler3; 159 | uint8_t Filler4; 160 | uint8_t ProgIpHi; 161 | uint8_t ProgIp2; 162 | uint8_t ProgIp1; 163 | uint8_t ProgIpLo; 164 | uint8_t ProgSmHi; 165 | uint8_t ProgSm2; 166 | uint8_t ProgSm1; 167 | uint8_t ProgSmLo; 168 | uint8_t ProgPortHi; 169 | uint8_t ProgPortLo; 170 | uint8_t Spare1; 171 | uint8_t Spare2; 172 | uint8_t Spare3; 173 | uint8_t Spare4; 174 | uint8_t Spare5; 175 | uint8_t Spare6; 176 | uint8_t Spare7; 177 | uint8_t Spare8; 178 | } __attribute__((packed)); 179 | 180 | typedef struct artnet_ipprog_reply_s artnet_ipprog_reply_t; 181 | 182 | 183 | struct artnet_address_s { 184 | uint8_t id[8]; 185 | uint16_t opCode; 186 | uint8_t verH; 187 | uint8_t ver; 188 | uint8_t filler1; 189 | uint8_t filler2; 190 | uint8_t shortname[ARTNET_SHORT_NAME_LENGTH]; 191 | uint8_t longname[ARTNET_LONG_NAME_LENGTH]; 192 | uint8_t swin[ARTNET_MAX_PORTS]; 193 | uint8_t swout[ARTNET_MAX_PORTS]; 194 | uint8_t subnet; 195 | uint8_t swvideo; 196 | uint8_t command; 197 | } __attribute__((packed)); 198 | 199 | typedef struct artnet_address_s artnet_address_t; 200 | 201 | 202 | struct artnet_dmx_s { 203 | uint8_t id[8]; 204 | uint16_t opCode; 205 | uint8_t verH; 206 | uint8_t ver; 207 | uint8_t sequence; 208 | uint8_t physical; 209 | uint16_t universe; 210 | uint8_t lengthHi; 211 | uint8_t length; 212 | uint8_t data[ARTNET_DMX_LENGTH]; 213 | } __attribute__((packed)); 214 | 215 | typedef struct artnet_dmx_s artnet_dmx_t; 216 | 217 | 218 | struct artnet_input_s { 219 | uint8_t id[8]; 220 | uint16_t opCode; 221 | uint8_t verH; 222 | uint8_t ver; 223 | uint8_t filler1; 224 | uint8_t filler2; 225 | uint8_t numbportsH; 226 | uint8_t numbports; 227 | uint8_t input[ARTNET_MAX_PORTS]; 228 | } __attribute__((packed)); 229 | 230 | typedef struct artnet_input_s artnet_input_t; 231 | 232 | 233 | struct artnet_todrequest_s { 234 | uint8_t id[8]; 235 | uint16_t opCode; 236 | uint8_t verH; 237 | uint8_t ver; 238 | uint8_t filler1; 239 | uint8_t filler2; 240 | uint8_t spare1; 241 | uint8_t spare2; 242 | uint8_t spare3; 243 | uint8_t spare4; 244 | uint8_t spare5; 245 | uint8_t spare6; 246 | uint8_t spare7; 247 | uint8_t spare8; 248 | uint8_t command; 249 | uint8_t adCount; 250 | uint8_t address[ARTNET_MAX_RDM_ADCOUNT]; 251 | } __attribute__((packed)); 252 | 253 | typedef struct artnet_todrequest_s artnet_todrequest_t; 254 | 255 | 256 | 257 | struct artnet_toddata_s { 258 | uint8_t id[8]; 259 | uint16_t opCode; 260 | uint8_t verH; 261 | uint8_t ver; 262 | uint8_t rdmVer; 263 | uint8_t port; 264 | uint8_t spare1; 265 | uint8_t spare2; 266 | uint8_t spare3; 267 | uint8_t spare4; 268 | uint8_t spare5; 269 | uint8_t spare6; 270 | uint8_t spare7; 271 | uint8_t spare8; 272 | uint8_t cmdRes; 273 | uint8_t address; 274 | uint8_t uidTotalHi; 275 | uint8_t uidTotal; 276 | uint8_t blockCount; 277 | uint8_t uidCount; 278 | uint8_t tod[ARTNET_MAX_UID_COUNT][ARTNET_RDM_UID_WIDTH]; 279 | } __attribute__((packed)); 280 | 281 | typedef struct artnet_toddata_s artnet_toddata_t; 282 | 283 | struct artnet_firmware_s { 284 | uint8_t id[8]; 285 | uint16_t opCode; 286 | uint8_t verH; 287 | uint8_t ver; 288 | uint8_t filler1; 289 | uint8_t filler2; 290 | uint8_t type; 291 | uint8_t blockId; 292 | uint8_t length[4]; 293 | uint8_t spare[20]; 294 | uint16_t data[ARTNET_FIRMWARE_SIZE ]; 295 | } __attribute__((packed)); 296 | 297 | typedef struct artnet_firmware_s artnet_firmware_t; 298 | 299 | struct artnet_todcontrol_s { 300 | uint8_t id[8]; 301 | uint16_t opCode; 302 | uint8_t verH; 303 | uint8_t ver; 304 | uint8_t filler1; 305 | uint8_t filler2; 306 | uint8_t spare1; 307 | uint8_t spare2; 308 | uint8_t spare3; 309 | uint8_t spare4; 310 | uint8_t spare5; 311 | uint8_t spare6; 312 | uint8_t spare7; 313 | uint8_t spare8; 314 | uint8_t cmd; 315 | uint8_t address; 316 | } __attribute__((packed)); 317 | 318 | 319 | typedef struct artnet_todcontrol_s artnet_todcontrol_t; 320 | 321 | 322 | 323 | struct artnet_rdm_s { 324 | uint8_t id[8]; 325 | uint16_t opCode; 326 | uint8_t verH; 327 | uint8_t ver; 328 | uint8_t rdmVer; 329 | uint8_t filler2; 330 | uint8_t spare1; 331 | uint8_t spare2; 332 | uint8_t spare3; 333 | uint8_t spare4; 334 | uint8_t spare5; 335 | uint8_t spare6; 336 | uint8_t spare7; 337 | uint8_t spare8; 338 | uint8_t cmd; 339 | uint8_t address; 340 | uint8_t data[ARTNET_MAX_RDM_DATA]; 341 | } __attribute__((packed)); 342 | 343 | 344 | typedef struct artnet_rdm_s artnet_rdm_t; 345 | 346 | 347 | struct artnet_firmware_reply_s { 348 | uint8_t id[8]; 349 | uint16_t opCode; 350 | uint8_t verH; 351 | uint8_t ver; 352 | uint8_t filler1; 353 | uint8_t filler2; 354 | uint8_t type; 355 | uint8_t spare[21]; 356 | } __attribute__((packed)); 357 | 358 | typedef struct artnet_firmware_reply_s artnet_firmware_reply_t; 359 | 360 | 361 | 362 | // union of all artnet packets 363 | typedef union { 364 | artnet_poll_t ap; 365 | artnet_reply_t ar; 366 | artnet_ipprog_t aip; 367 | artnet_address_t addr; 368 | artnet_dmx_t admx; 369 | artnet_input_t ainput; 370 | artnet_todrequest_t todreq; 371 | artnet_toddata_t toddata; 372 | artnet_firmware_t firmware; 373 | artnet_firmware_reply_t firmwarer; 374 | artnet_todcontrol_t todcontrol; 375 | artnet_rdm_t rdm; 376 | } artnet_packet_union_t; 377 | 378 | 379 | // a packet, containing data, length, type and a src/dst address 380 | typedef struct { 381 | int length; 382 | struct in_addr from; 383 | struct in_addr to; 384 | artnet_packet_type_t type; 385 | artnet_packet_union_t data; 386 | } artnet_packet_t; 387 | 388 | typedef artnet_packet_t *artnet_packet; 389 | 390 | #endif 391 | -------------------------------------------------------------------------------- /artnet/private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library; if not, write to the Free Software 14 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | * 16 | * private.h 17 | * Private definitions, data structures, macros and functions for libartnet 18 | * Copyright (C) 2004-2007 Simon Newton 19 | */ 20 | 21 | #if HAVE_CONFIG_H 22 | # include 23 | #endif 24 | 25 | #ifndef WIN32 26 | #include 27 | #include 28 | #include 29 | #endif 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "artnet.h" 37 | #include "artnet/packets.h" 38 | #include "misc.h" 39 | #include "tod.h" 40 | 41 | #ifndef ARTNET_PRIVATE_H 42 | #define ARTNET_PRIVATE_H 43 | 44 | // these are defined in artnet.c 45 | extern int ARTNET_PORT; 46 | extern char ARTNET_STRING[]; 47 | extern int ARTNET_STRING_SIZE; 48 | extern uint8_t ARTNET_VERSION; 49 | extern uint8_t OEM_HI; 50 | extern uint8_t OEM_LO; 51 | extern char ESTA_HI; 52 | extern char ESTA_LO; 53 | extern uint8_t TTM_BEHAVIOUR_MASK; 54 | extern uint8_t TTM_REPLY_MASK; 55 | extern uint8_t PROGRAM_NO_CHANGE; 56 | extern uint8_t PROGRAM_DEFAULTS; 57 | extern uint8_t PROGRAM_CHANGE_MASK; 58 | extern uint8_t HIGH_NIBBLE; 59 | extern uint8_t LOW_NIBBLE; 60 | extern uint8_t STATUS_PROG_AUTH_MASK; 61 | extern uint8_t PORT_STATUS_LPT_MODE; 62 | extern uint8_t PORT_STATUS_SHORT; 63 | extern uint8_t PORT_STATUS_ERROR; 64 | extern uint8_t PORT_STATUS_DISABLED_MASK; 65 | extern uint8_t ORT_STATUS_MERGE; 66 | extern uint8_t PORT_STATUS_DMX_TEXT; 67 | extern uint8_t PORT_STATUS_DMX_SIP; 68 | extern uint8_t PORT_STATUS_DMX_TEST; 69 | extern uint8_t PORT_STATUS_ACT_MASK; 70 | extern uint8_t PORT_DISABLE_MASK; 71 | extern uint8_t TOD_RESPONSE_FULL; 72 | extern uint8_t TOD_RESPONSE_NAK; 73 | extern uint8_t MIN_PACKET_SIZE; 74 | extern uint8_t MERGE_TIMEOUT_SECONDS; 75 | extern uint8_t FIRMWARE_TIMEOUT_SECONDS; 76 | extern uint8_t RECV_NO_DATA; 77 | 78 | #ifndef TRUE 79 | extern int TRUE; 80 | extern int FALSE; 81 | #endif 82 | 83 | extern uint16_t LOW_BYTE; 84 | extern uint16_t HIGH_BYTE; 85 | 86 | // non artnet specific 87 | #define SA struct sockaddr 88 | #define SI struct in_addr 89 | 90 | #ifndef min 91 | #define min(a, b) ((a) < (b) ? (a) : (b)) 92 | #endif 93 | 94 | #ifndef max 95 | #define max(a, b) ((a) > (b) ? (a) : (b)) 96 | #endif 97 | 98 | #ifndef INVALID_SOCKET 99 | #define INVALID_SOCKET -1 100 | #endif 101 | 102 | // byte ordering macros 103 | #ifndef bswap_16 104 | #define bswap_16(x) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)) 105 | #endif 106 | // htols : convert short from host to little endian order 107 | #ifdef WIN32 108 | # define htols(x) (x) 109 | #else 110 | # ifdef HAVE_ENDIAN_H 111 | # if BYTE_ORDER == __BIG_ENDIAN 112 | # define htols(x) bswap_16 (x) 113 | # else 114 | # define htols(x) (x) 115 | # endif 116 | # else 117 | # if BYTE_ORDER == BIG_ENDIAN 118 | # define htols(x) bswap_16 (x) 119 | # else 120 | # define htols(x) (x) 121 | # endif 122 | # endif 123 | #endif 124 | 125 | // convert from shorts to bytes and back again 126 | #define short_get_high_byte(x) ((HIGH_BYTE & x) >> 8) 127 | #define short_get_low_byte(x) (LOW_BYTE & x) 128 | 129 | #define bytes_to_short(h,l) ( ((h << 8) & 0xff00) | (l & 0x00FF) ); 130 | 131 | /* 132 | * These are enums for fields in packets 133 | * Ordered by packets they appear in. Some of these appear in the public header file 134 | * artnet.h if they have to be used by the user. 135 | * 136 | * They are all in the form artnet_xxx_code in case they have to be made public some day 137 | * 138 | */ 139 | 140 | // ArtPollReply 141 | //----------------------------------------------------------------------------- 142 | 143 | // the node report codes 144 | typedef enum { 145 | ARTNET_RCDEBUG, 146 | ARTNET_RCPOWEROK, 147 | ARTNET_RCPOWERFAIL, 148 | ARTNET_RCSOCKETWR1, 149 | ARTNET_RCPARSEFAIL, 150 | ARTNET_RCUDPFAIL, 151 | ARTNET_RCSHNAMEOK, 152 | ARTNET_RCLONAMEOK, 153 | ARTNET_RCDMXERROR, 154 | ARTNET_RCDMXUDPFULL, 155 | ARTNET_RCDMXRXFULL, 156 | ARTNET_RCSWITCHERR, 157 | ARTNET_RCCONFIGERR, 158 | ARTNET_RCDMXSHORT, 159 | ARTNET_RCFIRMWAREFAIL, 160 | ARTNET_RCUSERFAIL 161 | } artnet_node_report_code; 162 | 163 | // these define the types of node that can exist 164 | // note it's different from artnet_node_type 165 | typedef enum { 166 | STNODE = 0x00, 167 | STSERVER = 0x01, 168 | STMEDIA = 0x02, 169 | STROUTE = 0x03, 170 | STBACKUP = 0x04, 171 | STCONFIG = 0x05 172 | } artnet_node_style_code; 173 | 174 | // artnet_port_data in artnet.h 175 | 176 | // ArtAddress 177 | //----------------------------------------------------------------------------- 178 | 179 | // artnet_port_command_code in artnet.h 180 | 181 | // ArtFirmwareMaster 182 | //----------------------------------------------------------------------------- 183 | 184 | // defines contents of the firmware packet 185 | typedef enum { 186 | ARTNET_FIRMWARE_FIRMFIRST = 0x00, 187 | ARTNET_FIRMWARE_FIRMCONT = 0x01, 188 | ARTNET_FIRMWARE_FIRMLAST = 0x02, 189 | ARTNET_FIRMWARE_UBEAFIRST = 0x03, 190 | ARTNET_FIRMWARE_UBEACONT = 0x04, 191 | ARTNET_FIRMWARE_UBEALAST = 0x05, 192 | } artnet_firmware_type_code; 193 | 194 | // ArtFirmwareReply 195 | //----------------------------------------------------------------------------- 196 | 197 | // artnet_firmware_status_code in artnet.h 198 | 199 | 200 | 201 | // End packet enums 202 | //----------------------------------------------------------------------------- 203 | 204 | 205 | /* 206 | * Data structures to manage callbacks 207 | */ 208 | 209 | // packet callbacks have a function and some user data 210 | typedef struct { 211 | int (*fh)(artnet_node n, void *p, void *data); 212 | void *data; 213 | } callback_t; 214 | 215 | /* 216 | * the dmx callback is triggered when a dmx packet arrives 217 | */ 218 | typedef struct { 219 | int (*fh)(artnet_node n, int portid, void *data); 220 | void *data; 221 | } dmx_callback_t; 222 | 223 | /* 224 | * firmware callback is triggered when a firmware recieve has been completed sucessfully 225 | */ 226 | typedef struct { 227 | int (*fh)(artnet_node n, int ubea, uint16_t *data, int length, void *d); 228 | void *data; 229 | } firmware_callback_t; 230 | 231 | /* 232 | * called when a node is remote programmed 233 | */ 234 | typedef struct { 235 | int (*fh)(artnet_node n, void *d); 236 | void *data; 237 | } program_callback_t; 238 | 239 | /* 240 | * called when a node receives rdm data 241 | */ 242 | typedef struct { 243 | int (*fh)(artnet_node n, int address, uint8_t *rdm, int length, void *d); 244 | void *data; 245 | } rdm_callback_t; 246 | 247 | 248 | // struct to store callbacks 249 | typedef struct { 250 | callback_t recv; 251 | callback_t send; 252 | callback_t poll; 253 | callback_t reply; 254 | callback_t dmx; 255 | callback_t address; 256 | callback_t input; 257 | callback_t todrequest; 258 | callback_t toddata; 259 | callback_t todcontrol; 260 | callback_t rdm; 261 | callback_t ipprog; 262 | callback_t firmware; 263 | callback_t firmware_reply; 264 | dmx_callback_t dmx_c; 265 | firmware_callback_t firmware_c; 266 | program_callback_t program_c; 267 | rdm_callback_t rdm_c; 268 | dmx_callback_t rdm_init_c; 269 | dmx_callback_t rdm_tod_c; 270 | } node_callbacks_t; 271 | 272 | 273 | // End callback structures 274 | //----------------------------------------------------------------------------- 275 | 276 | /* 277 | * Begin port structures 278 | */ 279 | 280 | 281 | 282 | // first a generic port 283 | typedef struct { 284 | uint8_t addr; // the port address 285 | uint8_t default_addr; // the address set by the hardware 286 | uint8_t net_ctl; // if the port address is under network control 287 | uint8_t status; // status of the port 288 | uint8_t enabled; // true if the port has had it's address set, this is internal only, 289 | // it's not used by the ArtNet protocol, otherwise the node keeps 290 | // picking up packets for the 0x00 port 291 | tod_t tod; 292 | } g_port_t; 293 | 294 | /** 295 | * struct to represent an input port 296 | * input ports need to keep track of sequence numbers 297 | * (this doesn't seem to be used though) 298 | */ 299 | typedef struct { 300 | g_port_t port; 301 | uint8_t seq; 302 | } input_port_t; 303 | 304 | 305 | /** 306 | * For output ports we need to track if they merge in HTP or LTP modes 307 | */ 308 | typedef enum { 309 | ARTNET_MERGE_HTP, 310 | ARTNET_MERGE_LTP 311 | } merge_t; 312 | 313 | /** 314 | * struct to represent an output port 315 | * 316 | * output ports can merge data from two sources in either HTP 317 | * (highest takes precedence) or LPT (lowest takes precedence) mode 318 | * 319 | * we need to store: 320 | * o The data from each source 321 | * o The ip of the source 322 | * o The time the data was recv'ed 323 | * o the tod table, length and max length 324 | */ 325 | typedef struct { 326 | g_port_t port; 327 | int length; // the length of the data THAT HAS CHANGED since the last dmx packet 328 | uint8_t enabled; // true if the port has had it's address set, this is internal only, 329 | // it's not used by the ArtNet protocol, otherwise the node keeps 330 | // picking up packets for the 0x00 port 331 | uint8_t data[ARTNET_DMX_LENGTH]; // output data 332 | merge_t merge_mode; // for merging 333 | uint8_t dataA[ARTNET_DMX_LENGTH]; 334 | uint8_t dataB[ARTNET_DMX_LENGTH]; 335 | time_t timeA; 336 | time_t timeB; 337 | SI ipA; 338 | SI ipB; 339 | } output_port_t; 340 | 341 | // use defines to hide the inner structures 342 | #define port_addr port.addr 343 | #define port_default_addr port.default_addr 344 | #define port_net_ctl port.net_ctl 345 | #define port_status port.status 346 | #define port_enabled port.enabled 347 | #define port_tod port.tod 348 | 349 | // End port structures 350 | //----------------------------------------------------------------------------- 351 | 352 | 353 | /* 354 | * We use a linked list to keep track of nodes on the network 355 | * Here be the structures 356 | */ 357 | 358 | /* firstly we have the potential to do a firmware transfer to any node, 359 | * this struct keeps the information such as how much data has been transfered 360 | * and the address of the peer. It's also used for receiving firmware 361 | */ 362 | typedef struct { 363 | uint16_t *data; 364 | int bytes_current; 365 | int bytes_total; 366 | struct in_addr peer; 367 | int ubea; 368 | time_t last_time; 369 | int expected_block; 370 | int (*callback)(artnet_node n, artnet_firmware_status_code code, void *d); 371 | void *user_data; 372 | } firmware_transfer_t; 373 | 374 | /* 375 | * The node entry in the LL. It contains the public entry, as well as some stuff 376 | * we don't want public like firmware 377 | */ 378 | typedef struct node_entry_private_s { 379 | artnet_node_entry_t pub; 380 | struct node_entry_private_s *next; 381 | firmware_transfer_t firmware; 382 | SI ip; // don't rely on the ip address that the node 383 | // sends, they could be faking it. This is the ip that 384 | // the pollreply was sent from 385 | } node_entry_private_t; 386 | 387 | /** 388 | * The node list stores a pointer to the first, last and current 389 | * entries. 390 | */ 391 | typedef struct { 392 | node_entry_private_t *first; 393 | node_entry_private_t *current; 394 | node_entry_private_t *last; 395 | int length; 396 | } node_list_t; 397 | 398 | 399 | // End node list structures 400 | //----------------------------------------------------------------------------- 401 | 402 | 403 | // the status of the node 404 | typedef enum { 405 | ARTNET_OFF, 406 | ARTNET_STANDBY, 407 | ARTNET_ON 408 | } node_status_t; 409 | 410 | 411 | // struct to hold the state of the node 412 | typedef struct { 413 | artnet_node_type node_type; 414 | node_status_t mode; 415 | SI reply_addr; 416 | SI ip_addr; 417 | SI bcast_addr; 418 | uint8_t hw_addr[ARTNET_MAC_SIZE]; 419 | uint8_t default_subnet; 420 | uint8_t subnet_net_ctl; 421 | int send_apr_on_change; 422 | int ar_count; 423 | int verbose; 424 | char short_name[ARTNET_SHORT_NAME_LENGTH]; 425 | char long_name[ARTNET_LONG_NAME_LENGTH]; 426 | char report[ARTNET_REPORT_LENGTH]; 427 | uint8_t subnet; 428 | uint8_t oem_hi; 429 | uint8_t oem_lo; 430 | uint8_t esta_hi; 431 | uint8_t esta_lo; 432 | int bcast_limit; // the number of nodes after which we change to bcast 433 | artnet_node_report_code report_code; 434 | } node_state_t; 435 | 436 | 437 | typedef struct { 438 | struct artnet_node_s *peer; // peer if we've joined a group 439 | int master; 440 | } node_peering_t; 441 | 442 | 443 | /** 444 | * The main node structure 445 | */ 446 | typedef struct artnet_node_s{ 447 | int sd; // the two sockets 448 | node_state_t state; // the state struct 449 | node_callbacks_t callbacks; // the callbacks struct 450 | struct ports_s { 451 | uint8_t types[ARTNET_MAX_PORTS]; // type of port 452 | input_port_t in[ARTNET_MAX_PORTS]; // input ports 453 | output_port_t out[ARTNET_MAX_PORTS]; // output ports 454 | } ports; 455 | artnet_reply_t ar_temp; // buffered artpoll reply packet 456 | node_list_t node_list; // node list 457 | firmware_transfer_t firmware; // firmware details 458 | node_peering_t peering; // peer if we've joined a group 459 | } artnet_node_t; 460 | 461 | 462 | typedef artnet_node_t *node; 463 | 464 | /* 465 | * Function definitions follow 466 | */ 467 | 468 | // exported from artnet.c 469 | node_entry_private_t *find_private_entry( node n, artnet_node_entry e); 470 | void check_timeouts(node n); 471 | node_entry_private_t *find_entry_from_ip(node_list_t *nl, SI ip); 472 | int artnet_nl_update(node_list_t *nl, artnet_packet reply); 473 | 474 | 475 | // exported from receive.c 476 | int handle(node n, artnet_packet p); 477 | int16_t get_type(artnet_packet p); 478 | void reset_firmware_upload(node n); 479 | 480 | 481 | // exported from transmit.c 482 | int artnet_tx_poll(node n, const char *ip, artnet_ttm_value_t ttm); 483 | int artnet_tx_poll_reply(node n, int reply); 484 | int artnet_tx_tod_data(node n, int id); 485 | int artnet_tx_firmware_reply(node n, in_addr_t ip, artnet_firmware_status_code code); 486 | int artnet_tx_firmware_packet(node n, firmware_transfer_t *firm ); 487 | int artnet_tx_tod_request(node n); 488 | int artnet_tx_tod_control(node n, uint8_t address, artnet_tod_command_code action); 489 | int artnet_tx_rdm(node n, uint8_t address, uint8_t *data, int length); 490 | int artnet_tx_build_art_poll_reply(node n); 491 | 492 | 493 | // exported from network.c 494 | int artnet_net_recv(node n, artnet_packet p, int block); 495 | int artnet_net_send(node n, artnet_packet p); 496 | int artnet_net_set_non_block(node n); 497 | int artnet_net_init(node n, const char *ip); 498 | int artnet_net_start(node n); 499 | int artnet_net_close(int sock); 500 | int artnet_net_join(node n1, node n2); 501 | int artnet_net_set_fdset(node n, fd_set *fdset); 502 | int artnet_net_inet_aton(const char *ip_address, struct in_addr *address); 503 | const char *artnet_net_last_error(); 504 | 505 | #endif 506 | -------------------------------------------------------------------------------- /artnet/receive.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library; if not, write to the Free Software 14 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | * 16 | * receive.c 17 | * Handles the receiving of datagrams 18 | * Copyright (C) 2004-2007 Simon Newton 19 | */ 20 | 21 | #include "private.h" 22 | 23 | uint8_t _make_addr(uint8_t subnet, uint8_t addr); 24 | void check_merge_timeouts(node n, int port); 25 | void merge(node n, int port, int length, uint8_t *latest); 26 | 27 | /* 28 | * Checks if the callback is defined, if so call it passing the packet and 29 | * the user supplied data. 30 | * If the callbacks return a non-zero result, further processing is canceled. 31 | */ 32 | int check_callback(node n, artnet_packet p, callback_t callback) { 33 | if (callback.fh != NULL) 34 | return callback.fh(n, p, callback.data); 35 | 36 | return 0; 37 | } 38 | 39 | 40 | /* 41 | * Handle an artpoll packet 42 | */ 43 | int handle_poll(node n, artnet_packet p) { 44 | // run callback if defined 45 | if (check_callback(n, p, n->callbacks.poll)) 46 | return ARTNET_EOK; 47 | 48 | if (n->state.node_type != ARTNET_RAW) { 49 | //if we're told to unicast further replies 50 | if (p->data.ap.ttm & TTM_REPLY_MASK) { 51 | n->state.reply_addr = p->from; 52 | } else { 53 | n->state.reply_addr.s_addr = n->state.bcast_addr.s_addr; 54 | } 55 | 56 | // if we are told to send updates when node conditions change 57 | if (p->data.ap.ttm & TTM_BEHAVIOUR_MASK) { 58 | n->state.send_apr_on_change = TRUE; 59 | } else { 60 | n->state.send_apr_on_change = FALSE; 61 | } 62 | 63 | return artnet_tx_poll_reply(n, TRUE); 64 | 65 | } 66 | return ARTNET_EOK; 67 | } 68 | 69 | /* 70 | * handle an art poll reply 71 | */ 72 | void handle_reply(node n, artnet_packet p) { 73 | // update the node list 74 | artnet_nl_update(&n->node_list, p); 75 | 76 | // run callback if defined 77 | if (check_callback(n, p, n->callbacks.reply)) 78 | return; 79 | } 80 | 81 | 82 | /* 83 | * handle a art dmx packet 84 | */ 85 | void handle_dmx(node n, artnet_packet p) { 86 | int i, data_length; 87 | output_port_t *port; 88 | in_addr_t ipA, ipB; 89 | 90 | // run callback if defined 91 | if (check_callback(n, p, n->callbacks.dmx)) 92 | return; 93 | 94 | data_length = (int) bytes_to_short(p->data.admx.lengthHi, 95 | p->data.admx.length); 96 | data_length = min(data_length, ARTNET_DMX_LENGTH); 97 | 98 | // find matching output ports 99 | for (i = 0; i < ARTNET_MAX_PORTS; i++) { 100 | // if the addr matches and this port is enabled 101 | if (p->data.admx.universe == n->ports.out[i].port_addr && 102 | n->ports.out[i].port_enabled) { 103 | 104 | port = &n->ports.out[i]; 105 | ipA = port->ipA.s_addr; 106 | ipB = port->ipB.s_addr; 107 | 108 | // ok packet matches this port 109 | n->ports.out[i].port_status = n->ports.out[i].port_status | PORT_STATUS_ACT_MASK; 110 | 111 | /** 112 | * 9 cases for merging depending on what the stored ips are. 113 | * here's the truth table 114 | * 115 | * 116 | * \ ipA # # # # 117 | * ------ # empty # # # 118 | * ipB \ # ( 0 ) # p.from # ! p.from # 119 | * ################################################## 120 | * # new node # continued # start # 121 | * empty # first # trans- # merge # 122 | * (0) # packet # mission # # 123 | * ################################################## 124 | * #continued # # cont # 125 | * p.from # trans- # invalid! # merge # 126 | * # mission # # # 127 | * ################################################## 128 | * # start # cont # # 129 | * ! p.from # merge # merge # discard # 130 | * # # # # 131 | * ################################################## 132 | * 133 | * The merge exits when: 134 | * o ACCancel command is received in an ArtAddress packet 135 | * (this is done in handle_address ) 136 | * o no data is recv'ed from one source in 10 seconds 137 | * 138 | */ 139 | 140 | check_merge_timeouts(n,i); 141 | 142 | if (ipA == 0 && ipB == 0) { 143 | // first packet recv on this port 144 | port->ipA.s_addr = p->from.s_addr; 145 | port->timeA = time(NULL); 146 | 147 | memcpy(&port->dataA, &p->data.admx.data, data_length); 148 | port->length = data_length; 149 | memcpy(&port->data, &p->data.admx.data, data_length); 150 | } 151 | else if (ipA == p->from.s_addr && ipB == 0) { 152 | //continued transmission from the same ip (source A) 153 | 154 | port->timeA = time(NULL); 155 | memcpy(&port->dataA, &p->data.admx.data, data_length); 156 | port->length = data_length; 157 | memcpy(&port->data, &p->data.admx.data, data_length); 158 | } 159 | else if (ipA == 0 && ipB == p->from.s_addr) { 160 | //continued transmission from the same ip (source B) 161 | 162 | port->timeB = time(NULL); 163 | memcpy(&port->dataB, &p->data.admx.data, data_length); 164 | port->length = data_length; 165 | memcpy(&port->data, &p->data.admx.data, data_length); 166 | } 167 | else if (ipA != p->from.s_addr && ipB == 0) { 168 | // new source, start the merge 169 | port->ipB.s_addr = p->from.s_addr; 170 | port->timeB = time(NULL); 171 | memcpy(&port->dataB, &p->data.admx.data,data_length); 172 | port->length = data_length; 173 | 174 | // merge, newest data is port B 175 | merge(n,i,data_length, port->dataB); 176 | 177 | // send reply if needed 178 | 179 | } 180 | else if (ipA == 0 && ipB == p->from.s_addr) { 181 | // new source, start the merge 182 | port->ipA.s_addr = p->from.s_addr; 183 | port->timeB = time(NULL); 184 | memcpy(&port->dataB, &p->data.admx.data,data_length); 185 | port->length = data_length; 186 | 187 | // merge, newest data is portA 188 | merge(n,i,data_length, port->dataA); 189 | 190 | // send reply if needed 191 | } 192 | else if (ipA == p->from.s_addr && ipB != p->from.s_addr) { 193 | // continue merge 194 | port->timeA = time(NULL); 195 | memcpy(&port->dataA, &p->data.admx.data,data_length); 196 | port->length = data_length; 197 | 198 | // merge, newest data is portA 199 | merge(n,i,data_length, port->dataA); 200 | 201 | } 202 | else if (ipA != p->from.s_addr && ipB == p->from.s_addr) { 203 | // continue merge 204 | port->timeB = time(NULL); 205 | memcpy(&port->dataB, &p->data.admx.data,data_length); 206 | port->length = data_length; 207 | 208 | // merge newest data is portB 209 | merge(n,i,data_length, port->dataB); 210 | 211 | } 212 | else if (ipA == p->from.s_addr && ipB == p->from.s_addr) { 213 | // err_warn("In handle_dmx, source matches both buffers, this shouldn't be happening!\n"); 214 | 215 | } 216 | else if (ipA != p->from.s_addr && ipB != p->from.s_addr) { 217 | // err_warn("In handle_dmx, more than two sources, discarding data\n"); 218 | 219 | } 220 | else { 221 | // err_warn("In handle_dmx, no cases matched, this shouldn't happen!\n"); 222 | 223 | } 224 | 225 | // do the dmx callback here 226 | if (n->callbacks.dmx_c.fh != NULL) 227 | n->callbacks.dmx_c.fh(n,i, n->callbacks.dmx_c.data); 228 | } 229 | } 230 | return; 231 | } 232 | 233 | 234 | /** 235 | * handle art address packet. 236 | * This can reprogram certain nodes settings such as short/long name, port 237 | * addresses, subnet address etc. 238 | * 239 | */ 240 | int handle_address(node n, artnet_packet p) { 241 | int i, old_subnet; 242 | int addr[ARTNET_MAX_PORTS]; 243 | int ret; 244 | 245 | if (check_callback(n, p, n->callbacks.address)) 246 | return ARTNET_EOK; 247 | 248 | // servers (and raw nodes) don't respond to address packets 249 | if (n->state.node_type == ARTNET_SRV || n->state.node_type == ARTNET_RAW) 250 | return ARTNET_EOK; 251 | 252 | // reprogram shortname if required 253 | if (p->data.addr.shortname[0] != PROGRAM_DEFAULTS && 254 | p->data.addr.shortname[0] != PROGRAM_NO_CHANGE) { 255 | memcpy(&n->state.short_name, &p->data.addr.shortname, ARTNET_SHORT_NAME_LENGTH); 256 | n->state.report_code = ARTNET_RCSHNAMEOK; 257 | } 258 | // reprogram long name if required 259 | if (p->data.addr.longname[0] != PROGRAM_DEFAULTS && 260 | p->data.addr.longname[0] != PROGRAM_NO_CHANGE) { 261 | memcpy(&n->state.long_name, &p->data.addr.longname, ARTNET_LONG_NAME_LENGTH); 262 | n->state.report_code = ARTNET_RCLONAMEOK; 263 | } 264 | 265 | // first of all store existing port addresses 266 | // then we can work out if they change 267 | for (i=0; i< ARTNET_MAX_PORTS; i++) { 268 | addr[i] = n->ports.in[i].port_addr; 269 | } 270 | 271 | // program subnet 272 | old_subnet = p->data.addr.subnet; 273 | if (p->data.addr.subnet == PROGRAM_DEFAULTS) { 274 | // reset to defaults 275 | n->state.subnet = n->state.default_subnet; 276 | n->state.subnet_net_ctl = FALSE; 277 | 278 | } else if (p->data.addr.subnet & PROGRAM_CHANGE_MASK) { 279 | n->state.subnet = p->data.addr.subnet & ~PROGRAM_CHANGE_MASK; 280 | n->state.subnet_net_ctl = TRUE; 281 | } 282 | 283 | // check if subnet has actually changed 284 | if (old_subnet != n->state.subnet) { 285 | // if it does we need to change all port addresses 286 | for(i=0; i< ARTNET_MAX_PORTS; i++) { 287 | n->ports.in[i].port_addr = _make_addr(n->state.subnet, n->ports.in[i].port_addr); 288 | n->ports.out[i].port_addr = _make_addr(n->state.subnet, n->ports.out[i].port_addr); 289 | } 290 | } 291 | 292 | // program swins 293 | for (i =0; i < ARTNET_MAX_PORTS; i++) { 294 | if (p->data.addr.swin[i] == PROGRAM_NO_CHANGE) { 295 | continue; 296 | } else if (p->data.addr.swin[i] == PROGRAM_DEFAULTS) { 297 | // reset to defaults 298 | n->ports.in[i].port_addr = _make_addr(n->state.subnet, n->ports.in[i].port_default_addr); 299 | n->ports.in[i].port_net_ctl = FALSE; 300 | 301 | } else if ( p->data.addr.swin[i] & PROGRAM_CHANGE_MASK) { 302 | n->ports.in[i].port_addr = _make_addr(n->state.subnet, p->data.addr.swin[i]); 303 | n->ports.in[i].port_net_ctl = TRUE; 304 | } 305 | } 306 | 307 | // program swouts 308 | for (i =0; i < ARTNET_MAX_PORTS; i++) { 309 | if (p->data.addr.swout[i] == PROGRAM_NO_CHANGE) { 310 | continue; 311 | } else if (p->data.addr.swout[i] == PROGRAM_DEFAULTS) { 312 | // reset to defaults 313 | n->ports.out[i].port_addr = _make_addr(n->state.subnet, n->ports.out[i].port_default_addr); 314 | n->ports.out[i].port_net_ctl = FALSE; 315 | n->ports.out[i].port_enabled = TRUE; 316 | } else if ( p->data.addr.swout[i] & PROGRAM_CHANGE_MASK) { 317 | n->ports.out[i].port_addr = _make_addr(n->state.subnet, p->data.addr.swout[i]); 318 | n->ports.in[i].port_net_ctl = TRUE; 319 | n->ports.out[i].port_enabled = TRUE; 320 | } 321 | } 322 | 323 | // reset sequence numbers if the addresses change 324 | for (i=0; i< ARTNET_MAX_PORTS; i++) { 325 | if (addr[i] != n->ports.in[i].port_addr) 326 | n->ports.in[i].seq = 0; 327 | } 328 | 329 | // check command 330 | switch (p->data.addr.command) { 331 | case ARTNET_PC_CANCEL: 332 | // fix me 333 | break; 334 | case ARTNET_PC_RESET: 335 | n->ports.out[0].port_status = n->ports.out[0].port_status & ~PORT_STATUS_DMX_SIP & ~PORT_STATUS_DMX_TEST & ~PORT_STATUS_DMX_TEXT; 336 | // need to force a rerun of short tests here 337 | break; 338 | case ARTNET_PC_MERGE_LTP_O: 339 | n->ports.out[0].merge_mode = ARTNET_MERGE_LTP; 340 | n->ports.out[0].port_status = n->ports.out[0].port_status | PORT_STATUS_LPT_MODE; 341 | break; 342 | case ARTNET_PC_MERGE_LTP_1: 343 | n->ports.out[1].merge_mode = ARTNET_MERGE_LTP; 344 | n->ports.out[1].port_status = n->ports.out[1].port_status | PORT_STATUS_LPT_MODE; 345 | break; 346 | case ARTNET_PC_MERGE_LTP_2: 347 | n->ports.out[2].merge_mode = ARTNET_MERGE_LTP; 348 | n->ports.out[2].port_status = n->ports.out[2].port_status | PORT_STATUS_LPT_MODE; 349 | break; 350 | case ARTNET_PC_MERGE_LTP_3: 351 | n->ports.out[3].merge_mode = ARTNET_MERGE_LTP; 352 | n->ports.out[3].port_status = n->ports.out[3].port_status | PORT_STATUS_LPT_MODE; 353 | break; 354 | case ARTNET_PC_MERGE_HTP_0: 355 | n->ports.out[0].merge_mode = ARTNET_MERGE_HTP; 356 | n->ports.out[0].port_status = n->ports.out[0].port_status | PORT_STATUS_LPT_MODE; 357 | break; 358 | case ARTNET_PC_MERGE_HTP_1: 359 | n->ports.out[1].merge_mode = ARTNET_MERGE_HTP; 360 | n->ports.out[1].port_status = n->ports.out[1].port_status | PORT_STATUS_LPT_MODE; 361 | break; 362 | case ARTNET_PC_MERGE_HTP_2: 363 | n->ports.out[2].merge_mode = ARTNET_MERGE_HTP; 364 | n->ports.out[2].port_status = n->ports.out[2].port_status | PORT_STATUS_LPT_MODE; 365 | break; 366 | case ARTNET_PC_MERGE_HTP_3: 367 | n->ports.out[3].merge_mode = ARTNET_MERGE_HTP; 368 | n->ports.out[3].port_status = n->ports.out[3].port_status | PORT_STATUS_LPT_MODE; 369 | break; 370 | 371 | } 372 | 373 | if (n->callbacks.program_c.fh != NULL) 374 | n->callbacks.program_c.fh(n , n->callbacks.program_c.data); 375 | 376 | if ((ret = artnet_tx_build_art_poll_reply(n))) 377 | return ret; 378 | 379 | return artnet_tx_poll_reply(n, TRUE); 380 | } 381 | 382 | 383 | /* 384 | * handle art input. 385 | * ArtInput packets can disable input ports. 386 | */ 387 | int _artnet_handle_input(node n, artnet_packet p) { 388 | int i, ports, ret; 389 | 390 | if (check_callback(n, p, n->callbacks.input)) 391 | return ARTNET_EOK; 392 | 393 | // servers (and raw nodes) don't respond to input packets 394 | if (n->state.node_type != ARTNET_NODE && n->state.node_type != ARTNET_MSRV) 395 | return ARTNET_EOK; 396 | 397 | ports = min( p->data.ainput.numbports, ARTNET_MAX_PORTS); 398 | for (i =0; i < ports; i++) { 399 | if (p->data.ainput.input[i] & PORT_DISABLE_MASK) { 400 | // disable 401 | n->ports.in[i].port_status = n->ports.in[i].port_status | PORT_STATUS_DISABLED_MASK; 402 | } else { 403 | // enable 404 | n->ports.in[i].port_status = n->ports.in[i].port_status & ~PORT_STATUS_DISABLED_MASK; 405 | } 406 | } 407 | 408 | if ((ret = artnet_tx_build_art_poll_reply(n))) 409 | return ret; 410 | 411 | return artnet_tx_poll_reply(n, TRUE); 412 | } 413 | 414 | 415 | /*** 416 | * handle tod request packet 417 | */ 418 | int handle_tod_request(node n, artnet_packet p) { 419 | int i, j, limit; 420 | int ret = ARTNET_EOK; 421 | 422 | if (check_callback(n, p, n->callbacks.todrequest)) 423 | return ARTNET_EOK; 424 | 425 | if (n->state.node_type != ARTNET_NODE) 426 | return ARTNET_EOK; 427 | 428 | // limit to 32 429 | limit = min(ARTNET_MAX_RDM_ADCOUNT, p->data.todreq.adCount); 430 | 431 | // this should always be true 432 | if (p->data.todreq.command == 0x00) { 433 | for (i=0; i < limit; i++) { 434 | for (j=0; j < ARTNET_MAX_PORTS; j++) { 435 | if (n->ports.out[j].port_addr == p->data.todreq.address[i] && 436 | n->ports.out[j].port_enabled) { 437 | // reply with tod 438 | ret = ret || artnet_tx_tod_data(n, j); 439 | } 440 | } 441 | } 442 | } 443 | 444 | // err_warn("tod request received but command is 0x%02hhx rather than 0x00\n", p->data.todreq.command); 445 | return ret; 446 | } 447 | 448 | /** 449 | * handle tod data packet 450 | * 451 | * we don't maintain a tod of whats out on the network, 452 | * the calling app can deal with this. 453 | */ 454 | void handle_tod_data(node n, artnet_packet p) { 455 | 456 | if (check_callback(n, p, n->callbacks.toddata)) 457 | return; 458 | 459 | // pass data to app 460 | 461 | // if (n->callbacks.rdm_tod_c.fh != NULL) 462 | // n->callbacks.rdm_tod_c.fh(n, i, n->callbacks.rdm_tod_c.data); 463 | 464 | return; 465 | } 466 | 467 | 468 | 469 | int handle_tod_control(node n, artnet_packet p) { 470 | int i; 471 | int ret = ARTNET_EOK; 472 | 473 | if (check_callback(n, p, n->callbacks.todcontrol)) 474 | return ARTNET_EOK; 475 | 476 | for (i=0; i < ARTNET_MAX_PORTS; i++) { 477 | if (n->ports.out[i].port_addr == p->data.todcontrol.address && 478 | n->ports.out[i].port_enabled) { 479 | 480 | if (p->data.todcontrol.cmd == ARTNET_TOD_FLUSH) { 481 | // flush tod for this port 482 | flush_tod(&n->ports.out[i].port_tod); 483 | 484 | //initiate full rdm discovery 485 | // do callback here 486 | if (n->callbacks.rdm_init_c.fh != NULL) 487 | n->callbacks.rdm_init_c.fh(n, i, n->callbacks.rdm_init_c.data); 488 | 489 | // not really sure what to do here, the calling app should do a rdm 490 | // init and call artnet_add_rdm_devices() which will send a tod data 491 | // but do we really trust the caller ? 492 | // Instead we'll send an empty tod data and then another one a bit later 493 | // when our tod is populated 494 | } 495 | // reply with tod 496 | ret = ret || artnet_tx_tod_data(n, i); 497 | } 498 | } 499 | return ret; 500 | } 501 | 502 | /** 503 | * handle rdm packet 504 | * 505 | */ 506 | void handle_rdm(node n, artnet_packet p) { 507 | 508 | 509 | if (check_callback(n, p, n->callbacks.rdm)) 510 | return; 511 | 512 | printf("rdm data\n"); 513 | 514 | // hell dodgy 515 | if (n->callbacks.rdm_c.fh != NULL) 516 | n->callbacks.rdm_c.fh(n, p->data.rdm.address, p->data.rdm.data, ARTNET_MAX_RDM_DATA, n->callbacks.rdm_c.data); 517 | 518 | return; 519 | } 520 | 521 | /** 522 | * handle a firmware master 523 | */ 524 | 525 | // THIS NEEDS TO BE CHECKED FOR BUFFER OVERFLOWS 526 | // IMPORTANT!!!! 527 | int handle_firmware(node n, artnet_packet p) { 528 | int length, offset, block_length, total_blocks, block_id; 529 | artnet_firmware_status_code response_code = ARTNET_FIRMWARE_FAIL; 530 | 531 | // run callback if defined 532 | if (check_callback(n, p, n->callbacks.firmware)) 533 | return ARTNET_EOK; 534 | 535 | /* 536 | * What happens if an upload is less than 512 bytes ????? 537 | */ 538 | 539 | if ( p->data.firmware.type == ARTNET_FIRMWARE_FIRMFIRST || 540 | p->data.firmware.type == ARTNET_FIRMWARE_UBEAFIRST) { 541 | // a new transfer is initiated 542 | 543 | if (n->firmware.peer.s_addr == 0) { 544 | //new transfer 545 | // these are 2 byte words, so we get a total of 1k of data per packet 546 | length = artnet_misc_nbytes_to_32( p->data.firmware.length ) * 547 | sizeof(p->data.firmware.data[0]); 548 | 549 | // set parameters 550 | n->firmware.peer.s_addr = p->from.s_addr; 551 | n->firmware.data = malloc(length); 552 | 553 | if (n->firmware.data == NULL) { 554 | artnet_error_malloc(); 555 | return ARTNET_EMEM; 556 | } 557 | n->firmware.bytes_total = length; 558 | n->firmware.last_time = time(NULL); 559 | n->firmware.expected_block = 1; 560 | 561 | // check if this is a ubea upload or not 562 | if (p->data.firmware.type == ARTNET_FIRMWARE_FIRMFIRST) 563 | n->firmware.ubea = 0; 564 | else 565 | n->firmware.ubea = 1; 566 | 567 | // take the minimum of the total length and the max packet size 568 | block_length = min((unsigned int) length, ARTNET_FIRMWARE_SIZE * 569 | sizeof(p->data.firmware.data[0])); 570 | 571 | memcpy(n->firmware.data, p->data.firmware.data, block_length); 572 | n->firmware.bytes_current = block_length; 573 | 574 | if (block_length == length) { 575 | // this is the first and last packet 576 | // upload was less than 1k bytes 577 | // this behaviour isn't in the spec, presumably no firmware will be less that 1k 578 | response_code = ARTNET_FIRMWARE_ALLGOOD; 579 | 580 | // do the callback here 581 | if (n->callbacks.firmware_c.fh != NULL) 582 | n->callbacks.firmware_c.fh(n, 583 | n->firmware.ubea, 584 | n->firmware.data, 585 | n->firmware.bytes_total, 586 | n->callbacks.firmware_c.data); 587 | 588 | } else { 589 | response_code = ARTNET_FIRMWARE_BLOCKGOOD; 590 | } 591 | 592 | } else { 593 | // already in a transfer 594 | printf("First, but already for a packet\n"); 595 | 596 | // send a failure 597 | response_code = ARTNET_FIRMWARE_FAIL; 598 | } 599 | 600 | } else if (p->data.firmware.type == ARTNET_FIRMWARE_FIRMCONT || 601 | p->data.firmware.type == ARTNET_FIRMWARE_UBEACONT) { 602 | // continued transfer 603 | length = artnet_misc_nbytes_to_32(p->data.firmware.length) * 604 | sizeof(p->data.firmware.data[0]); 605 | total_blocks = length / ARTNET_FIRMWARE_SIZE / 2 + 1; 606 | block_length = ARTNET_FIRMWARE_SIZE * sizeof(uint16_t); 607 | block_id = p->data.firmware.blockId; 608 | 609 | // ok the blockid field is only 1 byte, so it wraps back to 0x00 we 610 | // need to watch for this 611 | if (n->firmware.expected_block > UINT8_MAX && 612 | (n->firmware.expected_block % (UINT8_MAX+1)) == p->data.firmware.blockId) { 613 | 614 | block_id = n->firmware.expected_block; 615 | } 616 | offset = block_id * ARTNET_FIRMWARE_SIZE; 617 | 618 | if (n->firmware.peer.s_addr == p->from.s_addr && 619 | length == n->firmware.bytes_total && 620 | block_id < total_blocks-1) { 621 | 622 | memcpy(n->firmware.data + offset, p->data.firmware.data, block_length); 623 | n->firmware.bytes_current += block_length; 624 | n->firmware.expected_block++; 625 | 626 | response_code = ARTNET_FIRMWARE_BLOCKGOOD; 627 | } else { 628 | printf("cont, ips don't match or length has changed or out of range block num\n" ); 629 | 630 | // in a transfer not from this ip 631 | response_code = ARTNET_FIRMWARE_FAIL; 632 | } 633 | 634 | } else if (p->data.firmware.type == ARTNET_FIRMWARE_FIRMLAST || 635 | p->data.firmware.type == ARTNET_FIRMWARE_UBEALAST) { 636 | length = artnet_misc_nbytes_to_32( p->data.firmware.length) * 637 | sizeof(p->data.firmware.data[0]); 638 | total_blocks = length / ARTNET_FIRMWARE_SIZE / 2 + 1; 639 | 640 | // length should be the remaining data 641 | block_length = n->firmware.bytes_total % (ARTNET_FIRMWARE_SIZE * sizeof(uint16_t)); 642 | block_id = p->data.firmware.blockId; 643 | 644 | // ok the blockid field is only 1 byte, so it wraps back to 0x00 we 645 | // need to watch for this 646 | if (n->firmware.expected_block > UINT8_MAX && 647 | (n->firmware.expected_block % (UINT8_MAX+1)) == p->data.firmware.blockId) { 648 | 649 | block_id = n->firmware.expected_block; 650 | } 651 | offset = block_id * ARTNET_FIRMWARE_SIZE; 652 | 653 | if (n->firmware.peer.s_addr == p->from.s_addr && 654 | length == n->firmware.bytes_total && 655 | block_id == total_blocks-1) { 656 | 657 | // all the checks work out 658 | memcpy(n->firmware.data + offset, p->data.firmware.data, block_length); 659 | n->firmware.bytes_current += block_length; 660 | 661 | // do the callback here 662 | if (n->callbacks.firmware_c.fh != NULL) 663 | n->callbacks.firmware_c.fh(n, n->firmware.ubea, 664 | n->firmware.data, 665 | n->firmware.bytes_total / sizeof(p->data.firmware.data[0]), 666 | n->callbacks.firmware_c.data); 667 | 668 | // reset values and free 669 | reset_firmware_upload(n); 670 | 671 | response_code = ARTNET_FIRMWARE_ALLGOOD; 672 | printf("Firmware upload complete\n"); 673 | 674 | } else if (n->firmware.peer.s_addr != p->from.s_addr) { 675 | // in a transfer not from this ip 676 | printf("last, ips don't match\n" ); 677 | response_code = ARTNET_FIRMWARE_FAIL; 678 | } else if (length != n->firmware.bytes_total) { 679 | // they changed the length mid way thru a transfer 680 | printf("last, lengths have changed %d %d\n", length, n->firmware.bytes_total); 681 | response_code = ARTNET_FIRMWARE_FAIL; 682 | } else if (block_id != total_blocks -1) { 683 | // the blocks don't match up 684 | printf("This is the last block, but not according to the lengths %d %d\n", block_id, total_blocks -1); 685 | response_code = ARTNET_FIRMWARE_FAIL; 686 | } 687 | } 688 | 689 | return artnet_tx_firmware_reply(n, p->from.s_addr, response_code); 690 | } 691 | 692 | /** 693 | * handle an firmware reply 694 | */ 695 | int handle_firmware_reply(node n, artnet_packet p) { 696 | node_entry_private_t *ent; 697 | 698 | // run callback if defined 699 | if (check_callback(n, p, n->callbacks.firmware_reply)) 700 | return ARTNET_EOK; 701 | 702 | ent = find_entry_from_ip(&n->node_list, p->from); 703 | 704 | // node doesn't exist in our list, or we're not doing a transfer to this node 705 | if (ent== NULL || ent->firmware.bytes_total == 0) 706 | return ARTNET_EOK; 707 | 708 | // three types of response, ALLGOOD, BLOCKGOOD and FIRMFAIL 709 | if (p->data.firmwarer.type == ARTNET_FIRMWARE_ALLGOOD) { 710 | 711 | if (ent->firmware.bytes_total == ent->firmware.bytes_current) { 712 | // transfer complete 713 | 714 | // do the callback 715 | if (ent->firmware.callback != NULL) 716 | ent->firmware.callback(n, ARTNET_FIRMWARE_ALLGOOD, ent->firmware.user_data); 717 | 718 | memset(&ent->firmware, 0x0, sizeof(firmware_transfer_t)); 719 | 720 | } else { 721 | // random ALLGOOD received, don't let this abort the transfer 722 | printf("FIRMWARE_ALLGOOD received before transfer completed\n"); 723 | } 724 | 725 | } else if (p->data.firmwarer.type == ARTNET_FIRMWARE_FAIL) { 726 | 727 | // do the callback 728 | if (ent->firmware.callback != NULL) 729 | ent->firmware.callback(n, ARTNET_FIRMWARE_FAIL, ent->firmware.user_data); 730 | 731 | // cancel transfer 732 | memset(&ent->firmware, 0x0, sizeof(firmware_transfer_t)); 733 | 734 | } else if (p->data.firmwarer.type == ARTNET_FIRMWARE_BLOCKGOOD) { 735 | // send the next block (only if we're not done yet) 736 | if (ent->firmware.bytes_total != ent->firmware.bytes_current) { 737 | return artnet_tx_firmware_packet(n, &ent->firmware); 738 | } 739 | } 740 | return ARTNET_EOK; 741 | } 742 | 743 | 744 | /* 745 | * have to sort this one out. 746 | */ 747 | void handle_ipprog(node n, artnet_packet p) { 748 | 749 | if (check_callback(n, p, n->callbacks.ipprog)) 750 | return; 751 | 752 | printf("in ipprog\n"); 753 | } 754 | 755 | 756 | /* 757 | * The main handler for an artnet packet. calls 758 | * the appropriate handler function 759 | */ 760 | int handle(node n, artnet_packet p) { 761 | 762 | if (check_callback(n, p, n->callbacks.recv)) 763 | return 0; 764 | 765 | switch (p->type) { 766 | case ARTNET_POLL: 767 | handle_poll(n, p); 768 | break; 769 | case ARTNET_REPLY: 770 | handle_reply(n,p); 771 | break; 772 | case ARTNET_DMX: 773 | handle_dmx(n, p); 774 | break; 775 | case ARTNET_ADDRESS: 776 | handle_address(n, p); 777 | break; 778 | case ARTNET_INPUT: 779 | _artnet_handle_input(n, p); 780 | break; 781 | case ARTNET_TODREQUEST: 782 | handle_tod_request(n, p); 783 | break; 784 | case ARTNET_TODDATA: 785 | handle_tod_data(n, p); 786 | break; 787 | case ARTNET_TODCONTROL: 788 | handle_tod_control(n, p); 789 | break; 790 | case ARTNET_RDM: 791 | handle_rdm(n, p); 792 | break; 793 | case ARTNET_VIDEOSTEUP: 794 | printf("vid setup\n"); 795 | break; 796 | case ARTNET_VIDEOPALETTE: 797 | printf("video palette\n"); 798 | break; 799 | case ARTNET_VIDEODATA: 800 | printf("video data\n"); 801 | break; 802 | case ARTNET_MACMASTER: 803 | printf("mac master\n"); 804 | break; 805 | case ARTNET_MACSLAVE: 806 | printf("mac slave\n"); 807 | break; 808 | case ARTNET_FIRMWAREMASTER: 809 | handle_firmware(n, p); 810 | break; 811 | case ARTNET_FIRMWAREREPLY: 812 | handle_firmware_reply(n, p); 813 | break; 814 | case ARTNET_IPPROG : 815 | handle_ipprog(n, p); 816 | break; 817 | case ARTNET_IPREPLY: 818 | printf("ip reply\n"); 819 | break; 820 | case ARTNET_MEDIA: 821 | printf("media \n"); 822 | break; 823 | case ARTNET_MEDIAPATCH: 824 | printf("media patch\n"); 825 | break; 826 | case ARTNET_MEDIACONTROLREPLY: 827 | printf("media control reply\n"); 828 | break; 829 | default: 830 | n->state.report_code = ARTNET_RCPARSEFAIL; 831 | printf("artnet but not yet implemented!, op was %x\n", (int) p->type); 832 | } 833 | return 0; 834 | } 835 | 836 | /** 837 | * this gets the opcode from a packet 838 | */ 839 | int16_t get_type(artnet_packet p) { 840 | uint8_t *data; 841 | 842 | if (p->length < 10) 843 | return 0; 844 | if (!memcmp(&p->data, "Art-Net\0", 8)) { 845 | // not the best here, this needs to be tested on different arch 846 | data = (uint8_t *) &p->data; 847 | 848 | p->type = (data[9] << 8) + data[8]; 849 | return p->type; 850 | } else { 851 | return 0; 852 | } 853 | } 854 | 855 | 856 | /* 857 | * takes a subnet and an address and creates the universe address 858 | */ 859 | uint8_t _make_addr(uint8_t subnet, uint8_t addr) { 860 | return ((subnet & LOW_NIBBLE) << 4) | (addr & LOW_NIBBLE); 861 | } 862 | 863 | 864 | /* 865 | * 866 | */ 867 | void check_merge_timeouts(node n, int port_id) { 868 | output_port_t *port; 869 | time_t now; 870 | time_t timeoutA, timeoutB; 871 | port = &n->ports.out[port_id]; 872 | time(&now); 873 | timeoutA = now - port->timeA; 874 | timeoutB = now - port->timeB; 875 | 876 | if (timeoutA > MERGE_TIMEOUT_SECONDS) { 877 | // A is old, stop the merge 878 | port->ipA.s_addr = 0; 879 | } 880 | 881 | if (timeoutB > MERGE_TIMEOUT_SECONDS) { 882 | // B is old, stop the merge 883 | port->ipB.s_addr = 0; 884 | } 885 | } 886 | 887 | 888 | /* 889 | * merge the data from two sources 890 | */ 891 | void merge(node n, int port_id, int length, uint8_t *latest) { 892 | int i; 893 | output_port_t *port; 894 | port = &n->ports.out[port_id]; 895 | 896 | if (port->merge_mode == ARTNET_MERGE_HTP) { 897 | for (i=0; i< length; i++) 898 | port->data[i] = max(port->dataA[i], port->dataB[i]); 899 | } else { 900 | memcpy(port->data, latest, length); 901 | } 902 | } 903 | 904 | 905 | void reset_firmware_upload(node n) { 906 | n->firmware.bytes_current = 0; 907 | n->firmware.bytes_total = 0; 908 | n->firmware.peer.s_addr = 0; 909 | n->firmware.ubea = 0; 910 | n->firmware.last_time = 0; 911 | free(n->firmware.data); 912 | } 913 | -------------------------------------------------------------------------------- /artnet/tod.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library; if not, write to the Free Software 14 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | * 16 | * tod.c 17 | * Functions to manipulate the TOD 18 | * Copyright (C) 2004-2005 Simon Newton 19 | */ 20 | 21 | #include 22 | 23 | #include "tod.h" 24 | #include "misc.h" 25 | 26 | /* 27 | * adds a uid to the table of devices 28 | */ 29 | int add_tod_uid(tod_t *tod, uint8_t uid[ARTNET_RDM_UID_WIDTH]) { 30 | uint8_t *addr; 31 | int size; 32 | 33 | if (tod == NULL) 34 | return -1; 35 | 36 | if (tod->data == NULL) { 37 | // malloc 38 | tod->data = malloc(ARTNET_RDM_UID_WIDTH * ARTNET_TOD_INITIAL_SIZE); 39 | 40 | if (tod->data == NULL) { 41 | artnet_error_malloc(); 42 | return ARTNET_EMEM; 43 | } 44 | tod->length = 1; 45 | tod->max_length = ARTNET_TOD_INITIAL_SIZE; 46 | 47 | } else if (tod->length == tod->max_length) { 48 | // realloc 49 | size = (tod->max_length + ARTNET_TOD_INCREMENT); 50 | tod->data = realloc(tod->data, size * ARTNET_RDM_UID_WIDTH); 51 | 52 | if (tod->data == NULL) { 53 | artnet_error_realloc(); 54 | return ARTNET_EMEM; 55 | } 56 | 57 | tod->max_length = size; 58 | tod->length++; 59 | 60 | } else { 61 | tod->length++; 62 | } 63 | 64 | addr = tod->data + (tod->length-1) * ARTNET_RDM_UID_WIDTH; 65 | memcpy(addr, uid, ARTNET_RDM_UID_WIDTH); 66 | 67 | return 0; 68 | } 69 | 70 | /* 71 | * remove a uid from the table of devices 72 | * 73 | */ 74 | int remove_tod_uid(tod_t *tod, uint8_t uid[ARTNET_RDM_UID_WIDTH]) { 75 | int i; 76 | int offset = 0; 77 | uint8_t *last; 78 | 79 | if (tod == NULL) 80 | return -1; 81 | 82 | if (tod->data == NULL) 83 | return -1; 84 | 85 | for (i=0; i < tod->length; i++) { 86 | offset += ARTNET_RDM_UID_WIDTH; 87 | if (memcmp(tod->data + offset, uid, ARTNET_RDM_UID_WIDTH) == 0) 88 | break; 89 | } 90 | 91 | if (i == tod->length) { 92 | return -1; 93 | } else { 94 | 95 | last = tod->data + (tod->length-1) * ARTNET_RDM_UID_WIDTH; 96 | // copy the last entry over this one 97 | memcpy(tod->data + offset, last ,ARTNET_RDM_UID_WIDTH); 98 | 99 | tod->length--; 100 | return 0; 101 | } 102 | } 103 | 104 | /* 105 | * clear the table of devices 106 | */ 107 | int flush_tod(tod_t *tod) { 108 | if (tod == NULL) 109 | return -1; 110 | 111 | free(tod->data); 112 | tod->data = NULL; 113 | tod->length = 0; 114 | tod->max_length = 0; 115 | 116 | return 0; 117 | } 118 | 119 | 120 | int reset_tod(tod_t *tod) { 121 | if (tod == NULL) 122 | return -1; 123 | 124 | tod->data = NULL; 125 | tod->length = 0; 126 | tod->max_length = 0; 127 | return 0; 128 | } 129 | -------------------------------------------------------------------------------- /artnet/tod.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library; if not, write to the Free Software 14 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | * 16 | * tod.h 17 | * Header file for tod.h 18 | * Copyright (C) 2004-2005 Simon Newton 19 | */ 20 | 21 | #ifndef ARTNET_TOD_H 22 | #define ARTNET_TOD_H 23 | 24 | #include 25 | #include "common.h" 26 | 27 | enum { ARTNET_TOD_INITIAL_SIZE = 100 }; 28 | enum { ARTNET_TOD_INCREMENT = 50 }; 29 | 30 | /* 31 | * table of devices 32 | */ 33 | typedef struct { 34 | uint8_t *data; 35 | int length; 36 | int max_length; 37 | } tod_t; 38 | 39 | 40 | extern int add_tod_uid(tod_t *tod, uint8_t uid[ARTNET_RDM_UID_WIDTH]); 41 | extern int remove_tod_uid(tod_t *tod, uint8_t uid[ARTNET_RDM_UID_WIDTH]); 42 | extern int flush_tod(tod_t *tod); 43 | extern int reset_tod(tod_t *tod); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /artnet/transmit.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This library is free software; you can redistribute it and/or 3 | * modify it under the terms of the GNU Lesser General Public 4 | * License as published by the Free Software Foundation; either 5 | * version 2.1 of the License, or (at your option) any later version. 6 | * 7 | * This library is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | * Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public 13 | * License along with this library; if not, write to the Free Software 14 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | * 16 | * transmit.c 17 | * Functions to handle sending datagrams 18 | * Copyright (C) 2004-2005 Simon Newton 19 | */ 20 | 21 | #include "private.h" 22 | 23 | /* 24 | * Send an art poll 25 | * 26 | * @param ip the ip address to send to 27 | * @param ttm the talk to me value, either ARTNET_TTM_DEFAULT, 28 | * ARTNET_TTM_PRIVATE or ARTNET_TTM_AUTO 29 | */ 30 | int artnet_tx_poll(node n, const char *ip, artnet_ttm_value_t ttm) { 31 | artnet_packet_t p; 32 | int ret; 33 | 34 | if (n->state.mode != ARTNET_ON) 35 | return ARTNET_EACTION; 36 | 37 | if (n->state.node_type == ARTNET_SRV || n->state.node_type == ARTNET_RAW) { 38 | if (ip) { 39 | ret = artnet_net_inet_aton(ip, &p.to); 40 | if (ret) 41 | return ret; 42 | } else { 43 | p.to.s_addr = n->state.bcast_addr.s_addr; 44 | } 45 | 46 | memcpy(&p.data.ap.id, ARTNET_STRING, ARTNET_STRING_SIZE); 47 | p.data.ap.opCode = htols(ARTNET_POLL); 48 | p.data.ap.verH = 0; 49 | p.data.ap.ver = ARTNET_VERSION; 50 | p.data.ap.ttm = ~ttm; 51 | p.data.ap.pad = 0; 52 | 53 | p.length = sizeof(artnet_poll_t); 54 | return artnet_net_send(n, &p); 55 | 56 | } else { 57 | artnet_error("Not sending poll, not a server or raw device"); 58 | return ARTNET_EACTION; 59 | } 60 | } 61 | 62 | /* 63 | * Send an ArtPollReply 64 | * @param n the node 65 | * @param response true if this reply is in response to a network packet 66 | * false if this reply is due to the node changing it's conditions 67 | */ 68 | int artnet_tx_poll_reply(node n, int response) { 69 | artnet_packet_t reply; 70 | int i; 71 | 72 | if (!response && n->state.mode == ARTNET_ON) { 73 | n->state.ar_count++; 74 | } 75 | 76 | reply.to = n->state.reply_addr; 77 | reply.type = ARTNET_REPLY; 78 | reply.length = sizeof(artnet_reply_t); 79 | 80 | // copy from a poll reply template 81 | memcpy(&reply.data, &n->ar_temp, sizeof(artnet_reply_t)); 82 | 83 | for (i=0; i< ARTNET_MAX_PORTS; i++) { 84 | reply.data.ar.goodinput[i] = n->ports.in[i].port_status; 85 | reply.data.ar.goodoutput[i] = n->ports.out[i].port_status; 86 | } 87 | 88 | snprintf((char *) &reply.data.ar.nodereport, 89 | sizeof(reply.data.ar.nodereport), 90 | "%04x [%04i] libartnet", 91 | n->state.report_code, 92 | n->state.ar_count); 93 | 94 | return artnet_net_send(n, &reply); 95 | } 96 | 97 | 98 | /* 99 | * Send a tod request 100 | */ 101 | int artnet_tx_tod_request(node n) { 102 | int i; 103 | artnet_packet_t todreq; 104 | 105 | todreq.to = n->state.bcast_addr; 106 | todreq.type = ARTNET_TODREQUEST; 107 | todreq.length = sizeof(artnet_todrequest_t); 108 | memset(&todreq.data,0x00, todreq.length); 109 | 110 | // set up the data 111 | memcpy(&todreq.data.todreq.id, ARTNET_STRING, ARTNET_STRING_SIZE); 112 | todreq.data.todreq.opCode = htols(ARTNET_TODREQUEST); 113 | todreq.data.todreq.verH = 0; 114 | todreq.data.todreq.ver = ARTNET_VERSION; 115 | todreq.data.todreq.command = ARTNET_TOD_FULL; // todfull 116 | todreq.data.todreq.adCount = 0; 117 | 118 | // include all enabled ports 119 | for (i=0; i < ARTNET_MAX_PORTS; i++) { 120 | if (n->ports.out[i].port_enabled) { 121 | todreq.data.todreq.address[todreq.data.todreq.adCount++] = n->ports.out[i].port_addr; 122 | } 123 | } 124 | 125 | return artnet_net_send(n, &todreq); 126 | } 127 | 128 | 129 | /* 130 | * Send a tod data for port number id 131 | * @param id the number of the port to send data for 132 | */ 133 | int artnet_tx_tod_data(node n, int id) { 134 | artnet_packet_t tod; 135 | int lim, remaining, bloc, offset; 136 | int ret = ARTNET_EOK; 137 | 138 | // ok we need to check how many uid's we have, 139 | // may need to send more than one datagram 140 | 141 | tod.to = n->state.bcast_addr; 142 | tod.type = ARTNET_TODDATA; 143 | tod.length = sizeof(artnet_toddata_t); 144 | 145 | memset(&tod.data,0x00, tod.length); 146 | 147 | // set up the data 148 | memcpy(&tod.data.toddata.id, ARTNET_STRING, ARTNET_STRING_SIZE); 149 | tod.data.toddata.opCode = htols(ARTNET_TODDATA); 150 | tod.data.toddata.verH = 0; 151 | tod.data.toddata.ver = ARTNET_VERSION; 152 | tod.data.toddata.port = id; 153 | 154 | // this is interesting, the spec mentions TOD_ADD and TOD_SUBTRACT, but the 155 | // codes aren't given. The windows drivers don't have these either.... 156 | tod.data.toddata.cmdRes = ARTNET_TOD_FULL; 157 | 158 | tod.data.toddata.address = n->ports.out[id].port_addr; 159 | tod.data.toddata.uidTotalHi = short_get_high_byte(n->ports.out[id].port_tod.length); 160 | tod.data.toddata.uidTotal = short_get_low_byte(n->ports.out[id].port_tod.length); 161 | 162 | remaining = n->ports.out[id].port_tod.length; 163 | bloc = 0; 164 | 165 | while (remaining > 0) { 166 | memset(&tod.data.toddata.tod,0x00, ARTNET_MAX_UID_COUNT); 167 | lim = min(ARTNET_MAX_UID_COUNT, remaining); 168 | tod.data.toddata.blockCount = bloc++; 169 | tod.data.toddata.uidCount = lim; 170 | 171 | offset = (n->ports.out[id].port_tod.length - remaining) * ARTNET_RDM_UID_WIDTH; 172 | if (n->ports.out[id].port_tod.data != NULL) 173 | memcpy(tod.data.toddata.tod, 174 | n->ports.out[id].port_tod.data + offset, 175 | lim * ARTNET_RDM_UID_WIDTH); 176 | 177 | ret = ret || artnet_net_send(n, &tod); 178 | remaining = remaining - lim; 179 | } 180 | return ret; 181 | } 182 | 183 | 184 | /* 185 | * Send a tod data for port number id 186 | * @param id the number of the port to send data for 187 | */ 188 | int artnet_tx_tod_control(node n, 189 | uint8_t address, 190 | artnet_tod_command_code action) { 191 | artnet_packet_t tod; 192 | 193 | tod.to = n->state.bcast_addr; 194 | tod.type = ARTNET_TODCONTROL; 195 | tod.length = sizeof(artnet_todcontrol_t); 196 | 197 | memset(&tod.data,0x00, tod.length); 198 | 199 | // set up the data 200 | memcpy(&tod.data.todcontrol.id, ARTNET_STRING, ARTNET_STRING_SIZE); 201 | tod.data.todcontrol.opCode = htols(ARTNET_TODCONTROL); 202 | tod.data.todcontrol.verH = 0; 203 | tod.data.todcontrol.ver = ARTNET_VERSION; 204 | tod.data.todcontrol.cmd = action; 205 | tod.data.todcontrol.address = address; 206 | 207 | return artnet_net_send(n, &tod); 208 | } 209 | 210 | 211 | /* 212 | * Send a RDM message 213 | * @param address the universe to address this datagram to 214 | * @param action the action to perform. Either ARTNET_TOD_FULL or 215 | * ARTNET_TOD_FLUSH 216 | */ 217 | int artnet_tx_rdm(node n, uint8_t address, uint8_t *data, int length) { 218 | artnet_packet_t rdm; 219 | int len; 220 | 221 | rdm.to = n->state.bcast_addr; 222 | rdm.type = ARTNET_RDM; 223 | rdm.length = sizeof(artnet_rdm_t); 224 | 225 | memset(&rdm.data,0x00, rdm.length); 226 | 227 | // set up the data 228 | memcpy(&rdm.data.todcontrol.id, ARTNET_STRING, ARTNET_STRING_SIZE); 229 | rdm.data.rdm.opCode = htols(ARTNET_RDM); 230 | rdm.data.rdm.verH = 0; 231 | rdm.data.rdm.ver = ARTNET_VERSION; 232 | rdm.data.rdm.cmd = 0x00; 233 | rdm.data.rdm.address = address; 234 | 235 | len = min(length, ARTNET_MAX_RDM_DATA); 236 | memcpy(&rdm.data.rdm.data, data, len); 237 | return artnet_net_send(n, &rdm); 238 | 239 | } 240 | 241 | 242 | /* 243 | * Send a firmware reply 244 | * @param ip the ip address to send to 245 | * @param code the response code 246 | */ 247 | int artnet_tx_firmware_reply(node n, in_addr_t ip, 248 | artnet_firmware_status_code code) { 249 | artnet_packet_t p; 250 | memset(&p, 0x0, sizeof(p)); 251 | 252 | p.to.s_addr = ip; 253 | p.length = sizeof(artnet_firmware_t); 254 | p.type = ARTNET_FIRMWAREREPLY; 255 | 256 | // now build packet 257 | memcpy(&p.data.firmware.id, ARTNET_STRING, ARTNET_STRING_SIZE); 258 | p.data.firmware.opCode = htols(ARTNET_FIRMWAREREPLY); 259 | p.data.firmware.verH = 0; 260 | p.data.firmware.ver = ARTNET_VERSION; 261 | p.data.firmware.type = code; 262 | 263 | return artnet_net_send(n, &p); 264 | } 265 | 266 | 267 | /* 268 | * Send an firmware data datagram 269 | * 270 | * @param firm a pointer to the firmware structure for this transfer 271 | */ 272 | int artnet_tx_firmware_packet(node n, firmware_transfer_t *firm) { 273 | artnet_packet_t p; 274 | uint8_t type = 0; 275 | int data_len, max_len, ret; 276 | 277 | memset(&p, 0x0, sizeof(p)); 278 | 279 | // max value of data_len is 1024; 280 | max_len = ARTNET_FIRMWARE_SIZE * sizeof(p.data.firmware.data[0]); 281 | 282 | // calculate length 283 | data_len = firm->bytes_total - firm->bytes_current; 284 | data_len = min(data_len, max_len); 285 | 286 | // work out type - 6 cases 287 | if(firm->ubea) { 288 | // ubea upload 289 | if (firm->bytes_current == 0) { 290 | // first 291 | type = ARTNET_FIRMWARE_UBEAFIRST; 292 | } else if (data_len == max_len) { 293 | // cont 294 | type = ARTNET_FIRMWARE_UBEACONT; 295 | } else if (data_len < max_len) { 296 | // last 297 | type = ARTNET_FIRMWARE_UBEALAST; 298 | } else { 299 | // this should never happen, something has gone wrong 300 | artnet_error("Attempting to send %d when the max is %d, very very bad...\n", data_len, max_len); 301 | } 302 | } else { 303 | // firmware upload 304 | if (firm->bytes_current == 0) { 305 | // first 306 | type = ARTNET_FIRMWARE_FIRMFIRST; 307 | } else if (data_len == max_len) { 308 | // cont 309 | type = ARTNET_FIRMWARE_FIRMCONT; 310 | } else if (data_len < max_len) { 311 | // last 312 | type = ARTNET_FIRMWARE_FIRMLAST; 313 | } else { 314 | // this should never happen, something has gone wrong 315 | artnet_error("Attempting to send %d when the max is %d, very very bad...\n", data_len, max_len); 316 | } 317 | } 318 | 319 | // set packet properties 320 | p.to.s_addr = firm->peer.s_addr; 321 | p.length = sizeof(artnet_firmware_t); 322 | p.type = ARTNET_FIRMWAREMASTER; 323 | 324 | // now build packet 325 | memcpy(&p.data.firmware.id, ARTNET_STRING, ARTNET_STRING_SIZE); 326 | p.data.firmware.opCode = htols(ARTNET_FIRMWAREMASTER); 327 | p.data.firmware.verH = 0; 328 | p.data.firmware.ver = ARTNET_VERSION; 329 | p.data.firmware.type = type; 330 | p.data.firmware.blockId = firm->expected_block; 331 | 332 | artnet_misc_int_to_bytes(firm->bytes_total / sizeof(uint16_t), 333 | p.data.firmware.length); 334 | 335 | memcpy(&p.data.firmware.data, 336 | firm->data + (firm->bytes_current / sizeof(uint16_t)), 337 | data_len); 338 | 339 | if ((ret = artnet_net_send(n, &p))) { 340 | // send failed 341 | return ret; 342 | } else { 343 | // update stats 344 | firm->bytes_current = firm->bytes_current + data_len; 345 | firm->last_time = time(NULL); 346 | firm->expected_block++; 347 | // limit between 0 and 255 (only 8 bits wide) 348 | // we dont' actually need this cause it will be shorted when assigned above 349 | firm->expected_block %= UINT8_MAX; 350 | } 351 | return ARTNET_EOK; 352 | } 353 | 354 | 355 | // this is called when the node's state changes to rebuild the 356 | // artpollreply packet 357 | int artnet_tx_build_art_poll_reply(node n) { 358 | int i; 359 | 360 | // shorten the amount we have to type 361 | artnet_reply_t *ar = &n->ar_temp; 362 | 363 | memset(ar, 0x00, sizeof(artnet_reply_t)); 364 | 365 | memcpy(&ar->id, ARTNET_STRING, ARTNET_STRING_SIZE); 366 | ar->opCode = htols(ARTNET_REPLY); 367 | memcpy(&ar->ip, &n->state.ip_addr.s_addr, 4); 368 | ar->port = htols(ARTNET_PORT); 369 | ar->verH = 0; 370 | ar->ver = 0; 371 | ar->subH = 0; 372 | ar->sub = n->state.subnet; 373 | ar->oemH = n->state.oem_hi; 374 | ar->oem = n->state.oem_lo; 375 | ar->ubea = 0; 376 | // ar->status 377 | 378 | // if(n->state 379 | 380 | // status need to be recalc everytime 381 | //ar->status 382 | 383 | // ESTA Manufacturer ID 384 | // Assigned 18/4/2006 385 | ar->etsaman[0] = n->state.esta_hi; 386 | ar->etsaman[1] = n->state.esta_lo; 387 | 388 | memcpy(&ar->shortname, &n->state.short_name, sizeof(n->state.short_name)); 389 | memcpy(&ar->longname, &n->state.long_name, sizeof(n->state.long_name)); 390 | 391 | // the report is generated on every send 392 | 393 | // port stuff here 394 | ar->numbportsH = 0; 395 | 396 | for (i = ARTNET_MAX_PORTS; i > 0; i--) { 397 | if (n->ports.out[i-1].port_enabled || n->ports.in[i-1].port_enabled) 398 | break; 399 | } 400 | 401 | ar->numbports = i; 402 | 403 | for (i=0; i< ARTNET_MAX_PORTS; i++) { 404 | ar->porttypes[i] = n->ports.types[i]; 405 | ar->goodinput[i] = n->ports.in[i].port_status; 406 | ar->goodoutput[i] = n->ports.out[i].port_status; 407 | ar->swin[i] = n->ports.in[i].port_addr; 408 | ar->swout[i] = n->ports.out[i].port_addr; 409 | } 410 | 411 | ar->swvideo = 0; 412 | ar->swmacro = 0; 413 | ar->swremote = 0; 414 | 415 | // spares 416 | ar->sp1 = 0; 417 | ar->sp2 = 0; 418 | ar->sp3 = 0; 419 | 420 | // hw address 421 | memcpy(&ar->mac, &n->state.hw_addr, ARTNET_MAC_SIZE); 422 | 423 | // set style 424 | switch (n->state.node_type) { 425 | case ARTNET_SRV: 426 | ar->style = STSERVER; 427 | break; 428 | case ARTNET_NODE: 429 | ar->style = STNODE; 430 | break; 431 | case ARTNET_MSRV: 432 | ar->style = STMEDIA; 433 | break; 434 | // we should fix this, it'll do for now 435 | case ARTNET_RAW: 436 | ar->style = STNODE; 437 | break; 438 | default: 439 | artnet_error("Node type not recognised!"); 440 | ar->style = STNODE; 441 | return ARTNET_ESTATE; 442 | } 443 | 444 | return ARTNET_EOK; 445 | } 446 | -------------------------------------------------------------------------------- /config.h.in: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.in by autoheader. */ 2 | 3 | /* Define to 1 if you have the header file. */ 4 | #undef HAVE_ARPA_INET_H 5 | 6 | /* Define to 1 if you have the header file. */ 7 | #undef HAVE_DLFCN_H 8 | 9 | /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ 10 | #undef HAVE_DOPRNT 11 | 12 | /* Define to 1 if you have the header file. */ 13 | #undef HAVE_ENDIAN_H 14 | 15 | /* Define to 1 if you have the `getifaddrs' function. */ 16 | #undef HAVE_GETIFADDRS 17 | 18 | /* Define to 1 if you have the `inet_aton' function. */ 19 | #undef HAVE_INET_ATON 20 | 21 | /* Define to 1 if you have the `inet_ntoa' function. */ 22 | #undef HAVE_INET_NTOA 23 | 24 | /* Define to 1 if you have the header file. */ 25 | #undef HAVE_INTTYPES_H 26 | 27 | /* Define to 1 if you have the header file. */ 28 | #undef HAVE_LINUX_IF_PACKET_H 29 | 30 | /* Define to 1 if your system has a GNU libc compatible `malloc' function, and 31 | to 0 otherwise. */ 32 | #undef HAVE_MALLOC 33 | 34 | /* Define to 1 if you have the header file. */ 35 | #undef HAVE_MEMORY_H 36 | 37 | /* Define to 1 if you have the `memset' function. */ 38 | #undef HAVE_MEMSET 39 | 40 | /* Define to 1 if you have the header file. */ 41 | #undef HAVE_NETINET_IN_H 42 | 43 | /* Define to 1 if you have the header file. */ 44 | #undef HAVE_PPC_ENDIAN_H 45 | 46 | /* Define to 1 if your system has a GNU libc compatible `realloc' function, 47 | and to 0 otherwise. */ 48 | #undef HAVE_REALLOC 49 | 50 | /* Define to 1 if you have the `select' function. */ 51 | #undef HAVE_SELECT 52 | 53 | /* define if socket address structures have length fields */ 54 | #undef HAVE_SOCKADDR_SA_LEN 55 | 56 | /* Define to 1 if you have the `socket' function. */ 57 | #undef HAVE_SOCKET 58 | 59 | /* Define to 1 if stdbool.h conforms to C99. */ 60 | #undef HAVE_STDBOOL_H 61 | 62 | /* Define to 1 if you have the header file. */ 63 | #undef HAVE_STDDEF_H 64 | 65 | /* Define to 1 if you have the header file. */ 66 | #undef HAVE_STDINT_H 67 | 68 | /* Define to 1 if you have the header file. */ 69 | #undef HAVE_STDLIB_H 70 | 71 | /* Define to 1 if you have the `strchr' function. */ 72 | #undef HAVE_STRCHR 73 | 74 | /* Define to 1 if you have the `strdup' function. */ 75 | #undef HAVE_STRDUP 76 | 77 | /* Define to 1 if you have the `strerror' function. */ 78 | #undef HAVE_STRERROR 79 | 80 | /* Define to 1 if you have the header file. */ 81 | #undef HAVE_STRINGS_H 82 | 83 | /* Define to 1 if you have the header file. */ 84 | #undef HAVE_STRING_H 85 | 86 | /* Define to 1 if you have the header file. */ 87 | #undef HAVE_SYS_IOCTL_H 88 | 89 | /* Define to 1 if you have the header file. */ 90 | #undef HAVE_SYS_SELECT_H 91 | 92 | /* Define to 1 if you have the header file. */ 93 | #undef HAVE_SYS_SOCKET_H 94 | 95 | /* Define to 1 if you have the header file. */ 96 | #undef HAVE_SYS_STAT_H 97 | 98 | /* Define to 1 if you have the header file. */ 99 | #undef HAVE_SYS_TYPES_H 100 | 101 | /* Define to 1 if you have the header file. */ 102 | #undef HAVE_UNISTD_H 103 | 104 | /* Define to 1 if you have the header file. */ 105 | #undef HAVE_UNISTD_HI 106 | 107 | /* Define to 1 if you have the `vprintf' function. */ 108 | #undef HAVE_VPRINTF 109 | 110 | /* Define to 1 if the system has the type `_Bool'. */ 111 | #undef HAVE__BOOL 112 | 113 | /* Define to 1 if the system supports IPv6 */ 114 | #undef IPV6 115 | 116 | /* Name of package */ 117 | #undef PACKAGE 118 | 119 | /* Define to the address where bug reports for this package should be sent. */ 120 | #undef PACKAGE_BUGREPORT 121 | 122 | /* Define to the full name of this package. */ 123 | #undef PACKAGE_NAME 124 | 125 | /* Define to the full name and version of this package. */ 126 | #undef PACKAGE_STRING 127 | 128 | /* Define to the one symbol short name of this package. */ 129 | #undef PACKAGE_TARNAME 130 | 131 | /* Define to the version of this package. */ 132 | #undef PACKAGE_VERSION 133 | 134 | /* Define to the type of arg 1 for `select'. */ 135 | #undef SELECT_TYPE_ARG1 136 | 137 | /* Define to the type of args 2, 3 and 4 for `select'. */ 138 | #undef SELECT_TYPE_ARG234 139 | 140 | /* Define to the type of arg 5 for `select'. */ 141 | #undef SELECT_TYPE_ARG5 142 | 143 | /* Define to 1 if you have the ANSI C header files. */ 144 | #undef STDC_HEADERS 145 | 146 | /* Define to 1 if you can safely include both and . */ 147 | #undef TIME_WITH_SYS_TIME 148 | 149 | /* Version number of package */ 150 | #undef VERSION 151 | 152 | /* Define to empty if `const' does not conform to ANSI C. */ 153 | #undef const 154 | 155 | /* Define to rpl_malloc if the replacement function should be used. */ 156 | #undef malloc 157 | 158 | /* Define to rpl_realloc if the replacement function should be used. */ 159 | #undef realloc 160 | 161 | /* Define to `unsigned int' if does not define. */ 162 | #undef size_t 163 | -------------------------------------------------------------------------------- /configure.in: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ(2.57) 5 | AC_INIT(configure.in) 6 | AM_CONFIG_HEADER(config.h) 7 | AM_INIT_AUTOMAKE(libartnet, 1.1.0) 8 | 9 | # Checks for programs. 10 | AC_PROG_CC 11 | AC_PROG_INSTALL 12 | AC_PROG_LN_S 13 | AC_PROG_MAKE_SET 14 | AC_LIBTOOL_WIN32_DLL 15 | AC_PROG_LIBTOOL 16 | 17 | # Checks for header files. 18 | AC_HEADER_STDC 19 | AC_CHECK_HEADERS([endian.h ppc/endian.h arpa/inet.h netinet/in.h stddef.h \ 20 | stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h \ 21 | unistd.hi linux/if_packet.h]) 22 | 23 | # Checks for typedefs, structures, and compiler characteristics. 24 | AC_C_CONST 25 | AC_TYPE_SIZE_T 26 | AC_HEADER_TIME 27 | AC_HEADER_STDBOOL 28 | 29 | # Checks for library functions. 30 | AC_PROG_GCC_TRADITIONAL 31 | AC_FUNC_MALLOC 32 | AC_FUNC_MEMCMP 33 | AC_FUNC_REALLOC 34 | AC_FUNC_SELECT_ARGTYPES 35 | AC_FUNC_VPRINTF 36 | AC_CHECK_FUNCS([inet_ntoa inet_aton memset select socket strchr strdup \ 37 | strerror getifaddrs]) 38 | 39 | # check for ipv6 support - taken from unp 40 | AC_MSG_CHECKING(for IPv6 support) 41 | AC_CACHE_VAL(ac_cv_ipv6, 42 | AC_TRY_RUN([ 43 | # include 44 | # include 45 | # include 46 | /* Make sure the definitions for AF_INET6 and struct sockaddr_in6 47 | * are defined, and that we can actually create an IPv6 TCP socket. 48 | */ 49 | main() 50 | { 51 | int fd; 52 | struct sockaddr_in6 foo; 53 | fd = socket(AF_INET6, SOCK_STREAM, 0); 54 | exit(fd >= 0 ? 0 : 1); 55 | }], 56 | ac_cv_ipv6=yes, 57 | ac_cv_ipv6=no, 58 | ac_cv_ipv6=no)) 59 | AC_MSG_RESULT($ac_cv_ipv6) 60 | if test $ac_cv_ipv6 = yes ; then 61 | AC_DEFINE(IPV6, 1, Define to 1 if the system supports IPv6) 62 | fi 63 | 64 | 65 | # Check if sockaddr{} has sa_len member. 66 | AC_CHECK_MEMBER([struct sockaddr.sa_len], 67 | AC_DEFINE(HAVE_SOCKADDR_SA_LEN, 1, 68 | define if socket address structures have length fields),, 69 | [ 70 | #include 71 | #include ]) 72 | 73 | # check for win32 74 | AM_CONDITIONAL(USING_WIN32, test "$host_os" = 'mingw32') 75 | 76 | AC_OUTPUT(Makefile \ 77 | artnet/Makefile \ 78 | debian/Makefile \ 79 | libartnet.pc) 80 | -------------------------------------------------------------------------------- /debian/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = changelog compat control copyright docs libartnet1.install \ 2 | libartnet1.postinst libartnet1.postrm libartnet-dev.install \ 3 | rules 4 | 5 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | libartnet (1.1.0-1) unstable; urgency=low 2 | 3 | * Release 1.1.0 4 | 5 | -- Simon Newton Sat, 15 May 2010 17:49:50 +0000 6 | 7 | libartnet (1.0.5.200705051336-1) unstable; urgency=low 8 | 9 | * New upstream release 10 | 11 | -- Simon Sat, 5 May 2007 13:36:23 +0800 12 | 13 | libartnet (1.0.5.200705051324-1) unstable; urgency=low 14 | 15 | * New upstream release 16 | 17 | -- Simon Sat, 5 May 2007 13:24:30 +0800 18 | 19 | libartnet (1.0.5.200704020300-1) unstable; urgency=low 20 | 21 | * New upstream release 22 | 23 | -- Simon Mon, 2 Apr 2007 03:00:49 +0800 24 | 25 | libartnet (1.0.5.200612261456-1) unstable; urgency=low 26 | 27 | * New upstream release 28 | 29 | -- Simon Tue, 26 Dec 2006 14:56:38 +0800 30 | 31 | libartnet (1.0.4.200610290609-1) unstable; urgency=low 32 | 33 | * New upstream release 34 | 35 | -- Simon Sun, 29 Oct 2006 06:09:27 +0800 36 | 37 | libartnet (1.0.4.200609191108-1) unstable; urgency=low 38 | 39 | * New upstream release 40 | 41 | -- Simon Tue, 19 Sep 2006 11:08:19 +0800 42 | 43 | libartnet (1.0.4.200609191106-1) unstable; urgency=low 44 | 45 | * New upstream release 46 | 47 | -- Simon Tue, 19 Sep 2006 11:06:01 +0800 48 | 49 | libartnet (1.0.4.200609181810-1) unstable; urgency=low 50 | 51 | * New upstream release 52 | 53 | -- Simon Mon, 18 Sep 2006 18:10:29 +0800 54 | 55 | libartnet (1.0.4.200609172229-1) unstable; urgency=low 56 | 57 | * New upstream release 58 | 59 | -- simon Sun, 17 Sep 2006 22:29:39 +0800 60 | 61 | libartnet (1.0.4.200609171250-1) unstable; urgency=low 62 | 63 | * New upstream release 64 | 65 | -- simon Sun, 17 Sep 2006 12:50:49 +0800 66 | 67 | libartnet (1.0.4.200609171142-1) unstable; urgency=low 68 | 69 | * New upstream release 70 | 71 | -- simon Sun, 17 Sep 2006 11:42:03 +0800 72 | 73 | libartnet (1.0.4.200608132342-1) unstable; urgency=low 74 | 75 | * New upstream release 76 | 77 | -- Simon Wed, 13 Sep 2006 23:42:42 +0800 78 | 79 | libartnet (1.0.4.200608131224-1) unstable; urgency=low 80 | 81 | * New upstream release 82 | 83 | -- simon Wed, 13 Sep 2006 12:25:00 +0800 84 | 85 | libartnet (1.0.4.200607281949-1) unstable; urgency=low 86 | 87 | * New upstream release 88 | 89 | -- simon Mon, 28 Aug 2006 19:49:22 +0800 90 | 91 | libartnet (1.0.3.200605221305-1) unstable; urgency=low 92 | 93 | * New upstream release 94 | 95 | -- simon Thu, 22 Jun 2006 13:05:52 +0800 96 | 97 | libartnet (1.0.3.200605121049-1) unstable; urgency=low 98 | 99 | * New upstream release 100 | 101 | -- simon Mon, 12 Jun 2006 10:49:23 +0800 102 | 103 | libartnet (1.0.2.200604271004-1) unstable; urgency=low 104 | 105 | * New upstream release 106 | 107 | -- simon Sat, 27 May 2006 10:04:40 +0800 108 | 109 | libartnet (1.0.2.200604091405-1) unstable; urgency=low 110 | 111 | * New upstream release 112 | 113 | -- simon Tue, 9 May 2006 14:05:49 +0800 114 | 115 | libartnet (1.0.2.200604091306-1) unstable; urgency=low 116 | 117 | * New upstream release 118 | 119 | -- simon Tue, 9 May 2006 13:06:06 +0800 120 | 121 | libartnet (1.0.2.200604042209-1) unstable; urgency=low 122 | 123 | * New upstream release 124 | 125 | -- simon Thu, 4 May 2006 22:09:10 +0800 126 | 127 | libartnet (1.0.1-2) unstable; urgency=low 128 | 129 | * Now build on a stable machine to reduce dependancies 130 | 131 | -- simon Mon, 17 Apr 2006 19:34:02 +0800 132 | 133 | libartnet (1.0.1-1) unstable; urgency=low 134 | 135 | * New upstream release 136 | 137 | -- Simon Newton Mon, 17 Apr 2006 12:18:44 +0800 138 | 139 | libartnet (1.0.0-3) unstable; urgency=low 140 | 141 | * More control file fixes - now lintian clean 142 | 143 | -- Simon Newton Sat, 1 Apr 2006 20:23:19 +0800 144 | 145 | libartnet (1.0.0-2) unstable; urgency=low 146 | 147 | * Cleaned up debian control files 148 | 149 | -- Simon Newton Sat, 1 Apr 2006 20:11:09 +0800 150 | 151 | libartnet (1.0.0-1) unstable; urgency=low 152 | 153 | * Initial Release. 154 | 155 | -- simon Thu, 30 Mar 2006 15:19:16 +0800 156 | 157 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 7 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: libartnet 2 | Priority: optional 3 | Maintainer: Simon Newton 4 | Build-Depends: debhelper (>= 7), autotools-dev 5 | Standards-Version: 3.8.0 6 | Section: libs 7 | Homepage: http://code.google.com/p/linux-lighting/ 8 | 9 | Package: libartnet-dev 10 | Section: libdevel 11 | Architecture: any 12 | Depends: libartnet1 (= ${binary:Version}) 13 | Description: ArtNet DMX over IP library 14 | libartnet is an implementation of the Art-Net DMX over IP protocol 15 | 16 | Package: libartnet1 17 | Section: libs 18 | Architecture: any 19 | Depends: ${shlibs:Depends}, ${misc:Depends} 20 | Description: ArtNet DMX over IP library 21 | libartnet is an implementation of the Art-Net DMX over IP protocol 22 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | This package was debianized by Simon Newton on 2 | Thu, 30 Mar 2006 15:19:16 +0800. 3 | 4 | It was downloaded from http://code.google.com/p/linux-lighting/ 5 | 6 | Upstream Author: 7 | 8 | Simon Newton 9 | 10 | Copyright: 11 | 12 | Copyright (C) 2004 Simon Newton 13 | 14 | License: 15 | 16 | You are free to distribute this software under the terms of 17 | the GNU General Public License either version of the License, 18 | or (at your option) any later version. 19 | 20 | This package is distributed in the hope that it will be useful, 21 | but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | GNU General Public License for more details. 24 | 25 | You should have received a copy of the GNU General Public License 26 | along with this package; if not, write to the Free Software 27 | Foundation, Inc., Franklin St, Fifth Floor, Boston, MA - USA 28 | 29 | The Debian packaging is (C) 2010, Simon Newton and 30 | is licensed under the GPL, see `/usr/share/common-licenses/GPL'. 31 | -------------------------------------------------------------------------------- /debian/docs: -------------------------------------------------------------------------------- 1 | NEWS 2 | README 3 | -------------------------------------------------------------------------------- /debian/libartnet-dev.install: -------------------------------------------------------------------------------- 1 | usr/include/* 2 | usr/lib/lib*.a 3 | usr/lib/lib*.so 4 | usr/lib/pkgconfig/* 5 | usr/lib/*.la 6 | -------------------------------------------------------------------------------- /debian/libartnet1.install: -------------------------------------------------------------------------------- 1 | usr/lib/lib*.so.* 2 | -------------------------------------------------------------------------------- /debian/libartnet1.postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # postinst script for libartnet 3 | # 4 | # see: dh_installdeb(1) 5 | 6 | set -e 7 | 8 | # summary of how this script can be called: 9 | # * `configure' 10 | # * `abort-upgrade' 11 | # * `abort-remove' `in-favour' 12 | # 13 | # * `abort-remove' 14 | # * `abort-deconfigure' `in-favour' 15 | # `removing' 16 | # 17 | # for details, see http://www.debian.org/doc/debian-policy/ or 18 | # the debian-policy package 19 | 20 | 21 | case "$1" in 22 | configure) 23 | ldconfig 24 | ;; 25 | 26 | abort-upgrade|abort-remove|abort-deconfigure) 27 | ;; 28 | 29 | *) 30 | echo "postinst called with unknown argument \`$1'" >&2 31 | exit 1 32 | ;; 33 | esac 34 | 35 | # dh_installdeb will replace this with shell code automatically 36 | # generated by other debhelper scripts. 37 | 38 | #DEBHELPER# 39 | 40 | exit 0 41 | 42 | 43 | -------------------------------------------------------------------------------- /debian/libartnet1.postrm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # postrm script for libartnet 3 | # 4 | # see: dh_installdeb(1) 5 | 6 | set -e 7 | 8 | # summary of how this script can be called: 9 | # * `remove' 10 | # * `purge' 11 | # * `upgrade' 12 | # * `failed-upgrade' 13 | # * `abort-install' 14 | # * `abort-install' 15 | # * `abort-upgrade' 16 | # * `disappear' 17 | # 18 | # for details, see http://www.debian.org/doc/debian-policy/ or 19 | # the debian-policy package 20 | 21 | 22 | case "$1" in 23 | remove) 24 | ldconfig 25 | ;; 26 | 27 | purge|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) 28 | ;; 29 | 30 | *) 31 | echo "postrm called with unknown argument \`$1'" >&2 32 | exit 1 33 | ;; 34 | esac 35 | 36 | # dh_installdeb will replace this with shell code automatically 37 | # generated by other debhelper scripts. 38 | 39 | #DEBHELPER# 40 | 41 | exit 0 42 | 43 | 44 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | # Sample debian/rules that uses debhelper. 4 | # This file was originally written by Joey Hess and Craig Small. 5 | # As a special exception, when this file is copied by dh-make into a 6 | # dh-make output file, you may use that output file without restriction. 7 | # This special exception was added by Craig Small in version 0.37 of dh-make. 8 | 9 | # Uncomment this to turn on verbose mode. 10 | #export DH_VERBOSE=1 11 | 12 | 13 | # These are used for cross-compiling and for saving the configure script 14 | # from having to guess our platform (since we know it already) 15 | DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) 16 | DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) 17 | ifneq ($(DEB_HOST_GNU_TYPE),$(DEB_BUILD_GNU_TYPE)) 18 | CROSS= --build $(DEB_BUILD_GNU_TYPE) --host $(DEB_HOST_GNU_TYPE) 19 | else 20 | CROSS= --build $(DEB_BUILD_GNU_TYPE) 21 | endif 22 | 23 | 24 | 25 | 26 | # shared library versions, option 1 27 | version=2.0.5 28 | major=2 29 | # option 2, assuming the library is created as src/.libs/libfoo.so.2.0.5 or so 30 | #version=`ls src/.libs/lib*.so.* | \ 31 | # awk '{if (match($$0,/[0-9]+\.[0-9]+\.[0-9]+$$/)) print substr($$0,RSTART)}'` 32 | #major=`ls src/.libs/lib*.so.* | \ 33 | # awk '{if (match($$0,/\.so\.[0-9]+$$/)) print substr($$0,RSTART+4)}'` 34 | 35 | config.status: configure 36 | dh_testdir 37 | # Add here commands to configure the package. 38 | ifneq "$(wildcard /usr/share/misc/config.sub)" "" 39 | cp -f /usr/share/misc/config.sub config.sub 40 | endif 41 | ifneq "$(wildcard /usr/share/misc/config.guess)" "" 42 | cp -f /usr/share/misc/config.guess config.guess 43 | endif 44 | ./configure $(CROSS) --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info CFLAGS="$(CFLAGS)" LDFLAGS="-Wl,-z,defs" 45 | 46 | 47 | build: build-stamp 48 | build-stamp: config.status 49 | dh_testdir 50 | 51 | # Add here commands to compile the package. 52 | $(MAKE) 53 | 54 | touch $@ 55 | 56 | clean: 57 | dh_testdir 58 | dh_testroot 59 | rm -f build-stamp 60 | 61 | # Add here commands to clean up after the build process. 62 | [ ! -f Makefile ] || $(MAKE) distclean 63 | rm -f config.sub config.guess 64 | 65 | dh_clean 66 | 67 | install: build 68 | dh_testdir 69 | dh_testroot 70 | dh_clean -k 71 | dh_installdirs 72 | 73 | # Add here commands to install the package into debian/tmp 74 | $(MAKE) DESTDIR=$(CURDIR)/debian/tmp install 75 | 76 | 77 | # Build architecture-independent files here. 78 | binary-indep: build install 79 | # We have nothing to do by default. 80 | 81 | # Build architecture-dependent files here. 82 | binary-arch: build install 83 | dh_testdir 84 | dh_testroot 85 | dh_install 86 | # dh_installmenu 87 | # dh_installdebconf 88 | # dh_installlogrotate 89 | # dh_installemacsen 90 | # dh_installpam 91 | # dh_installmime 92 | # dh_installinit 93 | # dh_installcron 94 | dh_link 95 | dh_strip 96 | dh_compress 97 | dh_fixperms 98 | # dh_perl 99 | # dh_python 100 | dh_makeshlibs -V 101 | dh_installdeb 102 | dh_shlibdeps 103 | dh_gencontrol 104 | dh_md5sums 105 | dh_builddeb 106 | 107 | binary: binary-indep binary-arch 108 | .PHONY: build clean binary-indep binary-arch binary install 109 | -------------------------------------------------------------------------------- /libartnet.config: -------------------------------------------------------------------------------- 1 | // ADD PREDEFINED MACROS HERE! 2 | -------------------------------------------------------------------------------- /libartnet.creator: -------------------------------------------------------------------------------- 1 | [General] 2 | -------------------------------------------------------------------------------- /libartnet.files: -------------------------------------------------------------------------------- 1 | artnet/artnet.c 2 | artnet/artnet.h 3 | artnet/artnet.o 4 | artnet/common.h 5 | artnet/misc.c 6 | artnet/misc.h 7 | artnet/misc.o 8 | artnet/network.c 9 | artnet/network.o 10 | artnet/packets.h 11 | artnet/private.h 12 | artnet/receive.c 13 | artnet/receive.o 14 | artnet/tod.c 15 | artnet/tod.h 16 | artnet/tod.o 17 | artnet/transmit.c 18 | artnet/transmit.o 19 | config.h 20 | debian/libartnet-dev/usr/include/artnet/artnet.h 21 | debian/libartnet-dev/usr/include/artnet/common.h 22 | debian/libartnet-dev/usr/include/artnet/packets.h 23 | debian/libartnet-dev/usr/lib/libartnet.a 24 | debian/tmp/usr/include/artnet/artnet.h 25 | debian/tmp/usr/include/artnet/common.h 26 | debian/tmp/usr/include/artnet/packets.h 27 | debian/tmp/usr/lib/libartnet.a 28 | ltmain.sh -------------------------------------------------------------------------------- /libartnet.includes: -------------------------------------------------------------------------------- 1 | artnet 2 | debian/libartnet-dev/usr/include/artnet 3 | debian/tmp/usr/include/artnet -------------------------------------------------------------------------------- /libartnet.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | 7 | Name: libartnet 8 | Version: @VERSION@ 9 | Description: libartnet 10 | Requires: 11 | Libs: -L${libdir} -lartnet 12 | Cflags: -I${includedir}/libartnet 13 | --------------------------------------------------------------------------------