├── LICENSE
├── README.md
├── antenna_array_controller.h
├── antenna_array_controller.ino
├── antenna_array_controller_features.h
├── antenna_array_controller_pins.h
└── antenna_array_controller_settings.h
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # k3ng_antenna_array_controller
2 | K3NG Arduino Directional Antenna Array Controller
3 |
4 | Project information is located at https://blog.radioartisan.com/arduino-directional-antenna-array-controller/
5 |
--------------------------------------------------------------------------------
/antenna_array_controller.h:
--------------------------------------------------------------------------------
1 | /*---------------------- macros - don't touch these unless you know what you are doing ---------------------*/
2 |
3 | #define AZ 1
4 | #define REQUEST_STOP 0
5 | #define REQUEST_AZIMUTH 1
6 | #define REQUEST_CW 2
7 | #define REQUEST_CCW 3
8 |
9 | #define LCD_UNDEF 0
10 | #define LCD_HEADING 1
11 | #define LCD_DIRECTION 2
12 | #define LCD_ROTATING_CW 6
13 | #define LCD_ROTATING_CCW 7
14 | #define LCD_SPLASH 8
15 |
16 | #define DIR_CCW 0x10 // CW Encoder Code (Do not change)
17 | #define DIR_CW 0x20 // CCW Encoder Code (Do not change)
18 |
19 | #define REMOTE_UNIT_DHL_COMMAND 1
20 | #define REMOTE_UNIT_DOI_COMMAND 2
21 |
--------------------------------------------------------------------------------
/antenna_array_controller.ino:
--------------------------------------------------------------------------------
1 | /* Arduino Antenna Array Controller
2 | Anthony Good
3 | K3NG
4 | anthony.good@gmail.com
5 |
6 |
7 | ***************************************************************************************************************
8 |
9 | This program is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
10 |
11 | http://creativecommons.org/licenses/by-nc-sa/3.0/
12 |
13 | http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode
14 |
15 |
16 | ***************************************************************************************************************
17 |
18 |
19 | Revision History
20 |
21 | 1.0.2016100301
22 | Added PIN_ACTIVE_STATE and PIN_INACTIVE_STATE settings in antenna_array_controller_settings.h
23 |
24 | 1.0.2016100601
25 | Added optional outputs for Comtek Four Square ACB-4 series in antenna_array_controller_pins.h: comtek_45_135_225_315_bit_0 comtek_45_135_225_315_bit_1
26 |
27 | 1.0.2016101301
28 | Fixed bugs with optional outputs for Comtek Four Square ACB-4 series
29 |
30 | */
31 |
32 |
33 | #define CODE_VERSION "1.0.2016101301"
34 |
35 | #include
36 | #include
37 | #include
38 | #include
39 |
40 | #include // required for classic 4 bit interface LCD display
41 | //#include // required for Adafruit I2C LCD display
42 | //#include // required for Adafruit I2C LCD display
43 | //#include // required for YourDuino.com or DFRobot I2C LCD display
44 | //#include // required for YourDuino.com I2C LCD display
45 |
46 |
47 | #include "antenna_array_controller.h"
48 | #include "antenna_array_controller_features.h"
49 | #include "antenna_array_controller_pins.h"
50 | #include "antenna_array_controller_settings.h"
51 |
52 | #if !defined(FEATURE_YAESU_EMULATION) && !defined(FEATURE_EASYCOM_EMULATION)
53 | #error "You need to activate FEATURE_YAESU_EMULATION or FEATURE_EASYCOM_EMULATION"
54 | #endif
55 |
56 |
57 | //#ifdef FEATURE_REMOTE_UNIT_INTERFACE
58 | HardwareSerial * remote_unit_port;
59 | //#endif //FEATURE_REMOTE_UNIT_INTERFACE
60 |
61 | /* antenna and pin definitions */
62 |
63 | const float ranges[] = {0, 180, 360}; // azimuths: 90, 270
64 | const int pins[] = {0,0,0};
65 | const byte number_of_positions = 2;
66 |
67 | // const float ranges[] = {90, 270, 450}; // azimuths: 180, 0
68 | // const int pins[] = {0,0};
69 | // const byte number_of_positions = 2;
70 |
71 | // const float ranges[] = {0, 90, 180, 270, 360}; // azimuths: 45, 135, 225, 315
72 | // const int pins[] = {0,0,0,0};
73 | // const byte number_of_positions = 4;
74 |
75 | // const float ranges[] = {0, 45, 90, 135, 180, 215, 270, 315, 360}; // azimuths: 22.5, 67.5, 112.5, 157.5, 202.5, 247.5, 292.5, 337.5
76 | // const int pins[] = {0,0,0,0,0,0,0,0};
77 | // const byte number_of_positions = 8;
78 |
79 | // const float ranges[] = {22.5, 67.5, 112.5, 157.5, 202.5, 247.5, 292.5, 337.5, 382.5}; // azimuths: 45, 90, 135, 180, 225, 270, 315, 0
80 | // const int pins[] = {0,0,0,0,0,0,0,0};
81 | // const byte number_of_positions = 8;
82 |
83 | /*----------------------- variables -------------------------------------*/
84 | int current_antenna_position = 1;
85 | byte configuration_dirty = 0;
86 | unsigned long last_serial_receive_time = 0;
87 | int azimuth = 0;
88 | byte incoming_serial_byte = 0;
89 | byte serial0_buffer[COMMAND_BUFFER_SIZE];
90 | int serial0_buffer_index = 0;
91 | byte debug_mode = DEFAULT_DEBUG_STATE;
92 | unsigned long last_debug_output_time = 0;
93 | byte backslash_command = 0;
94 |
95 | struct config_t {
96 | byte magic_number;
97 | float last_azimuth;
98 | } configuration;
99 |
100 |
101 |
102 |
103 | #ifdef FEATURE_LCD_DISPLAY
104 | unsigned long last_lcd_update = 0;
105 | String last_direction_string;
106 | byte push_lcd_update = 0;
107 | #define LCD_COLUMNS 16
108 | //#define LCD_COLUMNS 20
109 |
110 | byte lcd_state_row_0 = LCD_UNDEF;
111 | byte lcd_state_row_1 = LCD_UNDEF;
112 |
113 | #ifdef FEATURE_I2C_LCD
114 | #define RED 0x1
115 | #define YELLOW 0x3
116 | #define GREEN 0x2
117 | #define TEAL 0x6
118 | #define BLUE 0x4
119 | #define VIOLET 0x5
120 | #define WHITE 0x7
121 | byte lcdcolor = GREEN; // default color of I2C LCD display
122 | #endif //FEATURE_I2C_LCD
123 | #endif //FEATURE_LCD_DISPLAY
124 |
125 | #ifdef FEATURE_ROTARY_ENCODER_CONTROL
126 | #ifdef OPTION_ENCODER_HALF_STEP_MODE // Use the half-step state table (emits a code at 00 and 11)
127 | const unsigned char ttable[6][4] = {
128 | {0x3 , 0x2, 0x1, 0x0}, {0x23, 0x0, 0x1, 0x0},
129 | {0x13, 0x2, 0x0, 0x0}, {0x3 , 0x5, 0x4, 0x0},
130 | {0x3 , 0x3, 0x4, 0x10}, {0x3 , 0x5, 0x3, 0x20}
131 | };
132 | #else // Use the full-step state table (emits a code at 00 only)
133 | const unsigned char ttable[7][4] = {
134 | {0x0, 0x2, 0x4, 0x0}, {0x3, 0x0, 0x1, 0x10},
135 | {0x3, 0x2, 0x0, 0x0}, {0x3, 0x2, 0x1, 0x0},
136 | {0x6, 0x0, 0x4, 0x0}, {0x6, 0x5, 0x0, 0x10},
137 | {0x6, 0x5, 0x4, 0x0},
138 | };
139 | #endif //OPTION_ENCODER_HALF_STEP_MODE
140 | #endif //FEATURE_ROTARY_ENCODER_CONTROL
141 |
142 |
143 | /* ------------------ let's start doing some stuff now that we got the formalities out of the way --------------------*/
144 |
145 | void setup() {
146 |
147 | delay(1000);
148 |
149 | initialize_serial();
150 |
151 | read_settings_from_eeprom();
152 |
153 | initialize_pins();
154 |
155 | #ifdef FEATURE_LCD_DISPLAY
156 | initialize_display();
157 | #endif
158 |
159 | #ifdef FEATURE_YAESU_EMULATION
160 | report_current_azimuth(); // Yaesu - report the azimuth right off the bat without a C command; the Arduino doesn't wake up quick enough
161 | // to get first C command from HRD and if HRD doesn't see anything it doesn't connect
162 | #endif //FEATURE_YAESU_EMULATION
163 |
164 |
165 | }
166 |
167 | /*-------------------------- here's where the magic happens --------------------------------*/
168 |
169 | void loop() {
170 |
171 | check_serial();
172 |
173 | #ifdef FEATURE_LCD_DISPLAY
174 | update_display();
175 | #endif
176 |
177 | #ifdef FEATURE_ROTARY_ENCODER_CONTROL
178 | check_rotary_encoder();
179 | #endif
180 |
181 | check_buttons();
182 |
183 | output_debug();
184 |
185 | check_for_dirty_configuration();
186 |
187 | service_blink_led();
188 |
189 | }
190 | /* -------------------------------------- subroutines -----------------------------------------------
191 |
192 | Where the real work happens...
193 |
194 | */
195 |
196 |
197 | #ifdef FEATURE_ROTARY_ENCODER_CONTROL
198 | void check_rotary_encoder(){
199 |
200 | static unsigned char az_encoder_state = 0;
201 |
202 | az_encoder_state = ttable[az_encoder_state & 0xf][((digitalRead(rotary_encoder_pin2) << 1) | digitalRead(rotary_encoder_pin1))];
203 | unsigned char az_encoder_result = az_encoder_state & 0x30;
204 |
205 | #ifdef DEBUG_ENCODER
206 | static byte last_az_rotary_preset_pin1 = 0;
207 | static byte last_az_rotary_preset_pin2 = 0;
208 | if ((debug_mode) && (( last_az_rotary_preset_pin1 != digitalRead(rotary_encoder_pin1)) || ( last_az_rotary_preset_pin2 != digitalRead(rotary_encoder_pin2)))) {
209 | Serial.print(F("check_preset_encoders: "));
210 | Serial.print(last_az_rotary_preset_pin1);
211 | Serial.print(last_az_rotary_preset_pin2);
212 | Serial.print(digitalRead(rotary_encoder_pin1));
213 | Serial.print(digitalRead(rotary_encoder_pin2));
214 | Serial.print(F(" az_encoder_state: "));
215 | Serial.print(az_encoder_state,HEX);
216 | Serial.print(F(" encoder_result: "));
217 | Serial.println(az_encoder_result,HEX);
218 | }
219 | last_az_rotary_preset_pin1 = digitalRead(rotary_encoder_pin1);
220 | last_az_rotary_preset_pin2 = digitalRead(rotary_encoder_pin2);
221 | #endif //DEBUG_ENCODER
222 |
223 | if (az_encoder_result) { // If rotary encoder modified
224 |
225 | if (az_encoder_result == DIR_CW) {
226 | #ifdef DEBUG_ENCODER
227 | if (debug_mode){
228 | Serial.println(F("check_preset_encoders: az CW"));
229 | }
230 | #endif //DEBUG_ENCODER
231 |
232 | submit_request(AZ,REQUEST_CW,0);
233 | }
234 | if (az_encoder_result == DIR_CCW) {
235 | #ifdef DEBUG_ENCODER
236 | if (debug_mode){
237 | Serial.println(F("check_preset_encoders: az CCW"));
238 | }
239 | #endif //DEBUG_ENCODER
240 |
241 | submit_request(AZ,REQUEST_CCW,0);
242 |
243 | }
244 |
245 | }
246 |
247 | }
248 | #endif //FEATURE_ROTARY_ENCODER_CONTROL
249 |
250 | //--------------------------------------------------------------
251 |
252 | void service_blink_led(){
253 |
254 | static unsigned long last_blink_led_transition = 0;
255 | static byte blink_led_status = 0;
256 |
257 | #ifdef blink_led
258 | if ((millis() - last_blink_led_transition) >= 1000){
259 | if (blink_led_status){
260 | digitalWriteEnhanced(blink_led,LOW);
261 | blink_led_status = 0;
262 | } else {
263 | digitalWriteEnhanced(blink_led,HIGH);
264 | blink_led_status = 1;
265 | }
266 | last_blink_led_transition = millis();
267 | }
268 |
269 | #endif //blink_led
270 |
271 | }
272 |
273 |
274 | //--------------------------------------------------------------
275 |
276 | #ifdef FEATURE_YAESU_EMULATION
277 | void yaesu_serial_command(){
278 |
279 |
280 |
281 | if (incoming_serial_byte == 10) { return; } // ignore carriage returns
282 | if ((incoming_serial_byte != 13) && (serial0_buffer_index < COMMAND_BUFFER_SIZE)) { // if it's not a carriage return, add it to the buffer
283 | serial0_buffer[serial0_buffer_index] = incoming_serial_byte;
284 | serial0_buffer_index++;
285 | } else { // we got a carriage return, time to get to work on the command
286 | if ((serial0_buffer[0] > 96) && (serial0_buffer[0] < 123)) {
287 | serial0_buffer[0] = serial0_buffer[0] - 32;
288 | }
289 | switch (serial0_buffer[0]) { // look at the first character of the command
290 | case 'C': // C - return current azimuth
291 | #ifdef DEBUG_SERIAL
292 | if (debug_mode) {Serial.println(F("yaesu_serial_command: C cmd"));}
293 | #endif //DEBUG_SERIAL
294 | #ifdef OPTION_DELAY_C_CMD_OUTPUT
295 | delay(400);
296 | #endif
297 | report_current_azimuth();
298 | break;
299 | case 'F': // F - full scale calibration
300 | #ifdef DEBUG_SERIAL
301 | if (debug_mode) {Serial.println(F("yaesu_serial_command: F cmd"));}
302 | #endif //DEBUG_SERIAL
303 | yaesu_f_command();
304 | break;
305 |
306 | case 'H': print_help(); break; // H - print help (simulated Yaesu GS-232A help - not all commands are supported
307 | case 'L': // L - manual left (CCW) rotation
308 | #ifdef DEBUG_SERIAL
309 | if (debug_mode) {Serial.println(F("yaesu_serial_command: L cmd"));}
310 | #endif //DEBUG_SERIAL
311 | submit_request(AZ,REQUEST_CCW,0);
312 | Serial.println();
313 | break;
314 | case 'O': // O - offset calibration
315 | #ifdef DEBUG_SERIAL
316 | if (debug_mode) {Serial.println(F("yaesu_serial_command: O cmd"));}
317 | #endif //DEBUG_SERIAL
318 | yaesu_o_command();
319 | break;
320 | case 'R': // R - manual right (CW) rotation
321 | #ifdef DEBUG_SERIAL
322 | if (debug_mode) {Serial.println(F("yaesu_serial_command: R cmd"));}
323 | #endif //DEBUG_SERIAL
324 | submit_request(AZ,REQUEST_CW,0);
325 | Serial.println();
326 | break;
327 | case 'A': // A - CW/CCW rotation stop
328 | #ifdef DEBUG_SERIAL
329 | if (debug_mode) {Serial.println(F("yaesu_serial_command: A cmd"));}
330 | #endif //DEBUG_SERIAL
331 | submit_request(AZ,REQUEST_STOP,0);
332 | Serial.println();
333 | break;
334 | case 'S': // S - all stop
335 | #ifdef DEBUG_SERIAL
336 | if (debug_mode) {Serial.println(F("yaesu_serial_command: S cmd"));}
337 | #endif //DEBUG_SERIAL
338 | submit_request(AZ,REQUEST_STOP,0);
339 | #ifdef FEATURE_ELEVATION_CONTROL
340 | submit_request(EL,REQUEST_STOP,0);
341 | #endif
342 | #ifdef FEATURE_TIMED_BUFFER
343 | clear_timed_buffer();
344 | #endif //FEATURE_TIMED_BUFFER
345 | Serial.println();
346 | break;
347 | case 'M': // M - auto azimuth rotation
348 | #ifdef DEBUG_SERIAL
349 | if (debug_mode) {Serial.println(F("yaesu_serial_command: M cmd"));}
350 | #endif //DEBUG_SERIAL
351 | yaesu_m_command();
352 | break;
353 | #ifdef FEATURE_TIMED_BUFFER
354 | case 'N': // N - number of loaded timed interval entries
355 | #ifdef DEBUG_SERIAL
356 | if (debug_mode) {Serial.println(F("yaesu_serial_command: N cmd"));}
357 | #endif //DEBUG_SERIAL
358 | Serial.println(timed_buffer_number_entries_loaded);
359 | break;
360 | #endif //FEATURE_TIMED_BUFFER
361 | #ifdef FEATURE_TIMED_BUFFER
362 | case 'T': initiate_timed_buffer(); break; // T - initiate timed tracking
363 | #endif //FEATURE_TIMED_BUFFER
364 | case 'X': // X - azimuth speed change
365 | #ifdef DEBUG_SERIAL
366 | if (debug_mode) {Serial.println(F("yaesu_serial_command: X cmd"));}
367 | #endif //DEBUG_SERIAL
368 | yaesu_x_command();
369 | break;
370 | #ifdef FEATURE_ELEVATION_CONTROL
371 | case 'U': // U - manual up rotation
372 | #ifdef DEBUG_SERIAL
373 | if (debug_mode) {Serial.println(F("yaesu_serial_command: U cmd"));}
374 | #endif //DEBUG_SERIAL
375 | submit_request(EL,REQUEST_UP,0);
376 | Serial.println();
377 | break;
378 | case 'D': // D - manual down rotation
379 | #ifdef DEBUG_SERIAL
380 | if (debug_mode) {Serial.println(F("yaesu_serial_command: D cmd"));}
381 | #endif //DEBUG_SERIAL
382 | submit_request(EL,REQUEST_DOWN,0);
383 | Serial.println();
384 | break;
385 | case 'E': // E - stop elevation rotation
386 | #ifdef DEBUG_SERIAL
387 | if (debug_mode) {Serial.println(F("yaesu_serial_command: E cmd"));}
388 | #endif //DEBUG_SERIAL
389 | submit_request(EL,REQUEST_STOP,0);
390 | Serial.println();
391 | break;
392 | case 'B': report_current_elevation(); break; // B - return current elevation
393 | #endif
394 | case 'W': // W - auto elevation rotation
395 | #ifdef DEBUG_SERIAL
396 | if (debug_mode) {Serial.println(F("yaesu_serial_command: W cmd"));}
397 | #endif //DEBUG_SERIAL
398 | yaesu_w_command();
399 | break;
400 | #ifdef OPTION_GS_232B_EMULATION
401 | case 'P': yaesu_p_command(); break; // P - switch between 360 and 450 degree mode
402 | case 'Z': // Z - Starting point toggle
403 |
404 | break;
405 | #endif
406 | default:
407 | Serial.println(F("?>"));
408 | #ifdef DEBUG_SERIAL
409 | if (debug_mode) {
410 | Serial.print(F("check_serial: serial0_buffer_index: "));
411 | Serial.println(serial0_buffer_index);
412 | for (int debug_x = 0; debug_x < serial0_buffer_index; debug_x++) {
413 | Serial.print(F("check_serial: serial0_buffer["));
414 | Serial.print(debug_x);
415 | Serial.print(F("]: "));
416 | Serial.print(serial0_buffer[debug_x]);
417 | Serial.print(F(" "));
418 | Serial.write(serial0_buffer[debug_x]);
419 | Serial.println();
420 | }
421 | }
422 | #endif //DEBUG_SERIAL
423 | }
424 | clear_command_buffer();
425 | }
426 | }
427 | #endif //FEATURE_YAESU_EMULATION
428 | //--------------------------------------------------------------
429 | void clear_command_buffer(){
430 |
431 | serial0_buffer_index = 0;
432 | serial0_buffer[0] = 0;
433 |
434 |
435 | }
436 |
437 |
438 | //--------------------------------------------------------------
439 |
440 | #ifdef FEATURE_EASYCOM_EMULATION
441 | void easycom_serial_commmand(){
442 |
443 | /* Easycom protocol implementation
444 |
445 | Implemented commands:
446 |
447 | Command Meaning Parameters
448 | ------- ------- ----------
449 | AZ Azimuth number - 1 decimal place
450 | EL Elevation number - 1 decimal place
451 |
452 | ML Move Left
453 | MR Move Right
454 | MU Move Up
455 | MD Move Down
456 | SA Stop azimuth moving
457 | SE Stop elevation moving
458 |
459 | VE Request Version
460 |
461 | Easycom has no way to report azimuth or elevation back to the client, or report errors
462 |
463 |
464 | */
465 |
466 |
467 | float heading = -1;
468 |
469 |
470 |
471 | if ((incoming_serial_byte != 13) && (incoming_serial_byte != 10) && (incoming_serial_byte != 32) && (serial0_buffer_index < COMMAND_BUFFER_SIZE)){ // if it's not a CR, LF, or space, add it to the buffer
472 | if ((incoming_serial_byte > 96) && (incoming_serial_byte < 123)) {incoming_serial_byte = incoming_serial_byte - 32;} //uppercase it
473 | serial0_buffer[serial0_buffer_index] = incoming_serial_byte;
474 | serial0_buffer_index++;
475 | } else { // time to get to work on the command
476 | if (serial0_buffer_index){
477 | switch (serial0_buffer[0]) { // look at the first character of the command
478 | case 'A': //AZ
479 | if (serial0_buffer[1] == 'Z'){ // format is AZx.x or AZxx.x or AZxxx.x (why didn't they make it fixed length?)
480 | switch (serial0_buffer_index) {
481 | #ifdef OPTION_EASYCOM_AZ_QUERY_COMMAND
482 | case 2:
483 | Serial.print("AZ");
484 | Serial.println(float(azimuth*HEADING_MULTIPLIER),1);
485 | clear_command_buffer();
486 | return;
487 | break;
488 | #endif //OPTION_EASYCOM_AZ_QUERY_COMMAND
489 | case 5: // format AZx.x
490 | heading = (serial0_buffer[2]-48) + ((serial0_buffer[4]-48)/10);
491 | break;
492 | case 6: // format AZxx.x
493 | heading = ((serial0_buffer[2]-48)*10) + (serial0_buffer[3]-48) + ((serial0_buffer[5]-48)/10);
494 | break;
495 | case 7: // format AZxxx.x
496 | heading = ((serial0_buffer[2]-48)*100) + ((serial0_buffer[3]-48)*10) + (serial0_buffer[4]-48) + ((serial0_buffer[6]-48)/10);
497 | break;
498 | //default: Serial.println("?"); break;
499 | }
500 | if (((heading >= 0) && (heading < 451)) && (serial0_buffer[serial0_buffer_index-2] == '.')){
501 | submit_request(AZ,REQUEST_AZIMUTH,(heading*HEADING_MULTIPLIER));
502 | } else {
503 | Serial.println("?");
504 | }
505 | } else {
506 | Serial.println("?");
507 | }
508 | break;
509 | case 'S': // SA or SE - stop azimuth, stop elevation
510 | switch (serial0_buffer[1]) {
511 | case 'A':
512 | submit_request(AZ,REQUEST_STOP,0);
513 | break;
514 | #ifdef FEATURE_ELEVATION_CONTROL
515 | case 'E':
516 | submit_request(EL,REQUEST_STOP,0);
517 | break;
518 | #endif //FEATURE_ELEVATION_CONTROL
519 | default: Serial.println("?"); break;
520 | }
521 | break;
522 | case 'M': // ML, MR, MU, MD - move left, right, up, down
523 | switch (serial0_buffer[1]){
524 | case 'L': // ML - move left
525 | submit_request(AZ,REQUEST_CCW,0);
526 | break;
527 | case 'R': // MR - move right
528 | submit_request(AZ,REQUEST_CW,0);
529 | break;
530 | default: Serial.println(F("?")); break;
531 | }
532 | break;
533 | case 'V': // VE - version query
534 | if (serial0_buffer[1] == 'E') {Serial.println(F("VE002"));} // not sure what to send back, sending 002 because this is easycom version 2?
535 | break;
536 | default: Serial.println("?"); break;
537 | }
538 |
539 | }
540 | clear_command_buffer();
541 | }
542 |
543 |
544 | }
545 | #endif //FEATURE_EASYCOM_EMULATION
546 | //--------------------------------------------------------------
547 |
548 | void check_serial(){
549 |
550 | if (Serial.available()) {
551 | if (serial_led) {
552 | digitalWriteEnhanced(serial_led, HIGH); // blink the LED just to say we got something
553 | }
554 |
555 | incoming_serial_byte = Serial.read();
556 | last_serial_receive_time = millis();
557 |
558 | if ((incoming_serial_byte == 92) && (serial0_buffer_index == 0)) { // do we have a backslash command?
559 | serial0_buffer[serial0_buffer_index] = incoming_serial_byte;
560 | serial0_buffer_index++;
561 | backslash_command = 1;
562 | return;
563 | }
564 |
565 | if (backslash_command) {
566 | if (incoming_serial_byte == 13) { // do we have a carriage return?
567 | switch(serial0_buffer[1]){
568 | case 'D': if (debug_mode) {debug_mode = 0;} else {debug_mode = 1;} break; // D - Debug
569 | case 'E' : // E - Initialize eeprom
570 | initialize_eeprom_with_defaults();
571 | Serial.println(F("Initialized eeprom, please reset..."));
572 | break;
573 | case 'L': // L - rotate to long path
574 | if (azimuth < (180)){
575 | submit_request(AZ,REQUEST_AZIMUTH,(azimuth+180));
576 | } else {
577 | submit_request(AZ,REQUEST_AZIMUTH,(azimuth-180));
578 | }
579 | break;
580 |
581 |
582 | #ifdef FEATURE_ANCILLARY_PIN_CONTROL
583 | case 'N' : // \Nxx - turn pin on; xx = pin number
584 | if ((((serial0_buffer[2] > 47) && (serial0_buffer[2] < 58)) || (toupper(serial0_buffer[2]) == 'A')) && (serial0_buffer[3] > 47) && (serial0_buffer[3] < 58) && (serial0_buffer_index == 4)){
585 | byte pin_value = 0;
586 | if (toupper(serial0_buffer[2]) == 'A'){
587 | pin_value = get_analog_pin(serial0_buffer[3]-48);
588 | } else {
589 | pin_value = ((serial0_buffer[2]-48)*10) + (serial0_buffer[3]-48);
590 | }
591 | pinModeEnhanced(pin_value,OUTPUT);
592 | digitalWriteEnhanced(pin_value,PIN_ACTIVE_STATE);
593 | Serial.println("OK");
594 | } else {
595 | Serial.println(F("Error"));
596 | }
597 | break;
598 | case 'F' : // \Fxx - turn pin off; xx = pin number
599 | if ((((serial0_buffer[2] > 47) && (serial0_buffer[2] < 58)) || (toupper(serial0_buffer[2]) == 'A')) && (serial0_buffer[3] > 47) && (serial0_buffer[3] < 58) && (serial0_buffer_index == 4)){
600 | byte pin_value = 0;
601 | if (toupper(serial0_buffer[2]) == 'A'){
602 | pin_value = get_analog_pin(serial0_buffer[3]-48);
603 | } else {
604 | pin_value = ((serial0_buffer[2]-48)*10) + (serial0_buffer[3]-48);
605 | }
606 | pinModeEnhanced(pin_value,OUTPUT);
607 | digitalWriteEnhanced(pin_value,PIN_INACTIVE_STATE);
608 | Serial.println("OK");
609 | } else {
610 | Serial.println(F("Error"));
611 | }
612 | break;
613 | case 'W' : // \Wxxyyy - turn on pin PWM; xx = pin number, yyy = PWM value (0-255)
614 | if (((serial0_buffer[2] > 47) && (serial0_buffer[2] < 58)) && (serial0_buffer[3] > 47) && (serial0_buffer[3] < 58) && (serial0_buffer_index == 7)){
615 | byte pin_value = 0;
616 | if (toupper(serial0_buffer[2]) == 'A'){
617 | pin_value = get_analog_pin(serial0_buffer[3]-48);
618 | } else {
619 | pin_value = ((serial0_buffer[2]-48)*10) + (serial0_buffer[3]-48);
620 | }
621 | int write_value = ((serial0_buffer[4]-48)*100) + ((serial0_buffer[5]-48)*10) + (serial0_buffer[6]-48);
622 | if ((write_value >= 0) && (write_value < 256)){
623 | pinModeEnhanced(pin_value,OUTPUT);
624 | analogWrite(pin_value,write_value);
625 | Serial.println("OK");
626 | } else {
627 | Serial.println(F("Error"));
628 | }
629 | } else {
630 | Serial.println(F("Error"));
631 | }
632 | break;
633 | #endif //FEATURE_ANCILLARY_PIN_CONTROL
634 |
635 | default: Serial.println(F("error"));
636 | }
637 | clear_command_buffer();
638 | backslash_command = 0;
639 |
640 | } else { // no, add the character to the buffer
641 | if ((incoming_serial_byte > 96) && (incoming_serial_byte < 123)) {incoming_serial_byte = incoming_serial_byte - 32;} //uppercase it
642 | if (incoming_serial_byte != 10) { // add it to the buffer if it's not a line feed
643 | serial0_buffer[serial0_buffer_index] = incoming_serial_byte;
644 | serial0_buffer_index++;
645 | }
646 | }
647 |
648 | } else {
649 |
650 |
651 | #ifdef FEATURE_YAESU_EMULATION
652 | yaesu_serial_command();
653 | #endif //FEATURE_YAESU_EMULATION
654 |
655 | #ifdef FEATURE_EASYCOM_EMULATION
656 | easycom_serial_commmand();
657 | #endif //FEATURE_EASYCOM_EMULATION
658 |
659 |
660 | }
661 |
662 | if (serial_led) {
663 | digitalWriteEnhanced(serial_led, LOW);
664 | }
665 | } //if (Serial.available())
666 |
667 |
668 |
669 | }
670 |
671 |
672 | //--------------------------------------------------------------
673 |
674 | #ifdef FEATURE_LCD_DISPLAY
675 | char *azimuth_direction(int azimuth_in){
676 |
677 | //azimuth_in = azimuth_in / HEADING_MULTIPLIER;
678 |
679 |
680 |
681 | if (azimuth_in > 348) {return "N";}
682 | if (azimuth_in > 326) {return "NNW";}
683 | if (azimuth_in > 303) {return "NW";}
684 | if (azimuth_in > 281) {return "WNW";}
685 | if (azimuth_in > 258) {return "W";}
686 | if (azimuth_in > 236) {return "WSW";}
687 | if (azimuth_in > 213) {return "SW";}
688 | if (azimuth_in > 191) {return "SSW";}
689 | if (azimuth_in > 168) {return "S";}
690 | if (azimuth_in > 146) {return "SSE";}
691 | if (azimuth_in > 123) {return "SE";}
692 | if (azimuth_in > 101) {return "ESE";}
693 | if (azimuth_in > 78) {return "E";}
694 | if (azimuth_in > 56) {return "ENE";}
695 | if (azimuth_in > 33) {return "NE";}
696 | if (azimuth_in > 11) {return "NNE";}
697 | return "N";
698 |
699 | }
700 | #endif
701 | //--------------------------------------------------------------
702 | #ifdef FEATURE_LCD_DISPLAY
703 | void update_display()
704 | {
705 |
706 | // update the LCD display
707 |
708 |
709 | String direction_string;
710 | static int last_azimuth = -1;
711 | char workstring[7];
712 |
713 | if (lcd_state_row_0 == LCD_SPLASH){
714 | if ((millis()-last_lcd_update) < 2000){
715 | return;
716 | } else {
717 | lcd_state_row_0 = LCD_UNDEF;
718 | lcd_state_row_1 = LCD_UNDEF;
719 | }
720 | }
721 |
722 |
723 | // row 0 ------------------------------------------------------------
724 | if (((millis() - last_lcd_update) > LCD_UPDATE_TIME) || (push_lcd_update)){
725 | if ((lcd_state_row_0 == LCD_UNDEF) && (lcd_state_row_1 == LCD_UNDEF)){
726 | lcd.clear();
727 | lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2),0);
728 | lcd.print(direction_string);
729 | lcd_state_row_0 = LCD_DIRECTION;
730 | }
731 |
732 | if ((last_azimuth != azimuth) || (lcd_state_row_0 != LCD_DIRECTION)){
733 | direction_string = azimuth_direction(azimuth);
734 | if ((last_direction_string == direction_string) || (lcd_state_row_0 != LCD_DIRECTION)) {
735 | clear_display_row(0);
736 | lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2),0);
737 | lcd.print(direction_string);
738 | lcd_state_row_0 = LCD_DIRECTION;
739 | #ifdef DEBUG_DISPLAY
740 | if (debug_mode) {
741 | Serial.print(F("update_display: "));
742 | Serial.println(direction_string);
743 | }
744 | #endif //DEBUG_DISPLAY
745 | } else {
746 | lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2)-1,0);
747 | lcd.print(" ");
748 | lcd.print(direction_string);
749 | lcd.print(" ");
750 | #ifdef DEBUG_DISPLAY
751 | if (debug_mode) {
752 | Serial.print(F("update_display: row 0: "));
753 | Serial.println(direction_string);
754 | }
755 | #endif //DEBUG_DISPLAY
756 | }
757 | }
758 | push_lcd_update = 0;
759 |
760 | }
761 |
762 |
763 | // row 1 --------------------------------------------
764 | if ((millis()-last_lcd_update) > LCD_UPDATE_TIME) {
765 | if (last_azimuth != azimuth) {
766 | clear_display_row(1);
767 | direction_string = "Azimuth ";
768 | dtostrf(azimuth,1,0,workstring);
769 | direction_string.concat(workstring);
770 | direction_string.concat(char(223));
771 | lcd.setCursor(((LCD_COLUMNS - direction_string.length())/2),1);
772 | //lcd.setCursor(0,2);
773 | //lcd.print("test123");
774 | lcd.print(direction_string);
775 | #ifdef DEBUG_DISPLAY
776 | if (debug_mode) {
777 | Serial.print(F("update_display: row 1: "));
778 | Serial.println(direction_string);
779 | }
780 | #endif //DEBUG_DISPLAY
781 | last_azimuth = azimuth;
782 | lcd_state_row_1 = LCD_HEADING;
783 | }
784 | }
785 | if ((millis() - last_lcd_update) > LCD_UPDATE_TIME) {last_lcd_update = millis();}
786 | last_direction_string = direction_string;
787 | }
788 | #endif
789 | //--------------------------------------------------------------
790 | #ifdef FEATURE_LCD_DISPLAY
791 | void clear_display_row(byte row_number)
792 | {
793 | lcd.setCursor(0,row_number);
794 | for (byte x = 0; x < LCD_COLUMNS; x++) {
795 | lcd.print(" ");
796 | }
797 | }
798 | #endif
799 |
800 | //--------------------------------------------------------------
801 | void get_keystroke()
802 | {
803 | while (Serial.available() == 0) {}
804 | while (Serial.available() > 0) {
805 | incoming_serial_byte = Serial.read();
806 | }
807 | }
808 |
809 | //--------------------------------------------------------------
810 |
811 | #ifdef FEATURE_YAESU_EMULATION
812 | void yaesu_x_command() {
813 |
814 | if (serial0_buffer_index > 1) {
815 | switch (serial0_buffer[1]) {
816 | case '4':
817 | case '3':
818 | case '2':
819 | case '1':
820 | Serial.println(F("Speed commands unsupported..."));
821 | break;
822 | default: Serial.println(F("?>")); break;
823 | }
824 | } else {
825 | Serial.println(F("?>"));
826 | }
827 | }
828 | #endif //FEATURE_YAESU_EMULATION
829 |
830 | //--------------------------------------------------------------
831 | #ifdef FEATURE_YAESU_EMULATION
832 | #ifdef OPTION_GS_232B_EMULATION
833 | void yaesu_p_command()
834 | {
835 | if ((serial0_buffer[1] == '3') && (serial0_buffer_index > 2)) { // P36 command
836 | // configuration.azimuth_rotation_capability = 360;
837 | // Serial.print(F("Mode 360 degree\r\n"));
838 | // write_settings_to_eeprom();
839 | } else {
840 | if ((serial0_buffer[1] == '4') && (serial0_buffer_index > 2)) { // P45 command
841 | // configuration.azimuth_rotation_capability = 450;
842 | // Serial.print(F("Mode 450 degree\r\n"));
843 | // write_settings_to_eeprom();
844 | } else {
845 | Serial.println(F("?>"));
846 | }
847 | }
848 |
849 | }
850 | #endif //OPTION_GS_232B_EMULATION
851 | #endif //FEATURE_YAESU_EMULATION
852 | //--------------------------------------------------------------
853 |
854 | #ifdef FEATURE_YAESU_EMULATION
855 | void yaesu_o_command()
856 | {
857 |
858 | clear_serial_buffer();
859 |
860 | }
861 | #endif //FEATURE_YAESU_EMULATION
862 | //--------------------------------------------------------------
863 | #ifdef FEATURE_YAESU_EMULATION
864 | void print_wrote_to_memory(){
865 |
866 | Serial.println(F("Wrote to memory"));
867 |
868 | }
869 |
870 | #endif //FEATURE_YAESU_EMULATION
871 | //--------------------------------------------------------------
872 | #ifdef FEATURE_YAESU_EMULATION
873 | void clear_serial_buffer(){
874 |
875 | delay(200);
876 | while (Serial.available()) {incoming_serial_byte = Serial.read();}
877 |
878 | }
879 |
880 | #endif //FEATURE_YAESU_EMULATION
881 | //--------------------------------------------------------------
882 |
883 | #ifdef FEATURE_YAESU_EMULATION
884 | void yaesu_f_command()
885 | {
886 |
887 |
888 | clear_serial_buffer();
889 |
890 | }
891 | #endif //FEATURE_YAESU_EMULATION
892 |
893 | //--------------------------------------------------------------
894 |
895 | void read_settings_from_eeprom()
896 | {
897 |
898 | //EEPROM_readAnything(0,configuration);
899 |
900 | byte* p = (byte*)(void*)&configuration;
901 | unsigned int i;
902 | int ee = 0;
903 | for (i = 0; i < sizeof(configuration); i++){
904 | *p++ = EEPROM.read(ee++);
905 | }
906 |
907 | if (configuration.magic_number == EEPROM_MAGIC_NUMBER) {
908 | #ifdef DEBUG_EEPROM
909 | //if (debug_mode) {
910 | Serial.print(F("read_settings_from_eeprom: reading settings from eeprom: "));
911 | Serial.print("last_azimuth:");
912 | Serial.println(configuration.last_azimuth,1);
913 | //}
914 | #endif //DEBUG_EEPROM
915 |
916 |
917 | } else { // initialize eeprom with default values
918 | #ifdef DEBUG_EEPROM
919 | //if (debug_mode) {
920 | Serial.println(F("read_settings_from_eeprom: uninitialized eeprom, calling initialize_eeprom_with_defaults()"));
921 | //}
922 | #endif //DEBUG_EEPROM
923 | initialize_eeprom_with_defaults();
924 | }
925 | }
926 | //--------------------------------------------------------------
927 | void initialize_eeprom_with_defaults(){
928 |
929 | #ifdef DEBUG_EEPROM
930 | if (debug_mode) {
931 | Serial.println(F("initialize_eeprom_with_defaults: writing eeprom"));
932 | }
933 | #endif //DEBUG_EEPROM
934 |
935 |
936 | configuration.last_azimuth = azimuth;
937 |
938 |
939 | write_settings_to_eeprom();
940 |
941 | }
942 |
943 |
944 | //--------------------------------------------------------------
945 | void write_settings_to_eeprom()
946 | {
947 | #ifdef DEBUG_EEPROM
948 | if (debug_mode) {
949 | Serial.print(F("write_settings_to_eeprom: writing settings to eeprom\n"));
950 | }
951 | #endif //DEBUG_EEPROM
952 |
953 | configuration.magic_number = EEPROM_MAGIC_NUMBER;
954 |
955 | const byte* p = (const byte*)(const void*)&configuration;
956 | unsigned int i;
957 | int ee = 0;
958 | for (i = 0; i < sizeof(configuration); i++){
959 | EEPROM.write(ee++, *p++);
960 | }
961 |
962 | configuration_dirty = 0;
963 |
964 | }
965 |
966 | //--------------------------------------------------------------
967 |
968 |
969 | void output_debug()
970 | {
971 |
972 |
973 | if (((millis() - last_debug_output_time) >= 3000) && (debug_mode)) {
974 | Serial.flush();
975 | Serial.print("debug: ");
976 | Serial.print(CODE_VERSION);
977 | Serial.print(" uptime: ");
978 | Serial.print(millis()/1000);
979 | #ifdef DEBUG_MEMORY
980 | void* HP = malloc(4);
981 | if (HP) {
982 | free (HP);
983 | }
984 | unsigned long free = (unsigned long)SP - (unsigned long)HP;
985 | // if (free > 2048) {
986 | // free = 0;
987 | // }
988 | Serial.print((unsigned long)free,DEC);
989 | Serial.print(F("b free"));
990 | #endif
991 |
992 | #ifdef FEATURE_YAESU_EMULATION
993 | Serial.print(F(" GS-232"));
994 | #ifdef OPTION_GS_232B_EMULATION
995 | Serial.print(F("B"));
996 | #endif
997 | #ifndef OPTION_GS_232B_EMULATION
998 | Serial.print(F("A"));
999 | #endif
1000 | #endif //FEATURE_YAESU_EMULATIO
1001 | Serial.print(F(" az: "));
1002 | Serial.print(azimuth);
1003 | Serial.print(F(" current_ant_pos: "));
1004 | Serial.println(current_antenna_position);
1005 | Serial.println();
1006 |
1007 | last_debug_output_time = millis();
1008 |
1009 | }
1010 |
1011 | }
1012 |
1013 | //--------------------------------------------------------------
1014 |
1015 |
1016 | void report_current_azimuth() {
1017 |
1018 | #ifdef FEATURE_YAESU_EMULATION
1019 | // The C command that reports azimuth
1020 |
1021 | String azimuth_string;
1022 |
1023 | #ifndef OPTION_GS_232B_EMULATION
1024 | Serial.print(F("+0"));
1025 | #endif
1026 | #ifdef OPTION_GS_232B_EMULATION
1027 | Serial.print(F("AZ="));
1028 | #endif
1029 |
1030 | azimuth_string = String(int(azimuth), DEC);
1031 | if (azimuth_string.length() == 1) {
1032 | Serial.print(F("00"));
1033 | } else {
1034 | if (azimuth_string.length() == 2) {
1035 | Serial.print(F("0"));
1036 | }
1037 | }
1038 | Serial.print(azimuth_string);
1039 |
1040 | if ((serial0_buffer[1] == '2') && (serial0_buffer_index > 1)) { // did we get the C2 command?
1041 | #ifndef OPTION_GS_232B_EMULATION
1042 | Serial.println(F("+0000")); // return a dummy elevation since we don't have the elevation feature turned on
1043 | #else
1044 | Serial.println(F("EL=000"));
1045 | #endif
1046 | } else {
1047 | Serial.println();
1048 | }
1049 |
1050 | #endif //FEATURE_YAESU_EMULATION
1051 | }
1052 |
1053 |
1054 | //--------------------------------------------------------------
1055 |
1056 | void print_help(){
1057 |
1058 | // The H command
1059 |
1060 | #ifdef OPTION_SERIAL_HELP_TEXT
1061 | #ifdef FEATURE_YAESU_EMULATION
1062 | Serial.println(F("R Rotate Azimuth Clockwise"));
1063 | Serial.println(F("L Rotate Azimuth Counter Clockwise"));
1064 | Serial.println(F("A Stop"));
1065 | Serial.println(F("C Report Azimuth in Degrees"));
1066 | Serial.println(F("M### Rotate to ### degrees"));
1067 | Serial.println(F("MTTT XXX XXX XXX ... Timed Interval Direction Setting (TTT = Step value in seconds, XXX = Azimuth in degrees)"));
1068 | Serial.println(F("T Start Timed Interval Tracking"));
1069 | Serial.println(F("N Report Total Number of M Timed Interval Azimuths"));
1070 | Serial.println(F("X1 Horizontal Rotation Low Speed"));
1071 | Serial.println(F("X2 Horizontal Rotation Middle 1 Speed"));
1072 | Serial.println(F("X3 Horizontal Rotation Middle 2 Speed"));
1073 | Serial.println(F("X4 Horizontal Rotation High Speed"));
1074 | Serial.println(F("S Stop"));
1075 | Serial.println(F("O Offset Calibration"));
1076 | Serial.println(F("F Full Scale Calibration"));
1077 | #endif //FEATURE_YAESU_EMULATION
1078 | #endif //OPTION_SERIAL_HELP_TEXT
1079 |
1080 |
1081 | }
1082 |
1083 |
1084 | //--------------------------------------------------------------
1085 |
1086 | #ifdef FEATURE_YAESU_EMULATION
1087 | void yaesu_w_command ()
1088 | {
1089 |
1090 | // parse out W command
1091 | // Short Format: WXXX YYY = azimuth YYY = elevation
1092 | // Long Format : WSSS XXX YYY SSS = timed interval XXX = azimuth YYY = elevation
1093 |
1094 | int parsed_elevation = 0;
1095 | int parsed_azimuth = 0;
1096 | //int parsed_value1 = 0;
1097 | //int parsed_value2 = 0;
1098 |
1099 | if (serial0_buffer_index > 8) { // if there are more than 4 characters in the command buffer, we got a timed interval command
1100 | #ifdef FEATURE_TIMED_BUFFER
1101 | parsed_value1 = ((int(serial0_buffer[1])-48)*100) + ((int(serial0_buffer[2])-48)*10) + (int(serial0_buffer[3])-48);
1102 | if ((parsed_value1 > 0) && (parsed_value1 < 1000)) {
1103 | timed_buffer_interval_value_seconds = parsed_value1;
1104 | for (int x = 5; x < serial0_buffer_index; x = x + 8) {
1105 | parsed_value1 = ((int(serial0_buffer[x])-48)*100) + ((int(serial0_buffer[x+1])-48)*10) + (int(serial0_buffer[x+2])-48);
1106 | parsed_value2 = ((int(serial0_buffer[x+4])-48)*100) + ((int(serial0_buffer[x+5])-48)*10) + (int(serial0_buffer[x+6])-48);
1107 | if ((parsed_value1 > -1) && (parsed_value1 < 361) && (parsed_value2 > -1) && (parsed_value2 < 181)) { // is it a valid azimuth?
1108 | timed_buffer_azimuths[timed_buffer_number_entries_loaded] = (parsed_value1 * HEADING_MULTIPLIER);
1109 | timed_buffer_elevations[timed_buffer_number_entries_loaded] = (parsed_value2 * HEADING_MULTIPLIER);
1110 | timed_buffer_number_entries_loaded++;
1111 | timed_buffer_status = LOADED_AZIMUTHS_ELEVATIONS;
1112 | if (timed_buffer_number_entries_loaded > TIMED_INTERVAL_ARRAY_SIZE) { // is the array full?
1113 | x = serial0_buffer_index; // array is full, go to the first azimuth and elevation
1114 |
1115 | }
1116 | } else { // we hit an invalid bearing
1117 | timed_buffer_status = EMPTY;
1118 | timed_buffer_number_entries_loaded = 0;
1119 | Serial.println(F("?>")); // error
1120 | return;
1121 | }
1122 | }
1123 | }
1124 | timed_buffer_entry_pointer = 1; // go to the first bearings
1125 | parsed_azimuth = timed_buffer_azimuths[0];
1126 | parsed_elevation = timed_buffer_elevations[0];
1127 | #else
1128 | Serial.println(F("Feature not activated ?>"));
1129 | #endif //FEATURE_TIMED_BUFFER
1130 | } else {
1131 | // this is a short form W command, just parse the azimuth and elevation and initiate rotation
1132 | parsed_azimuth = (((int(serial0_buffer[1])-48)*100) + ((int(serial0_buffer[2])-48)*10) + (int(serial0_buffer[3])-48));
1133 | parsed_elevation = (((int(serial0_buffer[5])-48)*100) + ((int(serial0_buffer[6])-48)*10) + (int(serial0_buffer[7])-48));
1134 | }
1135 |
1136 | if ((parsed_azimuth >= 0) && (parsed_azimuth <= 360)) {
1137 | submit_request(AZ,REQUEST_AZIMUTH,parsed_azimuth);
1138 | } else {
1139 | #ifdef DEBUG_YAESU
1140 | if (debug_mode) {Serial.println(F("yaesu_w_command: W command elevation error"));}
1141 | #endif //DEBUG_YAESU
1142 | Serial.println(F("?>")); // bogus elevation - return and error and don't do anything
1143 | return;
1144 | }
1145 |
1146 | Serial.println();
1147 |
1148 | }
1149 | #endif //FEATURE_YAESU_EMULATION
1150 |
1151 |
1152 | //--------------------------------------------------------------
1153 |
1154 |
1155 |
1156 | void initialize_pins(){
1157 |
1158 | if (serial_led) {
1159 | pinModeEnhanced(serial_led, OUTPUT);
1160 | }
1161 |
1162 | if (button_cw) {
1163 | pinModeEnhanced(button_cw, INPUT);
1164 | digitalWriteEnhanced(button_cw, HIGH);
1165 | }
1166 | if (button_ccw) {
1167 | pinModeEnhanced(button_ccw, INPUT);
1168 | digitalWriteEnhanced(button_ccw, HIGH);
1169 | }
1170 | if (button_flip) {
1171 | pinModeEnhanced(button_flip, INPUT);
1172 | digitalWriteEnhanced(button_flip, HIGH);
1173 | }
1174 |
1175 | if (blink_led) {pinModeEnhanced(blink_led,OUTPUT);}
1176 |
1177 | for (int x = 0; x < number_of_positions; x++){
1178 | pinModeEnhanced(pins[x], OUTPUT);
1179 | digitalWriteEnhanced(pins[x], PIN_INACTIVE_STATE);
1180 | }
1181 |
1182 | #ifdef FEATURE_ROTARY_ENCODER_CONTROL
1183 | pinModeEnhanced(rotary_encoder_pin1, INPUT);
1184 | pinModeEnhanced(rotary_encoder_pin2, INPUT);
1185 | #ifdef OPTION_ENCODER_ENABLE_PULLUPS
1186 | digitalWriteEnhanced(rotary_encoder_pin1, HIGH);
1187 | digitalWriteEnhanced(rotary_encoder_pin2, HIGH);
1188 | #endif //OPTION_ENCODER_ENABLE_PULLUPS
1189 | #endif //FEATURE_ROTARY_ENCODER_CONTROL
1190 |
1191 | if (binary_output_bit_0) {pinModeEnhanced(binary_output_bit_0,OUTPUT); digitalWriteEnhanced(binary_output_bit_0,PIN_INACTIVE_STATE);}
1192 | if (binary_output_bit_1) {pinModeEnhanced(binary_output_bit_1,OUTPUT); digitalWriteEnhanced(binary_output_bit_1,PIN_INACTIVE_STATE);}
1193 | if (binary_output_bit_2) {pinModeEnhanced(binary_output_bit_2,OUTPUT); digitalWriteEnhanced(binary_output_bit_2,PIN_INACTIVE_STATE);}
1194 | if (binary_output_bit_3) {pinModeEnhanced(binary_output_bit_3,OUTPUT); digitalWriteEnhanced(binary_output_bit_3,PIN_INACTIVE_STATE);}
1195 |
1196 | if (comtek_45_135_225_315_bit_0) {pinModeEnhanced(comtek_45_135_225_315_bit_0,OUTPUT); digitalWriteEnhanced(comtek_45_135_225_315_bit_0,PIN_INACTIVE_STATE);}
1197 | if (comtek_45_135_225_315_bit_1) {pinModeEnhanced(comtek_45_135_225_315_bit_1,OUTPUT); digitalWriteEnhanced(comtek_45_135_225_315_bit_1,PIN_INACTIVE_STATE);}
1198 |
1199 |
1200 | submit_request(AZ, REQUEST_AZIMUTH, configuration.last_azimuth);
1201 | }
1202 |
1203 | //--------------------------------------------------------------
1204 |
1205 | void initialize_serial(){
1206 |
1207 | Serial.begin(SERIAL_BAUD_RATE);
1208 |
1209 | #ifdef FEATURE_REMOTE_UNIT_INTERFACE
1210 | remote_unit_port = REMOTE_UNIT_PORT_MAPPED_TO;
1211 | remote_unit_port->begin(REMOTE_UNIT_PORT_BAUD_RATE);
1212 | remote_unit_port->println();
1213 | #endif //FEATURE_REMOTE_UNIT_INTERFACE
1214 | }
1215 |
1216 | //--------------------------------------------------------------
1217 |
1218 | #ifdef FEATURE_LCD_DISPLAY
1219 | void initialize_display(){
1220 |
1221 |
1222 | #ifndef OPTION_INITIALIZE_YOURDUINO_I2C
1223 | lcd.begin(LCD_COLUMNS, 2);
1224 | #endif
1225 |
1226 | #ifdef OPTION_INITIALIZE_YOURDUINO_I2C
1227 | lcd.begin (LCD_COLUMNS,2);
1228 | lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
1229 | lcd.setBacklight(LED_ON);
1230 | #endif //OPTION_INITIALIZE_YOURDUINO_I2C
1231 |
1232 | #ifdef FEATURE_I2C_LCD
1233 | lcd.setBacklight(lcdcolor);
1234 | #endif //FEATURE_I2C_LCD
1235 |
1236 | lcd.setCursor(((LCD_COLUMNS-4)/2),0);
1237 | lcd.print("K3NG");
1238 | if (LCD_COLUMNS < 20) {
1239 | lcd.setCursor(((LCD_COLUMNS-15)/2),1); // W3SA
1240 | } else {
1241 | lcd.setCursor(((LCD_COLUMNS-18)/2),1);
1242 | }
1243 | lcd.print("Array Controller");
1244 | last_lcd_update = millis();
1245 |
1246 | lcd_state_row_0 = LCD_SPLASH;
1247 | lcd_state_row_1 = LCD_SPLASH;
1248 |
1249 | }
1250 | #endif
1251 |
1252 |
1253 |
1254 | //--------------------------------------------------------------
1255 |
1256 |
1257 | void check_for_dirty_configuration(){
1258 |
1259 | static unsigned long last_config_write_time = 0;
1260 |
1261 | if ((configuration_dirty) && ((millis() - last_config_write_time) > (EEPROM_WRITE_DIRTY_CONFIG_TIME*1000))){
1262 | write_settings_to_eeprom();
1263 | last_config_write_time = millis();
1264 | }
1265 |
1266 | }
1267 |
1268 | //--------------------------------------------------------------
1269 |
1270 | void yaesu_m_command(){
1271 |
1272 | int parsed_azimuth = 0;
1273 |
1274 | // parse out M command
1275 | if (serial0_buffer_index > 4) { // if there are more than 4 characters in the command buffer, we got a timed interval command
1276 | Serial.println(F("Feature not activated ?>"));
1277 | return;
1278 | } else { // if there are four characters, this is just a single direction setting
1279 | if (serial0_buffer_index == 4){
1280 | parsed_azimuth = ((int(serial0_buffer[1])-48)*100) + ((int(serial0_buffer[2])-48)*10) + (int(serial0_buffer[3])-48);
1281 | if (parsed_azimuth >= 360) {parsed_azimuth = parsed_azimuth - 360;}
1282 | submit_request(AZ,REQUEST_AZIMUTH,parsed_azimuth);
1283 | return;
1284 | }
1285 | }
1286 |
1287 | Serial.println(F("?>"));
1288 |
1289 | }
1290 | //--------------------------------------------------------------
1291 |
1292 | #if defined(FEATURE_ANCILLARY_PIN_CONTROL)
1293 | byte get_analog_pin(byte pin_number){
1294 |
1295 | byte return_output = 0;
1296 |
1297 | switch(pin_number){
1298 | case 0: return_output = A0; break;
1299 | case 1: return_output = A1; break;
1300 | case 2: return_output = A2; break;
1301 | case 3: return_output = A3; break;
1302 | case 4: return_output = A4; break;
1303 | case 5: return_output = A5; break;
1304 | case 6: return_output = A6; break;
1305 | }
1306 |
1307 | return return_output;
1308 |
1309 | }
1310 | #endif //defined(FEATURE_ANCILLARY_PIN_CONTROL)
1311 |
1312 | //--------------------------------------------------------------
1313 |
1314 | void submit_request(byte axis, byte request, int parm){
1315 |
1316 | byte found_a_match = 0;
1317 |
1318 | #ifdef DEBUG_SUBMIT_REQUEST
1319 | if (debug_mode) {
1320 | Serial.print(F("submit_request: parm: "));
1321 | Serial.print(parm);
1322 | Serial.print(" ");
1323 | }
1324 | #endif //DEBUG_SUBMIT_REQUEST
1325 |
1326 |
1327 | if (axis == AZ) {
1328 | #ifdef DEBUG_SUBMIT_REQUEST
1329 | if (debug_mode) {Serial.print(F("AZ "));}
1330 | #endif //DEBUG_SUBMIT_REQUEST
1331 | switch(request){
1332 | case REQUEST_STOP:
1333 | #ifdef DEBUG_SUBMIT_REQUEST
1334 | if (debug_mode) {Serial.print(F("REQUEST_STOP "));}
1335 | #endif //DEBUG_SUBMIT_REQUEST
1336 | break;
1337 | case REQUEST_AZIMUTH:
1338 | #ifdef DEBUG_SUBMIT_REQUEST
1339 | if (debug_mode) {Serial.print(F("REQUEST_AZIMUTH "));}
1340 | #endif //DEBUG_SUBMIT_REQUEST
1341 | for (int x = 0;x < number_of_positions;x++){
1342 | if ((parm >= ranges[x]) && (parm < ranges[x+1])){
1343 | change_antenna_position(x+1);
1344 | azimuth = parm;
1345 | x = number_of_positions+1;
1346 | found_a_match = 1;
1347 | }
1348 |
1349 | }
1350 | #ifdef DEBUG_SUBMIT_REQUEST
1351 | if (!found_a_match) {Serial.println(F("submit_request: match not found, checking end range"));}
1352 | #endif
1353 | if ((!found_a_match) && (ranges[0] != 0) && ((parm+360) >= ranges[number_of_positions-1]) && ((parm+360) < ranges[number_of_positions])){
1354 | change_antenna_position(number_of_positions);
1355 | azimuth = parm;
1356 | }
1357 | if (azimuth == 360) {azimuth = 0;}
1358 | update_azimuth();
1359 | break;
1360 | case REQUEST_CW:
1361 | #ifdef DEBUG_SUBMIT_REQUEST
1362 | if (debug_mode) {Serial.print(F("REQUEST_CW "));}
1363 | #endif //DEBUG_SUBMIT_REQUEST
1364 | if ((current_antenna_position + 1) <= number_of_positions){
1365 | change_antenna_position(current_antenna_position + 1);
1366 | } else {
1367 | change_antenna_position(1);
1368 | }
1369 | azimuth = ranges[current_antenna_position-1] + ((ranges[current_antenna_position] - ranges[current_antenna_position-1])/2);
1370 | if (azimuth == 360) {azimuth = 0;}
1371 | update_azimuth();
1372 | break;
1373 | case REQUEST_CCW:
1374 | #ifdef DEBUG_SUBMIT_REQUEST
1375 | if (debug_mode) {Serial.print(F("REQUEST_CCW "));}
1376 | #endif //DEBUG_SUBMIT_REQUEST
1377 | if ((current_antenna_position - 1) > 0){
1378 | change_antenna_position(current_antenna_position - 1);
1379 | } else {
1380 | change_antenna_position(number_of_positions);
1381 | }
1382 | azimuth = ranges[current_antenna_position-1] + ((ranges[current_antenna_position] - ranges[current_antenna_position-1])/2);
1383 | if (azimuth == 360) {azimuth = 0;}
1384 | update_azimuth();
1385 | break;
1386 |
1387 | }
1388 | #ifdef DEBUG_SUBMIT_REQUEST
1389 | Serial.println();
1390 | #endif //DEBUG_SUBMIT_REQUEST
1391 | }
1392 |
1393 | }
1394 | //--------------------------------------------------------------
1395 | void update_azimuth(){
1396 | configuration.last_azimuth = azimuth;
1397 | configuration_dirty = 1;
1398 |
1399 |
1400 | if ((comtek_45_135_225_315_bit_0) && (comtek_45_135_225_315_bit_1)){
1401 | if ((azimuth >= 0) && (azimuth < 90)) {
1402 | digitalWriteEnhanced(comtek_45_135_225_315_bit_0,PIN_INACTIVE_STATE);
1403 | digitalWriteEnhanced(comtek_45_135_225_315_bit_1,PIN_INACTIVE_STATE);
1404 | #ifdef DEBUG_ANTENNA_POSITION
1405 | Serial.println(F("update_azimuth: comtek: I I"));
1406 | #endif //DEBUG_ANTENNA_POSITION
1407 | }
1408 | if ((azimuth >= 90) && (azimuth < 180)) {
1409 | digitalWriteEnhanced(comtek_45_135_225_315_bit_0,PIN_ACTIVE_STATE);
1410 | digitalWriteEnhanced(comtek_45_135_225_315_bit_1,PIN_INACTIVE_STATE);
1411 | #ifdef DEBUG_ANTENNA_POSITION
1412 | Serial.println(F("update_azimuth: comtek: I A"));
1413 | #endif //DEBUG_ANTENNA_POSITION
1414 | }
1415 | if ((azimuth >= 180) && (azimuth < 270)) {
1416 | digitalWriteEnhanced(comtek_45_135_225_315_bit_0,PIN_INACTIVE_STATE);
1417 | digitalWriteEnhanced(comtek_45_135_225_315_bit_1,PIN_ACTIVE_STATE);
1418 | #ifdef DEBUG_ANTENNA_POSITION
1419 | Serial.println(F("update_azimuth: comtek: A I"));
1420 | #endif //DEBUG_ANTENNA_POSITION
1421 | }
1422 | if ((azimuth >= 270) && (azimuth < 361)) {
1423 | digitalWriteEnhanced(comtek_45_135_225_315_bit_0,PIN_ACTIVE_STATE);
1424 | digitalWriteEnhanced(comtek_45_135_225_315_bit_1,PIN_ACTIVE_STATE);
1425 | #ifdef DEBUG_ANTENNA_POSITION
1426 | Serial.println(F("update_azimuth: comtek: A A"));
1427 | #endif //DEBUG_ANTENNA_POSITION
1428 | }
1429 | }
1430 |
1431 | }
1432 |
1433 | //--------------------------------------------------------------
1434 | void change_antenna_position(int new_position){
1435 |
1436 | #ifdef DEBUG_ANTENNA_POSITION
1437 | Serial.print(F("change_antenna_position: new_position:"));
1438 | Serial.print(new_position);
1439 | Serial.print(" azimuth:");
1440 | Serial.print(azimuth);
1441 | Serial.print(" ");
1442 | #endif //DEBUG_ANTENNA_POSITION
1443 |
1444 | for (int x = 1;x <= number_of_positions;x++){
1445 | if (x == new_position){
1446 | digitalWriteEnhanced(pins[x-1],PIN_ACTIVE_STATE);
1447 | #ifdef DEBUG_ANTENNA_POSITION
1448 | Serial.print("[");
1449 | Serial.print(x);
1450 | Serial.print("]");
1451 | #endif //DEBUG_ANTENNA_POSITION
1452 | } else {
1453 | digitalWriteEnhanced(pins[x-1],PIN_INACTIVE_STATE);
1454 | #ifdef DEBUG_ANTENNA_POSITION
1455 | Serial.print(x);
1456 | #endif //DEBUG_ANTENNA_POSITION
1457 | }
1458 | #ifdef DEBUG_ANTENNA_POSITION
1459 | Serial.print(" ");
1460 | #endif //DEBUG_ANTENNA_POSITION
1461 | }
1462 |
1463 | if ((new_position & B0001) && (binary_output_bit_0)) {digitalWriteEnhanced(binary_output_bit_0,PIN_ACTIVE_STATE);} else {digitalWriteEnhanced(binary_output_bit_0, PIN_INACTIVE_STATE);}
1464 | if ((new_position & B0010) && (binary_output_bit_1)) {digitalWriteEnhanced(binary_output_bit_1,PIN_ACTIVE_STATE);} else {digitalWriteEnhanced(binary_output_bit_1, PIN_INACTIVE_STATE);}
1465 | if ((new_position & B0100) && (binary_output_bit_2)) {digitalWriteEnhanced(binary_output_bit_2,PIN_ACTIVE_STATE);} else {digitalWriteEnhanced(binary_output_bit_2, PIN_INACTIVE_STATE);}
1466 | if ((new_position & B1000) && (binary_output_bit_3)) {digitalWriteEnhanced(binary_output_bit_3,PIN_ACTIVE_STATE);} else {digitalWriteEnhanced(binary_output_bit_3, PIN_INACTIVE_STATE);}
1467 |
1468 |
1469 |
1470 |
1471 | current_antenna_position = new_position;
1472 |
1473 | #ifdef DEBUG_ANTENNA_POSITION
1474 | Serial.println();
1475 | #endif //DEBUG_ANTENNA_POSITION
1476 |
1477 | }
1478 |
1479 |
1480 | //--------------------------------------------------------------
1481 | void check_buttons(){
1482 |
1483 | static unsigned long last_button_action = 0;
1484 |
1485 | if ((button_cw && (digitalRead(button_cw) == LOW)) && ((millis() - last_button_action) > 250)){
1486 | #ifdef DEBUG_BUTTONS
1487 | if (debug_mode) {Serial.println(F("check_buttons: button_cw pushed"));}
1488 | #endif //DEBUG_BUTTONS
1489 | submit_request(AZ,REQUEST_CW,0);
1490 | last_button_action = millis();
1491 | } else {
1492 | if ((button_ccw && (digitalRead(button_ccw) == LOW)) && ((millis() - last_button_action) > 250)){
1493 | #ifdef DEBUG_BUTTONS
1494 | if (debug_mode) {
1495 | Serial.println(F("check_buttons: button_ccw pushed"));
1496 | }
1497 | #endif //DEBUG_BUTTONS
1498 | submit_request(AZ,REQUEST_CCW,0);
1499 | last_button_action = millis();
1500 | } else {
1501 | if ((button_flip && (digitalRead(button_flip) == LOW)) && ((millis() - last_button_action) > 250)){
1502 | if (azimuth >= 180) {
1503 | submit_request(AZ,REQUEST_AZIMUTH,azimuth-180);
1504 | } else {
1505 | submit_request(AZ,REQUEST_AZIMUTH,azimuth+180);
1506 | }
1507 | last_button_action = millis();
1508 | }
1509 | }
1510 |
1511 | }
1512 |
1513 |
1514 |
1515 |
1516 |
1517 | }
1518 | //--------------------------------------------------------------
1519 |
1520 |
1521 | void pinModeEnhanced(uint8_t pin, uint8_t mode){
1522 |
1523 | #if !defined(FEATURE_REMOTE_UNIT_INTERFACE)
1524 | pinMode(pin, mode);
1525 | #else
1526 | if (pin < 100) {
1527 | pinMode(pin, mode);
1528 | } else {
1529 | submit_remote_command(REMOTE_UNIT_DOI_COMMAND, pin, mode);
1530 | }
1531 | #endif // !defined(FEATURE_REMOTE_UNIT_INTERFACE)
1532 |
1533 | }
1534 |
1535 |
1536 | // --------------------------------------------------------------
1537 |
1538 |
1539 | void digitalWriteEnhanced(uint8_t pin, uint8_t writevalue){
1540 |
1541 |
1542 | #if !defined(FEATURE_REMOTE_UNIT_INTERFACE)
1543 | digitalWrite(pin, writevalue);
1544 | #else
1545 | if (pin < 100) {
1546 | digitalWrite(pin, writevalue);
1547 | } else {
1548 | submit_remote_command(REMOTE_UNIT_DHL_COMMAND, pin, writevalue);
1549 | }
1550 | #endif // !defined(FEATURE_REMOTE_UNIT_INTERFACE)
1551 |
1552 | }
1553 |
1554 | // --------------------------------------------------------------
1555 |
1556 | #ifdef FEATURE_REMOTE_UNIT_INTERFACE
1557 | byte submit_remote_command(byte remote_command_to_send, byte parm1, int parm2){
1558 |
1559 |
1560 | switch (remote_command_to_send) {
1561 |
1562 | case REMOTE_UNIT_DHL_COMMAND:
1563 | remote_unit_port->print("D");
1564 | if (parm2 == HIGH) {remote_unit_port->print("H");} else {remote_unit_port->print("L");}
1565 | parm1 = parm1 - 100;
1566 | if (parm1 < 10) {remote_unit_port->print("0");}
1567 | remote_unit_port->println(parm1);
1568 | break;
1569 |
1570 | case REMOTE_UNIT_DOI_COMMAND:
1571 | remote_unit_port->print("D");
1572 | if (parm2 == OUTPUT) {remote_unit_port->print("O");} else {remote_unit_port->print("I");}
1573 | parm1 = parm1 - 100;
1574 | if (parm1 < 10) {remote_unit_port->print("0");}
1575 | remote_unit_port->println(parm1);
1576 | break;
1577 |
1578 | }
1579 |
1580 |
1581 | } /* submit_remote_command */
1582 | #endif //FEATURE_REMOTE_UNIT_INTERFACE
--------------------------------------------------------------------------------
/antenna_array_controller_features.h:
--------------------------------------------------------------------------------
1 | /* ---------------------- Features and Options - you must configure this !! ------------------------------------------------*/
2 |
3 | /* main features */
4 | #define FEATURE_YAESU_EMULATION // uncomment this for Yaesu GS-232A emulation
5 | // #define FEATURE_ROTARY_ENCODER_CONTROL
6 | #define OPTION_ENCODER_ENABLE_PULLUPS // activate pullups on encoder input lines (with this you don't need to install 1k pullup resistors)
7 | #define OPTION_ENCODER_HALF_STEP_MODE
8 | #define OPTION_GS_232B_EMULATION // uncomment this for GS-232B emulation (also uncomment FEATURE_YAESU_EMULATION above)
9 | //#define FEATURE_EASYCOM_EMULATION // Easycom protocol emulation (undefine FEATURE_YAESU_EMULATION above)
10 | // #define FEATURE_LCD_DISPLAY // Uncomment for *all* LCD displays
11 | //#define FEATURE_I2C_LCD // Uncomment for Adafruit, YourDuino.com, or DFRobot I2C LCD display (also uncomment section in rotator_settings.h object declarations)
12 | //#define FEATURE_ANCILLARY_PIN_CONTROL
13 | // #define FEATURE_REMOTE_UNIT_INTERFACE // uncomment to activate remote unit port
14 | /*
15 |
16 | Note:
17 |
18 | Ham Radio Deluxe expects AZ and EL in output for Yaesu C command in AZ/EL mode. I'm not sure if this is default behavior for
19 | the Yaesu interface since the C2 command is supposed to be for AZ and EL. If you have problems with other software with this code in AZ/EL mode,
20 | uncomment #define OPTION_C_COMMAND_SENDS_AZ_AND_EL.
21 |
22 | */
23 |
24 | //#define OPTION_C_COMMAND_SENDS_AZ_AND_EL.
25 | #define OPTION_SERIAL_HELP_TEXT
26 |
27 | /* ---------------------- debug stuff - don't touch unless you know what you are doing --------------------------- */
28 |
29 |
30 |
31 | #define DEFAULT_DEBUG_STATE 0 // this should be set to zero unless you're debugging something at startup
32 |
33 | //#define DEBUG_MEMORY
34 | //#define DEBUG_SERIAL
35 | // #define DEBUG_EEPROM
36 | //#define DEBUG_DISPLAY
37 | // #define DEBUG_SUBMIT_REQUEST
38 | //#define DEBUG_YAESU
39 | // #define DEBUG_ANTENNA_POSITION
40 | //#define DEBUG_ENCODER
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/antenna_array_controller_pins.h:
--------------------------------------------------------------------------------
1 | /* ------------------------------------- Pin Definitions ------------------------------------------
2 |
3 | You need to look at these and set them appropriately !
4 |
5 | Most pins can be disabled by setting them to 0 (zero). If you're not using a pin or function, set it to 0.
6 |
7 | */
8 |
9 | #define button_cw 0 // normally open button to ground for manual CW rotation (schematic pin: A1)
10 | #define button_ccw 0 // normally open button to ground for manual CCW rotation (schematic pin: A2)
11 | #define button_flip 0 // flip to long path (+/- 180 degrees)
12 | #define serial_led 0 // LED blinks when command is received on serial port (set to 0 to disable)
13 | #define blink_led 13 // "run" LED - links every second (set to 0 to disable)
14 |
15 | // antenna binary output pins (set to 0 to disable)
16 | #define binary_output_bit_0 6 // least significant bit
17 | #define binary_output_bit_1 7
18 | #define binary_output_bit_2 8
19 | #define binary_output_bit_3 9 // most significant bit
20 |
21 | //classic 4 bit LCD pins
22 | #define lcd_4_bit_rs_pin 12
23 | #define lcd_4_bit_enable_pin 11
24 | #define lcd_4_bit_d4_pin 5
25 | #define lcd_4_bit_d5_pin 4
26 | #define lcd_4_bit_d6_pin 3
27 | #define lcd_4_bit_d7_pin 2
28 |
29 | // rotary encoder pins
30 | #define rotary_encoder_pin1 A3 //0
31 | #define rotary_encoder_pin2 A2 //0
32 |
33 |
34 | // outputs for Comtek ACB-4 unit https://static.dxengineering.com/global/images/instructions/com-acb-80-a.pdf
35 | //
36 | // set to 0 (zero) to disable
37 | //
38 | // bit
39 | // -------------------
40 | // Degrees 1 0
41 | // ------- -------- --------
42 | // 45 INACTIVE INACTIVE
43 | // 135 INACTIVE ACTIVE
44 | // 225 ACTIVE INACTIVE
45 | // 315 ACTIVE ACTIVE
46 | //
47 | #define comtek_45_135_225_315_bit_0 0
48 | #define comtek_45_135_225_315_bit_1 0
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/antenna_array_controller_settings.h:
--------------------------------------------------------------------------------
1 |
2 | /* -------------------------- rotation settings ---------------------------------------
3 |
4 |
5 | */
6 | #define SERIAL_BAUD_RATE 9600
7 | #define LCD_UPDATE_TIME 100 // LCD update time in milliseconds
8 | #define EEPROM_MAGIC_NUMBER 100
9 | #define EEPROM_WRITE_DIRTY_CONFIG_TIME 30 //time in seconds
10 | #define COMMAND_BUFFER_SIZE 20
11 |
12 | #define REMOTE_UNIT_PORT_MAPPED_TO &Serial1
13 | #define REMOTE_UNIT_PORT_BAUD_RATE 9600 // baud rate for the port interfacing with a remote unit
14 |
15 | #define PIN_ACTIVE_STATE HIGH
16 | #define PIN_INACTIVE_STATE LOW
17 |
18 |
19 | /* ---------------------------- object declarations ----------------------------------------------
20 |
21 |
22 | Object declarations are required for several LCD displays
23 |
24 |
25 | */
26 |
27 | /* uncomment this section for classic 4 bit interface LCD display (in addition to FEATURE_LCD_DISPLAY above) */
28 | LiquidCrystal lcd(lcd_4_bit_rs_pin, lcd_4_bit_enable_pin, lcd_4_bit_d4_pin, lcd_4_bit_d5_pin, lcd_4_bit_d6_pin, lcd_4_bit_d7_pin);
29 | /* end of classic 4 bit interface LCD display section */
30 |
31 | /* uncomment this section for Adafruit I2C LCD display */
32 | //Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
33 | /* end of Adafruit I2C LCD display */
34 |
35 | /* uncomment the section for YourDuino.com I2C LCD display */
36 | //#define OPTION_INITIALIZE_YOURDUINO_I2C
37 | //#define I2C_ADDR 0x20
38 | //#define BACKLIGHT_PIN 3
39 | //#define En_pin 2
40 | //#define Rw_pin 1
41 | //#define Rs_pin 0
42 | //#define D4_pin 4
43 | //#define D5_pin 5
44 | //#define D6_pin 6
45 | //#define D7_pin 7
46 | //#define LED_OFF 1
47 | //#define LED_ON 0
48 | //LiquidCrystal_I2C lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);
49 | /* end of of section to uncomment for YourDuino.com I2C LCD display */
50 |
51 | /* uncomment the section for DFRobot I2C LCD display */
52 | //LiquidCrystal_I2C lcd(0x27,16,2);
53 | /* end of of section to uncomment for DFRobot I2C LCD display */
54 |
55 |
--------------------------------------------------------------------------------