├── LICENSE
├── README.md
├── ubitx_cat.ino
├── ubitx_factory_alignment.ino
├── ubitx_keyer.ino
├── ubitx_menu.ino
├── ubitx_si5351.ino
├── ubitx_ui.ino
├── ubitx_v5.1_code.ino
└── ubitx_v5.pdf
/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 | # ubitx_v5
2 | Firmware for the version 5 of the ubitx
3 |
--------------------------------------------------------------------------------
/ubitx_cat.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * The CAT protocol is used by many radios to provide remote control to comptuers through
3 | * the serial port.
4 | *
5 | * This is very much a work in progress. Parts of this code have been liberally
6 | * borrowed from other GPLicensed works like hamlib.
7 | *
8 | * WARNING : This is an unstable version and it has worked with fldigi,
9 | * it gives time out error with WSJTX 1.8.0
10 | */
11 |
12 | static unsigned long rxBufferArriveTime = 0;
13 | static byte rxBufferCheckCount = 0;
14 | #define CAT_RECEIVE_TIMEOUT 500
15 | static byte cat[5];
16 | static byte insideCat = 0;
17 | static byte useOpenRadioControl = 0;
18 |
19 | //for broken protocol
20 | #define CAT_RECEIVE_TIMEOUT 500
21 |
22 | #define CAT_MODE_LSB 0x00
23 | #define CAT_MODE_USB 0x01
24 | #define CAT_MODE_CW 0x02
25 | #define CAT_MODE_CWR 0x03
26 | #define CAT_MODE_AM 0x04
27 | #define CAT_MODE_FM 0x08
28 | #define CAT_MODE_DIG 0x0A
29 | #define CAT_MODE_PKT 0x0C
30 | #define CAT_MODE_FMN 0x88
31 |
32 | #define ACK 0
33 |
34 | unsigned int skipTimeCount = 0;
35 |
36 | byte setHighNibble(byte b,byte v) {
37 | // Clear the high nibble
38 | b &= 0x0f;
39 | // Set the high nibble
40 | return b | ((v & 0x0f) << 4);
41 | }
42 |
43 | byte setLowNibble(byte b,byte v) {
44 | // Clear the low nibble
45 | b &= 0xf0;
46 | // Set the low nibble
47 | return b | (v & 0x0f);
48 | }
49 |
50 | byte getHighNibble(byte b) {
51 | return (b >> 4) & 0x0f;
52 | }
53 |
54 | byte getLowNibble(byte b) {
55 | return b & 0x0f;
56 | }
57 |
58 | // Takes a number and produces the requested number of decimal digits, staring
59 | // from the least significant digit.
60 | //
61 | void getDecimalDigits(unsigned long number,byte* result,int digits) {
62 | for (int i = 0; i < digits; i++) {
63 | // "Mask off" (in a decimal sense) the LSD and return it
64 | result[i] = number % 10;
65 | // "Shift right" (in a decimal sense)
66 | number /= 10;
67 | }
68 | }
69 |
70 | // Takes a frequency and writes it into the CAT command buffer in BCD form.
71 | //
72 | void writeFreq(unsigned long freq,byte* cmd) {
73 | // Convert the frequency to a set of decimal digits. We are taking 9 digits
74 | // so that we can get up to 999 MHz. But the protocol doesn't care about the
75 | // LSD (1's place), so we ignore that digit.
76 | byte digits[9];
77 | getDecimalDigits(freq,digits,9);
78 | // Start from the LSB and get each nibble
79 | cmd[3] = setLowNibble(cmd[3],digits[1]);
80 | cmd[3] = setHighNibble(cmd[3],digits[2]);
81 | cmd[2] = setLowNibble(cmd[2],digits[3]);
82 | cmd[2] = setHighNibble(cmd[2],digits[4]);
83 | cmd[1] = setLowNibble(cmd[1],digits[5]);
84 | cmd[1] = setHighNibble(cmd[1],digits[6]);
85 | cmd[0] = setLowNibble(cmd[0],digits[7]);
86 | cmd[0] = setHighNibble(cmd[0],digits[8]);
87 | }
88 |
89 | // This function takes a frquency that is encoded using 4 bytes of BCD
90 | // representation and turns it into an long measured in Hz.
91 | //
92 | // [12][34][56][78] = 123.45678? Mhz
93 | //
94 | unsigned long readFreq(byte* cmd) {
95 | // Pull off each of the digits
96 | byte d7 = getHighNibble(cmd[0]);
97 | byte d6 = getLowNibble(cmd[0]);
98 | byte d5 = getHighNibble(cmd[1]);
99 | byte d4 = getLowNibble(cmd[1]);
100 | byte d3 = getHighNibble(cmd[2]);
101 | byte d2 = getLowNibble(cmd[2]);
102 | byte d1 = getHighNibble(cmd[3]);
103 | byte d0 = getLowNibble(cmd[3]);
104 | return
105 | (unsigned long)d7 * 100000000L +
106 | (unsigned long)d6 * 10000000L +
107 | (unsigned long)d5 * 1000000L +
108 | (unsigned long)d4 * 100000L +
109 | (unsigned long)d3 * 10000L +
110 | (unsigned long)d2 * 1000L +
111 | (unsigned long)d1 * 100L +
112 | (unsigned long)d0 * 10L;
113 | }
114 |
115 | //void ReadEEPRom_FT817(byte fromType)
116 | void catReadEEPRom(void)
117 | {
118 | //for remove warnings
119 | byte temp0 = cat[0];
120 | byte temp1 = cat[1];
121 | /*
122 | itoa((int) cat[0], b, 16);
123 | strcat(b, ":");
124 | itoa((int) cat[1], c, 16);
125 | strcat(b, c);
126 | printLine2(b);
127 | */
128 |
129 | cat[0] = 0;
130 | cat[1] = 0;
131 | //for remove warnings[1] = 0;
132 |
133 | switch (temp1)
134 | {
135 | case 0x45 : //
136 | if (temp0 == 0x03)
137 | {
138 | cat[0] = 0x00;
139 | cat[1] = 0xD0;
140 | }
141 | break;
142 | case 0x47 : //
143 | if (temp0 == 0x03)
144 | {
145 | cat[0] = 0xDC;
146 | cat[1] = 0xE0;
147 | }
148 | break;
149 | case 0x55 :
150 | //0 : VFO A/B 0 = VFO-A, 1 = VFO-B
151 | //1 : MTQMB Select 0 = (Not MTQMB), 1 = MTQMB ("Memory Tune Quick Memory Bank")
152 | //2 : QMB Select 0 = (Not QMB), 1 = QMB ("Quick Memory Bank")
153 | //3 :
154 | //4 : Home Select 0 = (Not HOME), 1 = HOME memory
155 | //5 : Memory/MTUNE select 0 = Memory, 1 = MTUNE
156 | //6 :
157 | //7 : MEM/VFO Select 0 = Memory, 1 = VFO (A or B - see bit 0)
158 | cat[0] = 0x80 + (vfoActive == VFO_B ? 1 : 0);
159 | cat[1] = 0x00;
160 | break;
161 | case 0x57 : //
162 | //0 : 1-0 AGC Mode 00 = Auto, 01 = Fast, 10 = Slow, 11 = Off
163 | //2 DSP On/Off 0 = Off, 1 = On (Display format)
164 | //4 PBT On/Off 0 = Off, 1 = On (Passband Tuning)
165 | //5 NB On/Off 0 = Off, 1 = On (Noise Blanker)
166 | //6 Lock On/Off 0 = Off, 1 = On (Dial Lock)
167 | //7 FST (Fast Tuning) On/Off 0 = Off, 1 = On (Fast tuning)
168 |
169 | cat[0] = 0xC0;
170 | cat[1] = 0x40;
171 | break;
172 | case 0x59 : // band select VFO A Band Select 0000 = 160 M, 0001 = 75 M, 0010 = 40 M, 0011 = 30 M, 0100 = 20 M, 0101 = 17 M, 0110 = 15 M, 0111 = 12 M, 1000 = 10 M, 1001 = 6 M, 1010 = FM BCB, 1011 = Air, 1100 = 2 M, 1101 = UHF, 1110 = (Phantom)
173 | //http://www.ka7oei.com/ft817_memmap.html
174 | //CAT_BUFF[0] = 0xC2;
175 | //CAT_BUFF[1] = 0x82;
176 | break;
177 | case 0x5C : //Beep Volume (0-100) (#13)
178 | cat[0] = 0xB2;
179 | cat[1] = 0x42;
180 | break;
181 | case 0x5E :
182 | //3-0 : CW Pitch (300-1000 Hz) (#20) From 0 to E (HEX) with 0 = 300 Hz and each step representing 50 Hz
183 | //5-4 : Lock Mode (#32) 00 = Dial, 01 = Freq, 10 = Panel
184 | //7-6 : Op Filter (#38) 00 = Off, 01 = SSB, 10 = CW
185 | //CAT_BUFF[0] = 0x08;
186 | cat[0] = (sideTone - 300)/50;
187 | cat[1] = 0x25;
188 | break;
189 | case 0x61 : //Sidetone (Volume) (#44)
190 | cat[0] = sideTone % 50;
191 | cat[1] = 0x08;
192 | break;
193 | case 0x5F : //
194 | //4-0 CW Weight (1.:2.5-1:4.5) (#22) From 0 to 14 (HEX) with 0 = 1:2.5, incrementing in 0.1 weight steps
195 | //5 420 ARS (#2) 0 = Off, 1 = On
196 | //6 144 ARS (#1) 0 = Off, 1 = On
197 | //7 Sql/RF-G (#45) 0 = Off, 1 = On
198 | cat[0] = 0x32;
199 | cat[1] = 0x08;
200 | break;
201 | case 0x60 : //CW Delay (10-2500 ms) (#17) From 1 to 250 (decimal) with each step representing 10 ms
202 | cat[0] = cwDelayTime;
203 | cat[1] = 0x32;
204 | break;
205 | case 0x62 : //
206 | //5-0 CW Speed (4-60 WPM) (#21) From 0 to 38 (HEX) with 0 = 4 WPM and 38 = 60 WPM (1 WPM steps)
207 | //7-6 Batt-Chg (6/8/10 Hours (#11) 00 = 6 Hours, 01 = 8 Hours, 10 = 10 Hours
208 | //CAT_BUFF[0] = 0x08;
209 | cat[0] = 1200 / cwSpeed - 4;
210 | cat[1] = 0xB2;
211 | break;
212 | case 0x63 : //
213 | //6-0 VOX Gain (#51) Contains 1-100 (decimal) as displayed
214 | //7 Disable AM/FM Dial (#4) 0 = Enable, 1 = Disable
215 | cat[0] = 0xB2;
216 | cat[1] = 0xA5;
217 | break;
218 | case 0x64 : //
219 | break;
220 | case 0x67 : //6-0 SSB Mic (#46) Contains 0-100 (decimal) as displayed
221 | cat[0] = 0xB2;
222 | cat[1] = 0xB2;
223 | break; case 0x69 : //FM Mic (#29) Contains 0-100 (decimal) as displayed
224 | case 0x78 :
225 | if (isUSB)
226 | cat[0] = CAT_MODE_USB;
227 | else
228 | cat[0] = CAT_MODE_LSB;
229 |
230 | if (cat[0] != 0) cat[0] = 1 << 5;
231 | break;
232 | case 0x79 : //
233 | //1-0 TX Power (All bands) 00 = High, 01 = L3, 10 = L2, 11 = L1
234 | //3 PRI On/Off 0 = Off, 1 = On
235 | //DW On/Off 0 = Off, 1 = On
236 | //SCN (Scan) Mode 00 = No scan, 10 = Scan up, 11 = Scan down
237 | //ART On/Off 0 = Off, 1 = On
238 | cat[0] = 0x00;
239 | cat[1] = 0x00;
240 | break;
241 | case 0x7A : //SPLIT
242 | //7A 0 HF Antenna Select 0 = Front, 1 = Rear
243 | //7A 1 6 M Antenna Select 0 = Front, 1 = Rear
244 | //7A 2 FM BCB Antenna Select 0 = Front, 1 = Rear
245 | //7A 3 Air Antenna Select 0 = Front, 1 = Rear
246 | //7A 4 2 M Antenna Select 0 = Front, 1 = Rear
247 | //7A 5 UHF Antenna Select 0 = Front, 1 = Rear
248 | //7A 6 ? ?
249 | //7A 7 SPL On/Off 0 = Off, 1 = On
250 |
251 | cat[0] = (splitOn ? 0xFF : 0x7F);
252 | break;
253 | case 0xB3 : //
254 | cat[0] = 0x00;
255 | cat[1] = 0x4D;
256 | break;
257 |
258 | }
259 |
260 | // sent the data
261 | Serial.write(cat, 2);
262 | }
263 |
264 | void processCATCommand2(byte* cmd) {
265 | byte response[5];
266 | unsigned long f;
267 |
268 | switch(cmd[4]){
269 | /* case 0x00:
270 | response[0]=0;
271 | Serial.write(response, 1);
272 | break;
273 | */
274 | case 0x01:
275 | //set frequency
276 | f = readFreq(cmd);
277 | setFrequency(f);
278 | updateDisplay();
279 | response[0]=0;
280 | Serial.write(response, 1);
281 | //sprintf(b, "set:%ld", f);
282 | //printLine2(b);
283 | break;
284 |
285 | case 0x02:
286 | //split on
287 | splitOn = 1;
288 | break;
289 | case 0x82:
290 | //split off
291 | splitOn = 0;
292 | break;
293 |
294 | case 0x03:
295 | writeFreq(frequency,response); // Put the frequency into the buffer
296 | if (isUSB)
297 | response[4] = 0x01; //USB
298 | else
299 | response[4] = 0x00; //LSB
300 | Serial.write(response,5);
301 | //printLine2("cat:getfreq");
302 | break;
303 |
304 | case 0x07: // set mode
305 | if (cmd[0] == 0x00 || cmd[0] == 0x03)
306 | isUSB = 0;
307 | else
308 | isUSB = 1;
309 | response[0] = 0x00;
310 | Serial.write(response, 1);
311 | setFrequency(frequency);
312 | //printLine2("cat: mode changed");
313 | //updateDisplay();
314 | break;
315 |
316 | case 0x08: // PTT On
317 | if (!inTx) {
318 | response[0] = 0;
319 | txCAT = true;
320 | startTx(TX_SSB);
321 | updateDisplay();
322 | } else {
323 | response[0] = 0xf0;
324 | }
325 | Serial.write(response,1);
326 | updateDisplay();
327 | break;
328 |
329 | case 0x88 : //PTT OFF
330 | if (inTx) {
331 | stopTx();
332 | txCAT = false;
333 | }
334 | response[0] = 0;
335 | Serial.write(response,1);
336 | updateDisplay();
337 | break;
338 |
339 | case 0x81:
340 | //toggle the VFOs
341 | response[0] = 0;
342 | menuVfoToggle(1); // '1' forces it to change the VFO
343 | Serial.write(response,1);
344 | updateDisplay();
345 | break;
346 |
347 | case 0xBB: //Read FT-817 EEPROM Data (for comfirtable)
348 | catReadEEPRom();
349 | break;
350 |
351 | case 0xe7 :
352 | // get receiver status, we have hardcoded this as
353 | //as we dont' support ctcss, etc.
354 | response[0] = 0x09;
355 | Serial.write(response,1);
356 | break;
357 |
358 | case 0xf7:
359 | {
360 | boolean isHighSWR = false;
361 | boolean isSplitOn = false;
362 |
363 | /*
364 | Inverted -> *ptt = ((p->tx_status & 0x80) == 0); <-- souce code in ft817.c (hamlib)
365 | */
366 | response[0] = ((inTx ? 0 : 1) << 7) +
367 | ((isHighSWR ? 1 : 0) << 6) + //hi swr off / on
368 | ((isSplitOn ? 1 : 0) << 5) + //Split on / off
369 | (0 << 4) + //dummy data
370 | 0x08; //P0 meter data
371 |
372 | Serial.write(response, 1);
373 | }
374 | break;
375 |
376 | default:
377 | //somehow, get this to print the four bytes
378 | ultoa(*((unsigned long *)cmd), c, 16);
379 | itoa(cmd[4], b, 16);
380 | strcat(b, ">");
381 | strcat(b, c);
382 | printLine2(b);
383 | response[0] = 0x00;
384 | Serial.write(response[0]);
385 | }
386 |
387 | insideCat = false;
388 | }
389 |
390 | int catCount = 0;
391 | void checkCAT(){
392 | byte i;
393 |
394 | //Check Serial Port Buffer
395 | if (Serial.available() == 0) { //Set Buffer Clear status
396 | rxBufferCheckCount = 0;
397 | return;
398 | }
399 | else if (Serial.available() < 5) { //First Arrived
400 | if (rxBufferCheckCount == 0){
401 | rxBufferCheckCount = Serial.available();
402 | rxBufferArriveTime = millis() + CAT_RECEIVE_TIMEOUT; //Set time for timeout
403 | }
404 | else if (rxBufferArriveTime < millis()){ //Clear Buffer
405 | for (i = 0; i < Serial.available(); i++)
406 | rxBufferCheckCount = Serial.read();
407 | rxBufferCheckCount = 0;
408 | }
409 | else if (rxBufferCheckCount < Serial.available()){ // Increase buffer count, slow arrive
410 | rxBufferCheckCount = Serial.available();
411 | rxBufferArriveTime = millis() + CAT_RECEIVE_TIMEOUT; //Set time for timeout
412 | }
413 | return;
414 | }
415 |
416 |
417 | //Arived CAT DATA
418 | for (i = 0; i < 5; i++)
419 | cat[i] = Serial.read();
420 |
421 |
422 | //this code is not re-entrant.
423 | if (insideCat == 1)
424 | return;
425 | insideCat = 1;
426 |
427 | /**
428 | * This routine is enabled to debug the cat protocol
429 | **/
430 | catCount++;
431 |
432 | if (cat[4] != 0xf7 && cat[4] != 0xbb && cat[4] != 0x03){
433 | sprintf(b, "%d %02x %02x%02x%02x%02x", catCount, cat[4],cat[0], cat[1], cat[2], cat[3]);
434 | printLine2(b);
435 | }
436 |
437 | processCATCommand2(cat);
438 | insideCat = 0;
439 | }
440 |
441 |
442 |
--------------------------------------------------------------------------------
/ubitx_factory_alignment.ino:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * This procedure is only for those who have a signal generator/transceiver tuned to exactly 7.150 and a dummy load
4 | */
5 |
6 | void btnWaitForClick(){
7 | while(!btnDown())
8 | active_delay(50);
9 | while(btnDown())
10 | active_delay(50);
11 | active_delay(50);
12 | }
13 |
14 | /**
15 | * Take a deep breath, math(ematics) ahead
16 | * The 25 mhz oscillator is multiplied by 35 to run the vco at 875 mhz
17 | * This is divided by a number to generate different frequencies.
18 | * If we divide it by 875, we will get 1 mhz signal
19 | * So, if the vco is shifted up by 875 hz, the generated frequency of 1 mhz is shifted by 1 hz (875/875)
20 | * At 12 Mhz, the carrier will needed to be shifted down by 12 hz for every 875 hz of shift up of the vco
21 | *
22 | */
23 |
24 |
25 | void factory_alignment(){
26 |
27 | calibrateClock();
28 |
29 | if (calibration == 0){
30 | printLine2("Setup Aborted");
31 | return;
32 | }
33 |
34 | //move it away to 7.160 for an LSB signal
35 | setFrequency(7170000l);
36 | updateDisplay();
37 | printLine2("#2 BFO");
38 | active_delay(1000);
39 |
40 | usbCarrier = 11053000l;
41 | menuSetupCarrier(1);
42 |
43 | if (usbCarrier == 11994999l){
44 | printLine2("Setup Aborted");
45 | return;
46 | }
47 |
48 | printLine2("#3:Test 3.5MHz");
49 | isUSB = false;
50 | setFrequency(3500000l);
51 | updateDisplay();
52 |
53 | while (!btnDown()){
54 | checkPTT();
55 | active_delay(100);
56 | }
57 |
58 | btnWaitForClick();
59 | printLine2("#4:Test 7MHz");
60 |
61 | setFrequency(7150000l);
62 | updateDisplay();
63 | while (!btnDown()){
64 | checkPTT();
65 | active_delay(100);
66 | }
67 |
68 | btnWaitForClick();
69 | printLine2("#5:Test 14MHz");
70 |
71 | isUSB = true;
72 | setFrequency(14000000l);
73 | updateDisplay();
74 | while (!btnDown()){
75 | checkPTT();
76 | active_delay(100);
77 | }
78 |
79 | btnWaitForClick();
80 | printLine2("#6:Test 28MHz");
81 |
82 | setFrequency(28000000l);
83 | updateDisplay();
84 | while (!btnDown()){
85 | checkPTT();
86 | active_delay(100);
87 | }
88 |
89 | printLine2("Alignment done");
90 | active_delay(1000);
91 |
92 | isUSB = false;
93 | setFrequency(7150000l);
94 | updateDisplay();
95 |
96 | }
97 |
98 |
--------------------------------------------------------------------------------
/ubitx_keyer.ino:
--------------------------------------------------------------------------------
1 | /**
2 | CW Keyer
3 | CW Key logic change with ron's code (ubitx_keyer.cpp)
4 | Ron's logic has been modified to work with the original uBITX by KD8CEC
5 |
6 | Original Comment ----------------------------------------------------------------------------
7 | * The CW keyer handles either a straight key or an iambic / paddle key.
8 | * They all use just one analog input line. This is how it works.
9 | * The analog line has the internal pull-up resistor enabled.
10 | * When a straight key is connected, it shorts the pull-up resistor, analog input is 0 volts
11 | * When a paddle is connected, the dot and the dash are connected to the analog pin through
12 | * a 10K and a 2.2K resistors. These produce a 4v and a 2v input to the analog pins.
13 | * So, the readings are as follows :
14 | * 0v - straight key
15 | * 1-2.5 v - paddle dot
16 | * 2.5 to 4.5 v - paddle dash
17 | * 2.0 to 0.5 v - dot and dash pressed
18 | *
19 | * The keyer is written to transparently handle all these cases
20 | *
21 | * Generating CW
22 | * The CW is cleanly generated by unbalancing the front-end mixer
23 | * and putting the local oscillator directly at the CW transmit frequency.
24 | * The sidetone, generated by the Arduino is injected into the volume control
25 | */
26 |
27 | //CW ADC Range
28 | int cwAdcSTFrom = 0;
29 | int cwAdcSTTo = 50;
30 | int cwAdcBothFrom = 51;
31 | int cwAdcBothTo = 300;
32 | int cwAdcDotFrom = 301;
33 | int cwAdcDotTo = 600;
34 | int cwAdcDashFrom = 601;
35 | int cwAdcDashTo = 800;
36 | //byte cwKeyType = 0; //0: straight, 1 : iambica, 2: iambicb
37 |
38 | byte delayBeforeCWStartTime = 50;
39 |
40 |
41 |
42 |
43 | // in milliseconds, this is the parameter that determines how long the tx will hold between cw key downs
44 | //#define CW_TIMEOUT (600l) //Change to CW Delaytime for value save to eeprom
45 | #define PADDLE_DOT 1
46 | #define PADDLE_DASH 2
47 | #define PADDLE_BOTH 3
48 | #define PADDLE_STRAIGHT 4
49 |
50 | //we store the last padde's character
51 | //to alternatively send dots and dashes
52 | //when both are simultaneously pressed
53 | char lastPaddle = 0;
54 |
55 | //reads the analog keyer pin and reports the paddle
56 | byte getPaddle(){
57 | int paddle = analogRead(ANALOG_KEYER);
58 |
59 | if (paddle > 800) // above 4v is up
60 | return 0;
61 |
62 | if (paddle > 600) // 4-3v is dot
63 | return PADDLE_DASH;
64 | else if (paddle > 300) //1-2v is dash
65 | return PADDLE_DOT;
66 | else if (paddle > 50)
67 | return PADDLE_BOTH; //both are between 1 and 2v
68 | else
69 | return PADDLE_STRAIGHT; //less than 1v is the straight key
70 | }
71 |
72 | /**
73 | * Starts transmitting the carrier with the sidetone
74 | * It assumes that we have called cwTxStart and not called cwTxStop
75 | * each time it is called, the cwTimeOut is pushed further into the future
76 | */
77 | void cwKeydown(){
78 | keyDown = 1; //tracks the CW_KEY
79 | tone(CW_TONE, (int)sideTone);
80 | digitalWrite(CW_KEY, 1);
81 |
82 | //Modified by KD8CEC, for CW Delay Time save to eeprom
83 | //cwTimeout = millis() + CW_TIMEOUT;
84 | cwTimeout = millis() + cwDelayTime * 10;
85 | }
86 |
87 | /**
88 | * Stops the cw carrier transmission along with the sidetone
89 | * Pushes the cwTimeout further into the future
90 | */
91 | void cwKeyUp(){
92 | keyDown = 0; //tracks the CW_KEY
93 | noTone(CW_TONE);
94 | digitalWrite(CW_KEY, 0);
95 |
96 | //Modified by KD8CEC, for CW Delay Time save to eeprom
97 | //cwTimeout = millis() + CW_TIMEOUT;
98 | cwTimeout = millis() + cwDelayTime * 10;
99 | }
100 |
101 | //Variables for Ron's new logic
102 | #define DIT_L 0x01 // DIT latch
103 | #define DAH_L 0x02 // DAH latch
104 | #define DIT_PROC 0x04 // DIT is being processed
105 | #define PDLSWAP 0x08 // 0 for normal, 1 for swap
106 | #define IAMBICB 0x10 // 0 for Iambic A, 1 for Iambic B
107 | enum KSTYPE {IDLE, CHK_DIT, CHK_DAH, KEYED_PREP, KEYED, INTER_ELEMENT };
108 | static unsigned long ktimer;
109 | unsigned char keyerState = IDLE;
110 |
111 | //Below is a test to reduce the keying error. do not delete lines
112 | //create by KD8CEC for compatible with new CW Logic
113 | char update_PaddleLatch(byte isUpdateKeyState) {
114 | unsigned char tmpKeyerControl = 0;
115 |
116 | int paddle = analogRead(ANALOG_KEYER);
117 | //diagnostic, VU2ESE
118 | //itoa(paddle, b, 10);
119 | //printLine2(b);
120 |
121 | if (paddle >= cwAdcDashFrom && paddle <= cwAdcDashTo)
122 | tmpKeyerControl |= DAH_L;
123 | else if (paddle >= cwAdcDotFrom && paddle <= cwAdcDotTo)
124 | tmpKeyerControl |= DIT_L;
125 | else if (paddle >= cwAdcBothFrom && paddle <= cwAdcBothTo)
126 | tmpKeyerControl |= (DAH_L | DIT_L) ;
127 | else
128 | {
129 | if (Iambic_Key)
130 | tmpKeyerControl = 0 ;
131 | else if (paddle >= cwAdcSTFrom && paddle <= cwAdcSTTo)
132 | tmpKeyerControl = DIT_L ;
133 | else
134 | tmpKeyerControl = 0 ;
135 | }
136 |
137 | if (isUpdateKeyState == 1)
138 | keyerControl |= tmpKeyerControl;
139 |
140 | return tmpKeyerControl;
141 | }
142 |
143 | /*****************************************************************************
144 | // New logic, by RON
145 | // modified by KD8CEC
146 | ******************************************************************************/
147 | void cwKeyer(void){
148 | lastPaddle = 0;
149 | bool continue_loop = true;
150 | unsigned tmpKeyControl = 0;
151 |
152 | if( Iambic_Key ) {
153 | while(continue_loop) {
154 | switch (keyerState) {
155 | case IDLE:
156 | tmpKeyControl = update_PaddleLatch(0);
157 | if ( tmpKeyControl == DAH_L || tmpKeyControl == DIT_L ||
158 | tmpKeyControl == (DAH_L | DIT_L) || (keyerControl & 0x03)) {
159 | update_PaddleLatch(1);
160 | keyerState = CHK_DIT;
161 | }else{
162 | if (0 < cwTimeout && cwTimeout < millis()){
163 | cwTimeout = 0;
164 | stopTx();
165 | }
166 | continue_loop = false;
167 | }
168 | break;
169 |
170 | case CHK_DIT:
171 | if (keyerControl & DIT_L) {
172 | keyerControl |= DIT_PROC;
173 | ktimer = cwSpeed;
174 | keyerState = KEYED_PREP;
175 | }else{
176 | keyerState = CHK_DAH;
177 | }
178 | break;
179 |
180 | case CHK_DAH:
181 | if (keyerControl & DAH_L) {
182 | ktimer = cwSpeed*3;
183 | keyerState = KEYED_PREP;
184 | }else{
185 | keyerState = IDLE;
186 | }
187 | break;
188 |
189 | case KEYED_PREP:
190 | //modified KD8CEC
191 | if (!inTx){
192 | //DelayTime Option
193 | active_delay(delayBeforeCWStartTime * 2);
194 |
195 | keyDown = 0;
196 | cwTimeout = millis() + cwDelayTime * 10; //+ CW_TIMEOUT;
197 | startTx(TX_CW);
198 | }
199 | ktimer += millis(); // set ktimer to interval end time
200 | keyerControl &= ~(DIT_L + DAH_L); // clear both paddle latch bits
201 | keyerState = KEYED; // next state
202 |
203 | cwKeydown();
204 | break;
205 |
206 | case KEYED:
207 | if (millis() > ktimer) { // are we at end of key down ?
208 | cwKeyUp();
209 | ktimer = millis() + cwSpeed; // inter-element time
210 | keyerState = INTER_ELEMENT; // next state
211 | }else if (keyerControl & IAMBICB) {
212 | update_PaddleLatch(1); // early paddle latch in Iambic B mode
213 | }
214 | break;
215 |
216 | case INTER_ELEMENT:
217 | // Insert time between dits/dahs
218 | update_PaddleLatch(1); // latch paddle state
219 | if (millis() > ktimer) { // are we at end of inter-space ?
220 | if (keyerControl & DIT_PROC) { // was it a dit or dah ?
221 | keyerControl &= ~(DIT_L + DIT_PROC); // clear two bits
222 | keyerState = CHK_DAH; // dit done, check for dah
223 | }else{
224 | keyerControl &= ~(DAH_L); // clear dah latch
225 | keyerState = IDLE; // go idle
226 | }
227 | }
228 | break;
229 | }
230 |
231 | checkCAT();
232 | } //end of while
233 | }
234 | else{
235 | while(1){
236 | if (update_PaddleLatch(0) == DIT_L) {
237 | // if we are here, it is only because the key is pressed
238 | if (!inTx){
239 | //DelayTime Option
240 | active_delay(delayBeforeCWStartTime * 2);
241 |
242 | keyDown = 0;
243 | cwTimeout = millis() + cwDelayTime * 10; //+ CW_TIMEOUT;
244 | startTx(TX_CW);
245 | }
246 | cwKeydown();
247 |
248 | while ( update_PaddleLatch(0) == DIT_L )
249 | active_delay(1);
250 |
251 | cwKeyUp();
252 | }
253 | else{
254 | if (0 < cwTimeout && cwTimeout < millis()){
255 | cwTimeout = 0;
256 | keyDown = 0;
257 | stopTx();
258 | }
259 | //if (!cwTimeout) //removed by KD8CEC
260 | // return;
261 | // got back to the beginning of the loop, if no further activity happens on straight key
262 | // we will time out, and return out of this routine
263 | //delay(5);
264 | //delay_background(5, 3); //removed by KD8CEC
265 | //continue; //removed by KD8CEC
266 | return; //Tx stop control by Main Loop
267 | }
268 |
269 | checkCAT();
270 | } //end of while
271 | } //end of elese
272 | }
273 |
274 |
275 |
--------------------------------------------------------------------------------
/ubitx_menu.ino:
--------------------------------------------------------------------------------
1 | /** Menus
2 | * The Radio menus are accessed by tapping on the function button.
3 | * - The main loop() constantly looks for a button press and calls doMenu() when it detects
4 | * a function button press.
5 | * - As the encoder is rotated, at every 10th pulse, the next or the previous menu
6 | * item is displayed. Each menu item is controlled by it's own function.
7 | * - Eache menu function may be called to display itself
8 | * - Each of these menu routines is called with a button parameter.
9 | * - The btn flag denotes if the menu itme was clicked on or not.
10 | * - If the menu item is clicked on, then it is selected,
11 | * - If the menu item is NOT clicked on, then the menu's prompt is to be displayed
12 | */
13 |
14 |
15 | /** A generic control to read variable values
16 | */
17 | int getValueByKnob(int minimum, int maximum, int step_size, int initial, char* prefix, char *postfix)
18 | {
19 | int knob = 0;
20 | int knob_value;
21 |
22 | while (btnDown())
23 | active_delay(100);
24 |
25 | active_delay(200);
26 | knob_value = initial;
27 |
28 | strcpy(b, prefix);
29 | itoa(knob_value, c, 10);
30 | strcat(b, c);
31 | strcat(b, postfix);
32 | printLine2(b);
33 | active_delay(300);
34 |
35 | while(!btnDown() && digitalRead(PTT) == HIGH){
36 |
37 | knob = enc_read();
38 | if (knob != 0){
39 | if (knob_value > minimum && knob < 0)
40 | knob_value -= step_size;
41 | if (knob_value < maximum && knob > 0)
42 | knob_value += step_size;
43 |
44 | printLine2(prefix);
45 | itoa(knob_value, c, 10);
46 | strcpy(b, c);
47 | strcat(b, postfix);
48 | printLine1(b);
49 | }
50 | checkCAT();
51 | }
52 |
53 | return knob_value;
54 | }
55 |
56 | //# Menu: 1
57 |
58 | int menuBand(int btn){
59 | int knob = 0;
60 | int band;
61 | unsigned long offset;
62 |
63 | // band = frequency/1000000l;
64 | // offset = frequency % 1000000l;
65 |
66 | if (!btn){
67 | printLine2("Band Select \x7E");
68 | return;
69 | }
70 |
71 | printLine2("Band Select:");
72 | //wait for the button menu select button to be lifted)
73 | while (btnDown())
74 | active_delay(50);
75 | active_delay(50);
76 | ritDisable();
77 |
78 | while(!btnDown()){
79 |
80 | knob = enc_read();
81 | if (knob != 0){
82 | /*
83 | if (band > 3 && knob < 0)
84 | band--;
85 | if (band < 30 && knob > 0)
86 | band++;
87 | if (band > 10)
88 | isUSB = true;
89 | else
90 | isUSB = false;
91 | setFrequency(((unsigned long)band * 1000000l) + offset); */
92 | if (knob < 0 && frequency > 3000000l)
93 | setFrequency(frequency - 200000l);
94 | if (knob > 0 && frequency < 30000000l)
95 | setFrequency(frequency + 200000l);
96 | if (frequency > 10000000l)
97 | isUSB = true;
98 | else
99 | isUSB = false;
100 | updateDisplay();
101 | }
102 | checkCAT();
103 | active_delay(20);
104 | }
105 |
106 | while(btnDown())
107 | active_delay(50);
108 | active_delay(50);
109 |
110 | printLine2("");
111 | updateDisplay();
112 | menuOn = 0;
113 | }
114 |
115 | // Menu #2
116 | void menuRitToggle(int btn){
117 | if (!btn){
118 | if (ritOn == 1)
119 | printLine2("RIT On \x7E Off");
120 | else
121 | printLine2("RIT Off \x7E On");
122 | }
123 | else {
124 | if (ritOn == 0){
125 | //enable RIT so the current frequency is used at transmit
126 | ritEnable(frequency);
127 | printLine2("RIT is On");
128 |
129 | }
130 | else{
131 | ritDisable();
132 | printLine2("RIT is Off");
133 | }
134 | menuOn = 0;
135 | active_delay(500);
136 | printLine2("");
137 | updateDisplay();
138 | }
139 | }
140 |
141 |
142 | //Menu #3
143 | void menuVfoToggle(int btn){
144 |
145 | if (!btn){
146 | if (vfoActive == VFO_A)
147 | printLine2("VFO A \x7E B");
148 | else
149 | printLine2("VFO B \x7E A");
150 | }
151 | else {
152 | if (vfoActive == VFO_B){
153 | vfoB = frequency;
154 | isUsbVfoB = isUSB;
155 | EEPROM.put(VFO_B, frequency);
156 | if (isUsbVfoB)
157 | EEPROM.put(VFO_B_MODE, VFO_MODE_USB);
158 | else
159 | EEPROM.put(VFO_B_MODE, VFO_MODE_LSB);
160 |
161 | vfoActive = VFO_A;
162 | // printLine2("Selected VFO A ");
163 | frequency = vfoA;
164 | isUSB = isUsbVfoA;
165 | }
166 | else {
167 | vfoA = frequency;
168 | isUsbVfoA = isUSB;
169 | EEPROM.put(VFO_A, frequency);
170 | if (isUsbVfoA)
171 | EEPROM.put(VFO_A_MODE, VFO_MODE_USB);
172 | else
173 | EEPROM.put(VFO_A_MODE, VFO_MODE_LSB);
174 |
175 | vfoActive = VFO_B;
176 | // printLine2("Selected VFO B ");
177 | frequency = vfoB;
178 | isUSB = isUsbVfoB;
179 | }
180 |
181 | ritDisable();
182 | setFrequency(frequency);
183 | updateDisplay();
184 | printLine2("");
185 | //exit the menu
186 | menuOn = 0;
187 | }
188 | }
189 |
190 | // Menu #4
191 | void menuSidebandToggle(int btn){
192 | if (!btn){
193 | if (isUSB == true)
194 | printLine2("USB \x7E LSB");
195 | else
196 | printLine2("LSB \x7E USB");
197 | }
198 | else {
199 | if (isUSB == true){
200 | isUSB = false;
201 | printLine2("LSB Selected");
202 | active_delay(500);
203 | printLine2("");
204 | }
205 | else {
206 | isUSB = true;
207 | printLine2("USB Selected");
208 | active_delay(500);
209 | printLine2("");
210 | }
211 | //Added by KD8CEC
212 | if (vfoActive == VFO_B){
213 | isUsbVfoB = isUSB;
214 | }
215 | else {
216 | isUsbVfoB = isUSB;
217 | }
218 | updateDisplay();
219 | menuOn = 0;
220 | }
221 | }
222 |
223 | //Split communication using VFOA and VFOB by KD8CEC
224 | //Menu #5
225 | void menuSplitToggle(int btn){
226 | if (!btn){
227 | if (splitOn == 0)
228 | printLine2("Split Off \x7E On");
229 | else
230 | printLine2("Split On \x7E Off");
231 | }
232 | else {
233 | if (splitOn == 1){
234 | splitOn = 0;
235 | printLine2("Split ON");
236 | }
237 | else {
238 | splitOn = 1;
239 | if (ritOn == 1)
240 | ritOn = 0;
241 | printLine2("Split Off");
242 | }
243 | active_delay(500);
244 | printLine2("");
245 | updateDisplay();
246 | menuOn = 0;
247 | }
248 | }
249 |
250 | int menuCWSpeed(int btn){
251 | int knob = 0;
252 | int wpm;
253 |
254 | wpm = 1200/cwSpeed;
255 |
256 | if (!btn){
257 | strcpy(b, "CW: ");
258 | itoa(wpm,c, 10);
259 | strcat(b, c);
260 | strcat(b, " WPM \x7E");
261 | printLine2(b);
262 | return;
263 | }
264 |
265 | /*
266 | printLine1("Press FN to Set");
267 | strcpy(b, "5:CW>");
268 | itoa(wpm,c, 10);
269 | strcat(b, c);
270 | strcat(b, " WPM");
271 | printLine2(b);
272 | active_delay(300);
273 |
274 | while(!btnDown() && digitalRead(PTT) == HIGH){
275 |
276 | knob = enc_read();
277 | if (knob != 0){
278 | if (wpm > 3 && knob < 0)
279 | wpm--;
280 | if (wpm < 50 && knob > 0)
281 | wpm++;
282 |
283 | strcpy(b, "5:CW>");
284 | itoa(wpm,c, 10);
285 | strcat(b, c);
286 | strcat(b, " WPM");
287 | printLine2(b);
288 | }
289 | //abort if this button is down
290 | if (btnDown())
291 | //re-enable the clock1 and clock 2
292 | break;
293 | checkCAT();
294 | }
295 | */
296 | wpm = getValueByKnob(1, 100, 1, wpm, "CW: ", " WPM>");
297 |
298 | printLine2("CW Speed set!");
299 | cwSpeed = 1200/wpm;
300 | EEPROM.put(CW_SPEED, cwSpeed);
301 | active_delay(500);
302 |
303 | printLine2("");
304 | updateDisplay();
305 | menuOn = 0;
306 | }
307 |
308 | void menuExit(int btn){
309 |
310 | if (!btn){
311 | printLine2("Exit Menu \x7E");
312 | }
313 | else{
314 | printLine2("Exiting...");
315 | active_delay(500);
316 | printLine2("");
317 | updateDisplay();
318 | menuOn = 0;
319 | }
320 | }
321 |
322 | /**
323 | * The calibration routines are not normally shown in the menu as they are rarely used
324 | * They can be enabled by choosing this menu option
325 | */
326 | int menuSetup(int btn){
327 | if (!btn){
328 | if (!modeCalibrate)
329 | printLine2("Settings \x7E");
330 | else
331 | printLine2("Settings \x7E Off");
332 | }else {
333 | if (!modeCalibrate){
334 | modeCalibrate = true;
335 | printLine2("Settings On");
336 | }
337 | else {
338 | modeCalibrate = false;
339 | printLine2("Settings Off");
340 | }
341 |
342 | while(btnDown())
343 | active_delay(100);
344 | active_delay(500);
345 | printLine2("");
346 | return 10;
347 | }
348 | return 0;
349 | }
350 |
351 | //this is used by the si5351 routines in the ubitx_5351 file
352 | extern int32_t calibration;
353 | extern uint32_t si5351bx_vcoa;
354 |
355 | int calibrateClock(){
356 | int knob = 0;
357 | int32_t prev_calibration;
358 |
359 |
360 | //keep clear of any previous button press
361 | while (btnDown())
362 | active_delay(100);
363 | active_delay(100);
364 |
365 | digitalWrite(TX_LPF_A, 0);
366 | digitalWrite(TX_LPF_B, 0);
367 | digitalWrite(TX_LPF_C, 0);
368 |
369 | prev_calibration = calibration;
370 | calibration = 0;
371 |
372 | isUSB = true;
373 |
374 | //turn off the second local oscillator and the bfo
375 | si5351_set_calibration(calibration);
376 | startTx(TX_CW);
377 | si5351bx_setfreq(2, 10000000l);
378 |
379 | strcpy(b, "#1 10 MHz cal:");
380 | ltoa(calibration/8750, c, 10);
381 | strcat(b, c);
382 | printLine2(b);
383 |
384 | while (!btnDown())
385 | {
386 |
387 | if (digitalRead(PTT) == LOW && !keyDown)
388 | cwKeydown();
389 | if (digitalRead(PTT) == HIGH && keyDown)
390 | cwKeyUp();
391 |
392 | knob = enc_read();
393 |
394 | if (knob > 0)
395 | calibration += 875;
396 | else if (knob < 0)
397 | calibration -= 875;
398 | else
399 | continue; //don't update the frequency or the display
400 |
401 | si5351_set_calibration(calibration);
402 | si5351bx_setfreq(2, 10000000l);
403 | strcpy(b, "#1 10 MHz cal:");
404 | ltoa(calibration/8750, c, 10);
405 | strcat(b, c);
406 | printLine2(b);
407 | }
408 |
409 | cwTimeout = 0;
410 | keyDown = 0;
411 | stopTx();
412 |
413 | printLine2("Calibration set!");
414 | EEPROM.put(MASTER_CAL, calibration);
415 | initOscillators();
416 | setFrequency(frequency);
417 | updateDisplay();
418 |
419 | while(btnDown())
420 | active_delay(50);
421 | active_delay(100);
422 | }
423 |
424 | int menuSetupCalibration(int btn){
425 | int knob = 0;
426 | int32_t prev_calibration;
427 |
428 | if (!btn){
429 | printLine2("Setup:Calibrate\x7E");
430 | return 0;
431 | }
432 |
433 | printLine1("Press PTT & tune");
434 | printLine2("to exactly 10 MHz");
435 | active_delay(2000);
436 | calibrateClock();
437 | }
438 |
439 | void printCarrierFreq(unsigned long freq){
440 |
441 | memset(c, 0, sizeof(c));
442 | memset(b, 0, sizeof(b));
443 |
444 | ultoa(freq, b, DEC);
445 |
446 | strncat(c, b, 2);
447 | strcat(c, ".");
448 | strncat(c, &b[2], 3);
449 | strcat(c, ".");
450 | strncat(c, &b[5], 1);
451 | printLine2(c);
452 | }
453 |
454 | void menuSetupCarrier(int btn){
455 | int knob = 0;
456 | unsigned long prevCarrier;
457 |
458 | if (!btn){
459 | printLine2("Setup:BFO \x7E");
460 | return;
461 | }
462 |
463 | prevCarrier = usbCarrier;
464 | printLine1("Tune to best Signal");
465 | printLine2("Press to confirm. ");
466 | active_delay(1000);
467 |
468 | usbCarrier = 11053000l;
469 | si5351bx_setfreq(0, usbCarrier);
470 | printCarrierFreq(usbCarrier);
471 |
472 | //disable all clock 1 and clock 2
473 | while (!btnDown()){
474 | knob = enc_read();
475 |
476 | if (knob > 0)
477 | usbCarrier -= 50;
478 | else if (knob < 0)
479 | usbCarrier += 50;
480 | else
481 | continue; //don't update the frequency or the display
482 |
483 | si5351bx_setfreq(0, usbCarrier);
484 | printCarrierFreq(usbCarrier);
485 |
486 | active_delay(100);
487 | }
488 |
489 | printLine2("Carrier set! ");
490 | EEPROM.put(USB_CAL, usbCarrier);
491 | active_delay(1000);
492 |
493 | si5351bx_setfreq(0, usbCarrier);
494 | setFrequency(frequency);
495 | updateDisplay();
496 | printLine2("");
497 | menuOn = 0;
498 | }
499 |
500 | void menuSetupCwTone(int btn){
501 | int knob = 0;
502 | int prev_sideTone;
503 |
504 | if (!btn){
505 | printLine2("Setup:CW Tone \x7E");
506 | return;
507 | }
508 |
509 | prev_sideTone = sideTone;
510 | printLine1("Tune CW tone");
511 | printLine2("PTT to confirm. ");
512 | active_delay(1000);
513 | tone(CW_TONE, sideTone);
514 |
515 | //disable all clock 1 and clock 2
516 | while (digitalRead(PTT) == HIGH && !btnDown())
517 | {
518 | knob = enc_read();
519 |
520 | if (knob > 0 && sideTone < 2000)
521 | sideTone += 10;
522 | else if (knob < 0 && sideTone > 100 )
523 | sideTone -= 10;
524 | else
525 | continue; //don't update the frequency or the display
526 |
527 | tone(CW_TONE, sideTone);
528 | itoa(sideTone, b, 10);
529 | printLine2(b);
530 |
531 | checkCAT();
532 | active_delay(20);
533 | }
534 | noTone(CW_TONE);
535 | //save the setting
536 | if (digitalRead(PTT) == LOW){
537 | printLine2("Sidetone set! ");
538 | EEPROM.put(CW_SIDETONE, sideTone);
539 | active_delay(2000);
540 | }
541 | else
542 | sideTone = prev_sideTone;
543 |
544 | printLine2("");
545 | updateDisplay();
546 | menuOn = 0;
547 | }
548 |
549 | void menuSetupCwDelay(int btn){
550 | int knob = 0;
551 | int prev_cw_delay;
552 |
553 | if (!btn){
554 | printLine2("Setup:CW Delay \x7E");
555 | return;
556 | }
557 |
558 | active_delay(500);
559 | prev_cw_delay = cwDelayTime;
560 | cwDelayTime = getValueByKnob(10, 1000, 50, cwDelayTime, "CW Delay>", " msec");
561 |
562 | printLine1("CW Delay Set!");
563 | printLine2("");
564 | active_delay(500);
565 | updateDisplay();
566 | menuOn = 0;
567 | }
568 |
569 | void menuSetupKeyer(int btn){
570 | int tmp_key, knob;
571 |
572 | if (!btn){
573 | if (!Iambic_Key)
574 | printLine2("Setup:CW(Hand)\x7E");
575 | else if (keyerControl & IAMBICB)
576 | printLine2("Setup:CW(IambA)\x7E");
577 | else
578 | printLine2("Setup:CW(IambB)\x7E");
579 | return;
580 | }
581 |
582 | active_delay(500);
583 |
584 | if (!Iambic_Key)
585 | tmp_key = 0; //hand key
586 | else if (keyerControl & IAMBICB)
587 | tmp_key = 2; //Iambic B
588 | else
589 | tmp_key = 1;
590 |
591 | while (!btnDown())
592 | {
593 | knob = enc_read();
594 | if (knob < 0 && tmp_key > 0)
595 | tmp_key--;
596 | if (knob > 0)
597 | tmp_key++;
598 |
599 | if (tmp_key > 2)
600 | tmp_key = 0;
601 |
602 | if (tmp_key == 0)
603 | printLine1("Hand Key?");
604 | else if (tmp_key == 1)
605 | printLine1("Iambic A?");
606 | else if (tmp_key == 2)
607 | printLine1("Iambic B?");
608 | }
609 |
610 | active_delay(500);
611 | if (tmp_key == 0)
612 | Iambic_Key = false;
613 | else if (tmp_key == 1){
614 | Iambic_Key = true;
615 | keyerControl &= ~IAMBICB;
616 | }
617 | else if (tmp_key == 2){
618 | Iambic_Key = true;
619 | keyerControl |= IAMBICB;
620 | }
621 |
622 | EEPROM.put(CW_KEY_TYPE, tmp_key);
623 |
624 | printLine1("Keyer Set!");
625 | active_delay(600);
626 | printLine1("");
627 |
628 | //Added KD8CEC
629 | printLine2("");
630 | updateDisplay();
631 | menuOn = 0;
632 | }
633 |
634 | void menuReadADC(int btn){
635 | int adc;
636 |
637 | if (!btn){
638 | printLine2("6:Setup>Read ADC>");
639 | return;
640 | }
641 | delay(500);
642 |
643 | while (!btnDown()){
644 | adc = analogRead(ANALOG_KEYER);
645 | itoa(adc, b, 10);
646 | printLine1(b);
647 | }
648 |
649 | printLine1("");
650 | updateDisplay();
651 | }
652 |
653 | void doMenu(){
654 | int select=0, i,btnState;
655 |
656 | //wait for the button to be raised up
657 | while(btnDown())
658 | active_delay(50);
659 | active_delay(50); //debounce
660 |
661 | menuOn = 2;
662 |
663 | while (menuOn){
664 | i = enc_read();
665 | btnState = btnDown();
666 |
667 | if (i > 0){
668 | if (modeCalibrate && select + i < 150)
669 | select += i;
670 | if (!modeCalibrate && select + i < 80)
671 | select += i;
672 | }
673 | if (i < 0 && select - i >= 0)
674 | select += i; //caught ya, i is already -ve here, so you add it
675 |
676 | if (select < 10)
677 | menuBand(btnState);
678 | else if (select < 20)
679 | menuRitToggle(btnState);
680 | else if (select < 30)
681 | menuVfoToggle(btnState);
682 | else if (select < 40)
683 | menuSidebandToggle(btnState);
684 | else if (select < 50)
685 | menuSplitToggle(btnState);
686 | else if (select < 60)
687 | menuCWSpeed(btnState);
688 | else if (select < 70)
689 | select += menuSetup(btnState);
690 | else if (select < 80 && !modeCalibrate)
691 | menuExit(btnState);
692 | else if (select < 90 && modeCalibrate)
693 | menuSetupCalibration(btnState); //crystal
694 | else if (select < 100 && modeCalibrate)
695 | menuSetupCarrier(btnState); //lsb
696 | else if (select < 110 && modeCalibrate)
697 | menuSetupCwTone(btnState);
698 | else if (select < 120 && modeCalibrate)
699 | menuSetupCwDelay(btnState);
700 | else if (select < 130 && modeCalibrate)
701 | menuReadADC(btnState);
702 | else if (select < 140 && modeCalibrate)
703 | menuSetupKeyer(btnState);
704 | else
705 | menuExit(btnState);
706 | }
707 |
708 | //debounce the button
709 | while(btnDown())
710 | active_delay(50);
711 | active_delay(50);
712 |
713 | checkCAT();
714 | }
715 |
716 |
--------------------------------------------------------------------------------
/ubitx_si5351.ino:
--------------------------------------------------------------------------------
1 | // ************* SI5315 routines - tks Jerry Gaffke, KE7ER ***********************
2 |
3 | // An minimalist standalone set of Si5351 routines.
4 | // VCOA is fixed at 875mhz, VCOB not used.
5 | // The output msynth dividers are used to generate 3 independent clocks
6 | // with 1hz resolution to any frequency between 4khz and 109mhz.
7 |
8 | // Usage:
9 | // Call si5351bx_init() once at startup with no args;
10 | // Call si5351bx_setfreq(clknum, freq) each time one of the
11 | // three output CLK pins is to be updated to a new frequency.
12 | // A freq of 0 serves to shut down that output clock.
13 |
14 | // The global variable si5351bx_vcoa starts out equal to the nominal VCOA
15 | // frequency of 25mhz*35 = 875000000 Hz. To correct for 25mhz crystal errors,
16 | // the user can adjust this value. The vco frequency will not change but
17 | // the number used for the (a+b/c) output msynth calculations is affected.
18 | // Example: We call for a 5mhz signal, but it measures to be 5.001mhz.
19 | // So the actual vcoa frequency is 875mhz*5.001/5.000 = 875175000 Hz,
20 | // To correct for this error: si5351bx_vcoa=875175000;
21 |
22 | // Most users will never need to generate clocks below 500khz.
23 | // But it is possible to do so by loading a value between 0 and 7 into
24 | // the global variable si5351bx_rdiv, be sure to return it to a value of 0
25 | // before setting some other CLK output pin. The affected clock will be
26 | // divided down by a power of two defined by 2**si5351_rdiv
27 | // A value of zero gives a divide factor of 1, a value of 7 divides by 128.
28 | // This lightweight method is a reasonable compromise for a seldom used feature.
29 |
30 |
31 | #define BB0(x) ((uint8_t)x) // Bust int32 into Bytes
32 | #define BB1(x) ((uint8_t)(x>>8))
33 | #define BB2(x) ((uint8_t)(x>>16))
34 |
35 | #define SI5351BX_ADDR 0x60 // I2C address of Si5351 (typical)
36 | #define SI5351BX_XTALPF 2 // 1:6pf 2:8pf 3:10pf
37 |
38 | // If using 27mhz crystal, set XTAL=27000000, MSA=33. Then vco=891mhz
39 | #define SI5351BX_XTAL 25000000 // Crystal freq in Hz
40 | #define SI5351BX_MSA 35 // VCOA is at 25mhz*35 = 875mhz
41 |
42 | // User program may have reason to poke new values into these 3 RAM variables
43 | uint32_t si5351bx_vcoa = (SI5351BX_XTAL*SI5351BX_MSA); // 25mhzXtal calibrate
44 | uint8_t si5351bx_rdiv = 0; // 0-7, CLK pin sees fout/(2**rdiv)
45 | uint8_t si5351bx_drive[3] = {3, 3, 3}; // 0=2ma 1=4ma 2=6ma 3=8ma for CLK 0,1,2
46 | uint8_t si5351bx_clken = 0xFF; // Private, all CLK output drivers off
47 | int32_t calibration = 0;
48 |
49 | void i2cWrite(uint8_t reg, uint8_t val) { // write reg via i2c
50 | Wire.beginTransmission(SI5351BX_ADDR);
51 | Wire.write(reg);
52 | Wire.write(val);
53 | Wire.endTransmission();
54 | }
55 |
56 | void i2cWriten(uint8_t reg, uint8_t *vals, uint8_t vcnt) { // write array
57 | Wire.beginTransmission(SI5351BX_ADDR);
58 | Wire.write(reg);
59 | while (vcnt--) Wire.write(*vals++);
60 | Wire.endTransmission();
61 | }
62 |
63 |
64 | void si5351bx_init() { // Call once at power-up, start PLLA
65 | uint8_t reg; uint32_t msxp1;
66 | Wire.begin();
67 | i2cWrite(149, 0); // SpreadSpectrum off
68 | i2cWrite(3, si5351bx_clken); // Disable all CLK output drivers
69 | i2cWrite(183, SI5351BX_XTALPF << 6); // Set 25mhz crystal load capacitance
70 | msxp1 = 128 * SI5351BX_MSA - 512; // and msxp2=0, msxp3=1, not fractional
71 | uint8_t vals[8] = {0, 1, BB2(msxp1), BB1(msxp1), BB0(msxp1), 0, 0, 0};
72 | i2cWriten(26, vals, 8); // Write to 8 PLLA msynth regs
73 | i2cWrite(177, 0x20); // Reset PLLA (0x80 resets PLLB)
74 | // for (reg=16; reg<=23; reg++) i2cWrite(reg, 0x80); // Powerdown CLK's
75 | // i2cWrite(187, 0); // No fannout of clkin, xtal, ms0, ms4
76 |
77 | //initializing the ppl2 as well
78 | i2cWriten(34, vals, 8); // Write to 8 PLLA msynth regs
79 | i2cWrite(177, 0xa0); // Reset PLLA & PPLB (0x80 resets PLLB)
80 |
81 | }
82 |
83 | void si5351bx_setfreq(uint8_t clknum, uint32_t fout) { // Set a CLK to fout Hz
84 | uint32_t msa, msb, msc, msxp1, msxp2, msxp3p2top;
85 | if ((fout < 500000) || (fout > 109000000)) // If clock freq out of range
86 | si5351bx_clken |= 1 << clknum; // shut down the clock
87 | else {
88 | msa = si5351bx_vcoa / fout; // Integer part of vco/fout
89 | msb = si5351bx_vcoa % fout; // Fractional part of vco/fout
90 | msc = fout; // Divide by 2 till fits in reg
91 | while (msc & 0xfff00000) {
92 | msb = msb >> 1;
93 | msc = msc >> 1;
94 | }
95 | msxp1 = (128 * msa + 128 * msb / msc - 512) | (((uint32_t)si5351bx_rdiv) << 20);
96 | msxp2 = 128 * msb - 128 * msb / msc * msc; // msxp3 == msc;
97 | msxp3p2top = (((msc & 0x0F0000) << 4) | msxp2); // 2 top nibbles
98 | uint8_t vals[8] = { BB1(msc), BB0(msc), BB2(msxp1), BB1(msxp1),
99 | BB0(msxp1), BB2(msxp3p2top), BB1(msxp2), BB0(msxp2)
100 | };
101 | i2cWriten(42 + (clknum * 8), vals, 8); // Write to 8 msynth regs
102 | // if (clknum == 1) //PLLB | MS src | drive current
103 | // i2cWrite(16 + clknum, 0x20 | 0x0C | si5351bx_drive[clknum]); // use local msynth
104 | // else
105 | i2cWrite(16 + clknum, 0x0C | si5351bx_drive[clknum]); // use local msynth
106 |
107 | si5351bx_clken &= ~(1 << clknum); // Clear bit to enable clock
108 | }
109 | i2cWrite(3, si5351bx_clken); // Enable/disable clock
110 | }
111 |
112 | void si5351_set_calibration(int32_t cal){
113 | si5351bx_vcoa = (SI5351BX_XTAL * SI5351BX_MSA) + cal; // apply the calibration correction factor
114 | si5351bx_setfreq(0, usbCarrier);
115 | }
116 |
117 | void initOscillators(){
118 | //initialize the SI5351
119 | si5351bx_init();
120 | si5351bx_vcoa = (SI5351BX_XTAL * SI5351BX_MSA) + calibration; // apply the calibration correction factor
121 | si5351bx_setfreq(0, usbCarrier);
122 | }
123 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/ubitx_ui.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * The user interface of the ubitx consists of the encoder, the push-button on top of it
3 | * and the 16x2 LCD display.
4 | * The upper line of the display is constantly used to display frequency and status
5 | * of the radio. Occasionally, it is used to provide a two-line information that is
6 | * quickly cleared up.
7 | */
8 |
9 | //returns true if the button is pressed
10 | int btnDown(){
11 | if (digitalRead(FBUTTON) == HIGH)
12 | return 0;
13 | else
14 | return 1;
15 | }
16 |
17 | /**
18 | * Meter (not used in this build for anything)
19 | * the meter is drawn using special characters. Each character is composed of 5 x 8 matrix.
20 | * The s_meter array holds the definition of the these characters.
21 | * each line of the array is is one character such that 5 bits of every byte
22 | * makes up one line of pixels of the that character (only 5 bits are used)
23 | * The current reading of the meter is assembled in the string called meter
24 | */
25 |
26 |
27 | char meter[17];
28 |
29 | const byte PROGMEM s_meter_bitmap[] = {
30 | B00000,B00000,B00000,B00000,B00000,B00100,B00100,B11011,
31 | B10000,B10000,B10000,B10000,B10100,B10100,B10100,B11011,
32 | B01000,B01000,B01000,B01000,B01100,B01100,B01100,B11011,
33 | B00100,B00100,B00100,B00100,B00100,B00100,B00100,B11011,
34 | B00010,B00010,B00010,B00010,B00110,B00110,B00110,B11011,
35 | B00001,B00001,B00001,B00001,B00101,B00101,B00101,B11011,
36 | B10000,B11000,B11100,B11110,B11100,B11000,B10000,B00000,
37 | B00001,B00011,B00111,B01111,B00111,B00011,B00001,B00000
38 | };
39 |
40 |
41 |
42 | // initializes the custom characters
43 | // we start from char 1 as char 0 terminates the string!
44 | void initMeter(){
45 | lcd.createChar(1, s_meter_bitmap);
46 | lcd.createChar(2, s_meter_bitmap + 8);
47 | lcd.createChar(3, s_meter_bitmap + 16);
48 | lcd.createChar(4, s_meter_bitmap + 24);
49 | lcd.createChar(5, s_meter_bitmap + 32);
50 | lcd.createChar(6, s_meter_bitmap + 40);
51 | lcd.createChar(0, s_meter_bitmap + 48);
52 | lcd.createChar(7, s_meter_bitmap + 56);
53 | }
54 |
55 |
56 | /**
57 | * The meter is drawn with special characters.
58 | * character 1 is used to simple draw the blocks of the scale of the meter
59 | * characters 2 to 6 are used to draw the needle in positions 1 to within the block
60 | * This displays a meter from 0 to 100, -1 displays nothing
61 | */
62 |
63 | void drawMeter(int8_t needle){
64 | int16_t best, i, s;
65 |
66 | if (needle < 0)
67 | return;
68 |
69 | s = (needle * 4)/10;
70 | for (i = 0; i < 8; i++){
71 | if (s >= 5)
72 | meter[i] = 1;
73 | else if (s >= 0)
74 | meter[i] = 2 + s;
75 | else
76 | meter[i] = 1;
77 | s = s - 5;
78 | }
79 | if (needle >= 40)
80 | meter[i-1] = 6;
81 | meter[i] = 0;
82 | }
83 |
84 | // The generic routine to display one line on the LCD
85 | void printLine(char linenmbr, char *c) {
86 | if (strcmp(c, printBuff[linenmbr])) { // only refresh the display when there was a change
87 | lcd.setCursor(0, linenmbr); // place the cursor at the beginning of the selected line
88 | lcd.print(c);
89 | strcpy(printBuff[linenmbr], c);
90 |
91 | for (byte i = strlen(c); i < 16; i++) { // add white spaces until the end of the 16 characters line is reached
92 | lcd.print(' ');
93 | }
94 | }
95 | }
96 |
97 |
98 | // short cut to print to the first line
99 | void printLine1(char *c){
100 | printLine(1,c);
101 | }
102 | // short cut to print to the first line
103 | void printLine2(char *c){
104 | printLine(0,c);
105 | }
106 |
107 | // this builds up the top line of the display with frequency and mode
108 | void updateDisplay() {
109 | // tks Jack Purdum W8TEE
110 | // replaced fsprint commmands by str commands for code size reduction
111 |
112 | memset(c, 0, sizeof(c));
113 | memset(b, 0, sizeof(b));
114 |
115 | ultoa(frequency, b, DEC);
116 |
117 | if (inTx){
118 | if (cwTimeout > 0)
119 | strcpy(c, " CW:");
120 | else
121 | strcpy(c, " TX:");
122 | }
123 | else {
124 | if (ritOn)
125 | strcpy(c, "RIT ");
126 | else {
127 | if (isUSB)
128 | strcpy(c, "USB ");
129 | else
130 | strcpy(c, "LSB ");
131 | }
132 | if (vfoActive == VFO_A) // VFO A is active
133 | strcat(c, "A:");
134 | else
135 | strcat(c, "B:");
136 | }
137 |
138 |
139 |
140 | //one mhz digit if less than 10 M, two digits if more
141 | if (frequency < 10000000l){
142 | c[6] = ' ';
143 | c[7] = b[0];
144 | strcat(c, ".");
145 | strncat(c, &b[1], 3);
146 | strcat(c, ".");
147 | strncat(c, &b[4], 3);
148 | }
149 | else {
150 | strncat(c, b, 2);
151 | strcat(c, ".");
152 | strncat(c, &b[2], 3);
153 | strcat(c, ".");
154 | strncat(c, &b[5], 3);
155 | }
156 |
157 | if (inTx)
158 | strcat(c, " TX");
159 | printLine(1, c);
160 |
161 | /*
162 | //now, the second line
163 | memset(c, 0, sizeof(c));
164 | memset(b, 0, sizeof(b));
165 |
166 | if (inTx)
167 | strcat(c, "TX ");
168 | else if (ritOn)
169 | strcpy(c, "RIT");
170 |
171 | strcpy(c, " \xff");
172 | drawMeter(meter_reading);
173 | strcat(c, meter);
174 | strcat(c, "\xff");
175 | printLine2(c);*/
176 | }
177 |
178 | int enc_prev_state = 3;
179 |
180 | /**
181 | * The A7 And A6 are purely analog lines on the Arduino Nano
182 | * These need to be pulled up externally using two 10 K resistors
183 | *
184 | * There are excellent pages on the Internet about how these encoders work
185 | * and how they should be used. We have elected to use the simplest way
186 | * to use these encoders without the complexity of interrupts etc to
187 | * keep it understandable.
188 | *
189 | * The enc_state returns a two-bit number such that each bit reflects the current
190 | * value of each of the two phases of the encoder
191 | *
192 | * The enc_read returns the number of net pulses counted over 50 msecs.
193 | * If the puluses are -ve, they were anti-clockwise, if they are +ve, the
194 | * were in the clockwise directions. Higher the pulses, greater the speed
195 | * at which the enccoder was spun
196 | */
197 |
198 | byte enc_state (void) {
199 | return (analogRead(ENC_A) > 500 ? 1 : 0) + (analogRead(ENC_B) > 500 ? 2: 0);
200 | }
201 |
202 | int enc_read(void) {
203 | int result = 0;
204 | byte newState;
205 | int enc_speed = 0;
206 |
207 | long stop_by = millis() + 50;
208 |
209 | while (millis() < stop_by) { // check if the previous state was stable
210 | newState = enc_state(); // Get current state
211 |
212 | if (newState != enc_prev_state)
213 | delay (1);
214 |
215 | if (enc_state() != newState || newState == enc_prev_state)
216 | continue;
217 | //these transitions point to the encoder being rotated anti-clockwise
218 | if ((enc_prev_state == 0 && newState == 2) ||
219 | (enc_prev_state == 2 && newState == 3) ||
220 | (enc_prev_state == 3 && newState == 1) ||
221 | (enc_prev_state == 1 && newState == 0)){
222 | result--;
223 | }
224 | //these transitions point o the enccoder being rotated clockwise
225 | if ((enc_prev_state == 0 && newState == 1) ||
226 | (enc_prev_state == 1 && newState == 3) ||
227 | (enc_prev_state == 3 && newState == 2) ||
228 | (enc_prev_state == 2 && newState == 0)){
229 | result++;
230 | }
231 | enc_prev_state = newState; // Record state for next pulse interpretation
232 | enc_speed++;
233 | active_delay(1);
234 | }
235 | return(result);
236 | }
237 |
238 |
239 |
--------------------------------------------------------------------------------
/ubitx_v5.1_code.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * This source file is under General Public License version 3.
3 | *
4 | * This verision uses a built-in Si5351 library
5 | * Most source code are meant to be understood by the compilers and the computers.
6 | * Code that has to be hackable needs to be well understood and properly documented.
7 | * Donald Knuth coined the term Literate Programming to indicate code that is written be
8 | * easily read and understood.
9 | *
10 | * The Raduino is a small board that includes the Arduin Nano, a 16x2 LCD display and
11 | * an Si5351a frequency synthesizer. This board is manufactured by Paradigm Ecomm Pvt Ltd
12 | *
13 | * To learn more about Arduino you may visit www.arduino.cc.
14 | *
15 | * The Arduino works by starts executing the code in a function called setup() and then it
16 | * repeatedly keeps calling loop() forever. All the initialization code is kept in setup()
17 | * and code to continuously sense the tuning knob, the function button, transmit/receive,
18 | * etc is all in the loop() function. If you wish to study the code top down, then scroll
19 | * to the bottom of this file and read your way up.
20 | *
21 | * Below are the libraries to be included for building the Raduino
22 | * The EEPROM library is used to store settings like the frequency memory, caliberation data,
23 | * callsign etc .
24 | *
25 | * The main chip which generates upto three oscillators of various frequencies in the
26 | * Raduino is the Si5351a. To learn more about Si5351a you can download the datasheet
27 | * from www.silabs.com although, strictly speaking it is not a requirment to understand this code.
28 | * Instead, you can look up the Si5351 library written by xxx, yyy. You can download and
29 | * install it from www.url.com to complile this file.
30 | * The Wire.h library is used to talk to the Si5351 and we also declare an instance of
31 | * Si5351 object to control the clocks.
32 | */
33 | #include
34 | #include
35 |
36 | /**
37 | The main chip which generates upto three oscillators of various frequencies in the
38 | Raduino is the Si5351a. To learn more about Si5351a you can download the datasheet
39 | from www.silabs.com although, strictly speaking it is not a requirment to understand this code.
40 |
41 | We no longer use the standard SI5351 library because of its huge overhead due to many unused
42 | features consuming a lot of program space. Instead of depending on an external library we now use
43 | Jerry Gaffke's, KE7ER, lightweight standalone mimimalist "si5351bx" routines (see further down the
44 | code). Here are some defines and declarations used by Jerry's routines:
45 | */
46 |
47 |
48 | /**
49 | * We need to carefully pick assignment of pin for various purposes.
50 | * There are two sets of completely programmable pins on the Raduino.
51 | * First, on the top of the board, in line with the LCD connector is an 8-pin connector
52 | * that is largely meant for analog inputs and front-panel control. It has a regulated 5v output,
53 | * ground and six pins. Each of these six pins can be individually programmed
54 | * either as an analog input, a digital input or a digital output.
55 | * The pins are assigned as follows (left to right, display facing you):
56 | * Pin 1 (Violet), A7, SPARE
57 | * Pin 2 (Blue), A6, KEYER (DATA)
58 | * Pin 3 (Green), +5v
59 | * Pin 4 (Yellow), Gnd
60 | * Pin 5 (Orange), A3, PTT
61 | * Pin 6 (Red), A2, F BUTTON
62 | * Pin 7 (Brown), A1, ENC B
63 | * Pin 8 (Black), A0, ENC A
64 | *Note: A5, A4 are wired to the Si5351 as I2C interface
65 | * *
66 | * Though, this can be assigned anyway, for this application of the Arduino, we will make the following
67 | * assignment
68 | * A2 will connect to the PTT line, which is the usually a part of the mic connector
69 | * A3 is connected to a push button that can momentarily ground this line. This will be used for RIT/Bandswitching, etc.
70 | * A6 is to implement a keyer, it is reserved and not yet implemented
71 | * A7 is connected to a center pin of good quality 100K or 10K linear potentiometer with the two other ends connected to
72 | * ground and +5v lines available on the connector. This implments the tuning mechanism
73 | */
74 |
75 | #define ENC_A (A0)
76 | #define ENC_B (A1)
77 | #define FBUTTON (A2)
78 | #define PTT (A3)
79 | #define ANALOG_KEYER (A6)
80 | #define ANALOG_SPARE (A7)
81 |
82 | /**
83 | * The Raduino board is the size of a standard 16x2 LCD panel. It has three connectors:
84 | *
85 | * First, is an 8 pin connector that provides +5v, GND and six analog input pins that can also be
86 | * configured to be used as digital input or output pins. These are referred to as A0,A1,A2,
87 | * A3,A6 and A7 pins. The A4 and A5 pins are missing from this connector as they are used to
88 | * talk to the Si5351 over I2C protocol.
89 | *
90 | * Second is a 16 pin LCD connector. This connector is meant specifically for the standard 16x2
91 | * LCD display in 4 bit mode. The 4 bit mode requires 4 data lines and two control lines to work:
92 | * Lines used are : RESET, ENABLE, D4, D5, D6, D7
93 | * We include the library and declare the configuration of the LCD panel too
94 | */
95 |
96 | #include
97 | LiquidCrystal lcd(8,9,10,11,12,13);
98 |
99 | /**
100 | * The Arduino, unlike C/C++ on a regular computer with gigabytes of RAM, has very little memory.
101 | * We have to be very careful with variables that are declared inside the functions as they are
102 | * created in a memory region called the stack. The stack has just a few bytes of space on the Arduino
103 | * if you declare large strings inside functions, they can easily exceed the capacity of the stack
104 | * and mess up your programs.
105 | * We circumvent this by declaring a few global buffers as kitchen counters where we can
106 | * slice and dice our strings. These strings are mostly used to control the display or handle
107 | * the input and output from the USB port. We must keep a count of the bytes used while reading
108 | * the serial port as we can easily run out of buffer space. This is done in the serial_in_count variable.
109 | */
110 | char c[30], b[30];
111 | char printBuff[2][31]; //mirrors what is showing on the two lines of the display
112 | int count = 0; //to generally count ticks, loops, etc
113 |
114 | /**
115 | * The second set of 16 pins on the Raduino's bottom connector are have the three clock outputs and the digital lines to control the rig.
116 | * This assignment is as follows :
117 | * Pin 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
118 | * GND +5V CLK0 GND GND CLK1 GND GND CLK2 GND D2 D3 D4 D5 D6 D7
119 | * These too are flexible with what you may do with them, for the Raduino, we use them to :
120 | * - TX_RX line : Switches between Transmit and Receive after sensing the PTT or the morse keyer
121 | * - CW_KEY line : turns on the carrier for CW
122 | */
123 |
124 | #define TX_RX (7)
125 | #define CW_TONE (6)
126 | #define TX_LPF_A (5)
127 | #define TX_LPF_B (4)
128 | #define TX_LPF_C (3)
129 | #define CW_KEY (2)
130 |
131 | /**
132 | * These are the indices where these user changable settinngs are stored in the EEPROM
133 | */
134 | #define MASTER_CAL 0
135 | #define LSB_CAL 4
136 | #define USB_CAL 8
137 | #define SIDE_TONE 12
138 | //these are ids of the vfos as well as their offset into the eeprom storage, don't change these 'magic' values
139 | #define VFO_A 16
140 | #define VFO_B 20
141 | #define CW_SIDETONE 24
142 | #define CW_SPEED 28
143 |
144 | //These are defines for the new features back-ported from KD8CEC's software
145 | //these start from beyond 256 as Ian, KD8CEC has kept the first 256 bytes free for the base version
146 | #define VFO_A_MODE 256 // 2: LSB, 3: USB
147 | #define VFO_B_MODE 257
148 |
149 | //values that are stroed for the VFO modes
150 | #define VFO_MODE_LSB 2
151 | #define VFO_MODE_USB 3
152 |
153 | // handkey, iambic a, iambic b : 0,1,2f
154 | #define CW_KEY_TYPE 358
155 |
156 | /**
157 | * The uBITX is an upconnversion transceiver. The first IF is at 45 MHz.
158 | * The first IF frequency is not exactly at 45 Mhz but about 5 khz lower,
159 | * this shift is due to the loading on the 45 Mhz crystal filter by the matching
160 | * L-network used on it's either sides.
161 | * The first oscillator works between 48 Mhz and 75 MHz. The signal is subtracted
162 | * from the first oscillator to arriive at 45 Mhz IF. Thus, it is inverted : LSB becomes USB
163 | * and USB becomes LSB.
164 | * The second IF of 12 Mhz has a ladder crystal filter. If a second oscillator is used at
165 | * 57 Mhz, the signal is subtracted FROM the oscillator, inverting a second time, and arrives
166 | * at the 12 Mhz ladder filter thus doouble inversion, keeps the sidebands as they originally were.
167 | * If the second oscillator is at 33 Mhz, the oscilaltor is subtracated from the signal,
168 | * thus keeping the signal's sidebands inverted. The USB will become LSB.
169 | * We use this technique to switch sidebands. This is to avoid placing the lsbCarrier close to
170 | * 12 MHz where its fifth harmonic beats with the arduino's 16 Mhz oscillator's fourth harmonic
171 | */
172 |
173 |
174 | #define INIT_USB_FREQ (11059200l)
175 | // limits the tuning and working range of the ubitx between 3 MHz and 30 MHz
176 | #define LOWEST_FREQ (100000l)
177 | #define HIGHEST_FREQ (30000000l)
178 |
179 | //we directly generate the CW by programmin the Si5351 to the cw tx frequency, hence, both are different modes
180 | //these are the parameter passed to startTx
181 | #define TX_SSB 0
182 | #define TX_CW 1
183 |
184 | char ritOn = 0;
185 | char vfoActive = VFO_A;
186 | int8_t meter_reading = 0; // a -1 on meter makes it invisible
187 | unsigned long vfoA=7150000L, vfoB=14200000L, sideTone=800, usbCarrier;
188 | char isUsbVfoA=0, isUsbVfoB=1;
189 | unsigned long frequency, ritRxFrequency, ritTxFrequency; //frequency is the current frequency on the dial
190 | unsigned long firstIF = 45005000L;
191 |
192 | //these are variables that control the keyer behaviour
193 | int cwSpeed = 100; //this is actuall the dot period in milliseconds
194 | extern int32_t calibration;
195 | byte cwDelayTime = 60;
196 | bool Iambic_Key = true;
197 | #define IAMBICB 0x10 // 0 for Iambic A, 1 for Iambic B
198 | unsigned char keyerControl = IAMBICB;
199 |
200 |
201 | /**
202 | * Raduino needs to keep track of current state of the transceiver. These are a few variables that do it
203 | */
204 | boolean txCAT = false; //turned on if the transmitting due to a CAT command
205 | char inTx = 0; //it is set to 1 if in transmit mode (whatever the reason : cw, ptt or cat)
206 | char splitOn = 0; //working split, uses VFO B as the transmit frequency, (NOT IMPLEMENTED YET)
207 | char keyDown = 0; //in cw mode, denotes the carrier is being transmitted
208 | char isUSB = 0; //upper sideband was selected, this is reset to the default for the
209 | //frequency when it crosses the frequency border of 10 MHz
210 | byte menuOn = 0; //set to 1 when the menu is being displayed, if a menu item sets it to zero, the menu is exited
211 | unsigned long cwTimeout = 0; //milliseconds to go before the cw transmit line is released and the radio goes back to rx mode
212 | unsigned long dbgCount = 0; //not used now
213 | unsigned char txFilter = 0; //which of the four transmit filters are in use
214 | boolean modeCalibrate = false;//this mode of menus shows extended menus to calibrate the oscillators and choose the proper
215 | //beat frequency
216 |
217 | /**
218 | * Below are the basic functions that control the uBitx. Understanding the functions before
219 | * you start hacking around
220 | */
221 |
222 | /**
223 | * Our own delay. During any delay, the raduino should still be processing a few times.
224 | */
225 |
226 | void active_delay(int delay_by){
227 | unsigned long timeStart = millis();
228 |
229 | while (millis() - timeStart <= delay_by) {
230 | //Background Work
231 | checkCAT();
232 | }
233 | }
234 |
235 | /**
236 | * Select the properly tx harmonic filters
237 | * The four harmonic filters use only three relays
238 | * the four LPFs cover 30-21 Mhz, 18 - 14 Mhz, 7-10 MHz and 3.5 to 5 Mhz
239 | * Briefly, it works like this,
240 | * - When KT1 is OFF, the 'off' position routes the PA output through the 30 MHz LPF
241 | * - When KT1 is ON, it routes the PA output to KT2. Which is why you will see that
242 | * the KT1 is on for the three other cases.
243 | * - When the KT1 is ON and KT2 is off, the off position of KT2 routes the PA output
244 | * to 18 MHz LPF (That also works for 14 Mhz)
245 | * - When KT1 is On, KT2 is On, it routes the PA output to KT3
246 | * - KT3, when switched on selects the 7-10 Mhz filter
247 | * - KT3 when switched off selects the 3.5-5 Mhz filter
248 | * See the circuit to understand this
249 | */
250 |
251 | void setTXFilters(unsigned long freq){
252 |
253 | if (freq > 21000000L){ // the default filter is with 35 MHz cut-off
254 | digitalWrite(TX_LPF_A, 0);
255 | digitalWrite(TX_LPF_B, 0);
256 | digitalWrite(TX_LPF_C, 0);
257 | }
258 | else if (freq >= 14000000L){ //thrown the KT1 relay on, the 30 MHz LPF is bypassed and the 14-18 MHz LPF is allowd to go through
259 | digitalWrite(TX_LPF_A, 1);
260 | digitalWrite(TX_LPF_B, 0);
261 | digitalWrite(TX_LPF_C, 0);
262 | }
263 | else if (freq > 7000000L){
264 | digitalWrite(TX_LPF_A, 0);
265 | digitalWrite(TX_LPF_B, 1);
266 | digitalWrite(TX_LPF_C, 0);
267 | }
268 | else {
269 | digitalWrite(TX_LPF_A, 0);
270 | digitalWrite(TX_LPF_B, 0);
271 | digitalWrite(TX_LPF_C, 1);
272 | }
273 | }
274 |
275 |
276 | void setTXFilters_v5(unsigned long freq){
277 |
278 | if (freq > 21000000L){ // the default filter is with 35 MHz cut-off
279 | digitalWrite(TX_LPF_A, 0);
280 | digitalWrite(TX_LPF_B, 0);
281 | digitalWrite(TX_LPF_C, 0);
282 | }
283 | else if (freq >= 14000000L){ //thrown the KT1 relay on, the 30 MHz LPF is bypassed and the 14-18 MHz LPF is allowd to go through
284 | digitalWrite(TX_LPF_A, 1);
285 | digitalWrite(TX_LPF_B, 0);
286 | digitalWrite(TX_LPF_C, 0);
287 | }
288 | else if (freq > 7000000L){
289 | digitalWrite(TX_LPF_A, 0);
290 | digitalWrite(TX_LPF_B, 1);
291 | digitalWrite(TX_LPF_C, 0);
292 | }
293 | else {
294 | digitalWrite(TX_LPF_A, 0);
295 | digitalWrite(TX_LPF_B, 0);
296 | digitalWrite(TX_LPF_C, 1);
297 | }
298 | }
299 |
300 |
301 | /**
302 | * This is the most frequently called function that configures the
303 | * radio to a particular frequeny, sideband and sets up the transmit filters
304 | *
305 | * The transmit filter relays are powered up only during the tx so they dont
306 | * draw any current during rx.
307 | *
308 | * The carrier oscillator of the detector/modulator is permanently fixed at
309 | * uppper sideband. The sideband selection is done by placing the second oscillator
310 | * either 12 Mhz below or above the 45 Mhz signal thereby inverting the sidebands
311 | * through mixing of the second local oscillator.
312 | */
313 |
314 | void setFrequency(unsigned long f){
315 | uint64_t osc_f, firstOscillator, secondOscillator;
316 |
317 | setTXFilters(f);
318 |
319 | /*
320 | if (isUSB){
321 | si5351bx_setfreq(2, firstIF + f);
322 | si5351bx_setfreq(1, firstIF + usbCarrier);
323 | }
324 | else{
325 | si5351bx_setfreq(2, firstIF + f);
326 | si5351bx_setfreq(1, firstIF - usbCarrier);
327 | }
328 | */
329 | //alternative to reduce the intermod spur
330 | if (isUSB){
331 | si5351bx_setfreq(2, firstIF + f);
332 | si5351bx_setfreq(1, firstIF + usbCarrier);
333 | }
334 | else{
335 | si5351bx_setfreq(2, firstIF + f);
336 | si5351bx_setfreq(1, firstIF - usbCarrier);
337 | }
338 |
339 | frequency = f;
340 | }
341 |
342 | /**
343 | * startTx is called by the PTT, cw keyer and CAT protocol to
344 | * put the uBitx in tx mode. It takes care of rit settings, sideband settings
345 | * Note: In cw mode, doesnt key the radio, only puts it in tx mode
346 | * CW offest is calculated as lower than the operating frequency when in LSB mode, and vice versa in USB mode
347 | */
348 |
349 | void startTx(byte txMode){
350 | unsigned long tx_freq = 0;
351 |
352 | digitalWrite(TX_RX, 1);
353 | inTx = 1;
354 |
355 | if (ritOn){
356 | //save the current as the rx frequency
357 | ritRxFrequency = frequency;
358 | setFrequency(ritTxFrequency);
359 | }
360 | else
361 | {
362 | if (splitOn == 1) {
363 | if (vfoActive == VFO_B) {
364 | vfoActive = VFO_A;
365 | isUSB = isUsbVfoA;
366 | frequency = vfoA;
367 | }
368 | else if (vfoActive == VFO_A){
369 | vfoActive = VFO_B;
370 | frequency = vfoB;
371 | isUSB = isUsbVfoB;
372 | }
373 | }
374 | setFrequency(frequency);
375 | }
376 |
377 | if (txMode == TX_CW){
378 | //turn off the second local oscillator and the bfo
379 | si5351bx_setfreq(0, 0);
380 | si5351bx_setfreq(1, 0);
381 |
382 | //shif the first oscillator to the tx frequency directly
383 | //the key up and key down will toggle the carrier unbalancing
384 | //the exact cw frequency is the tuned frequency + sidetone
385 | if (isUSB)
386 | si5351bx_setfreq(2, frequency + sideTone);
387 | else
388 | si5351bx_setfreq(2, frequency - sideTone);
389 | }
390 | updateDisplay();
391 | }
392 |
393 | void stopTx(){
394 | inTx = 0;
395 |
396 | digitalWrite(TX_RX, 0); //turn off the tx
397 | si5351bx_setfreq(0, usbCarrier); //set back the cardrier oscillator anyway, cw tx switches it off
398 |
399 | if (ritOn)
400 | setFrequency(ritRxFrequency);
401 | else{
402 | if (splitOn == 1) {
403 | //vfo Change
404 | if (vfoActive == VFO_B){
405 | vfoActive = VFO_A;
406 | frequency = vfoA;
407 | isUSB = isUsbVfoA;
408 | }
409 | else if (vfoActive == VFO_A){
410 | vfoActive = VFO_B;
411 | frequency = vfoB;
412 | isUSB = isUsbVfoB;
413 | }
414 | }
415 | setFrequency(frequency);
416 | }
417 | updateDisplay();
418 | }
419 |
420 | /**
421 | * ritEnable is called with a frequency parameter that determines
422 | * what the tx frequency will be
423 | */
424 | void ritEnable(unsigned long f){
425 | ritOn = 1;
426 | //save the non-rit frequency back into the VFO memory
427 | //as RIT is a temporary shift, this is not saved to EEPROM
428 | ritTxFrequency = f;
429 | }
430 |
431 | // this is called by the RIT menu routine
432 | void ritDisable(){
433 | if (ritOn){
434 | ritOn = 0;
435 | setFrequency(ritTxFrequency);
436 | updateDisplay();
437 | }
438 | }
439 |
440 | /**
441 | * Basic User Interface Routines. These check the front panel for any activity
442 | */
443 |
444 | /**
445 | * The PTT is checked only if we are not already in a cw transmit session
446 | * If the PTT is pressed, we shift to the ritbase if the rit was on
447 | * flip the T/R line to T and update the display to denote transmission
448 | */
449 |
450 | void checkPTT(){
451 | //we don't check for ptt when transmitting cw
452 | if (cwTimeout > 0)
453 | return;
454 |
455 | if (digitalRead(PTT) == 0 && inTx == 0){
456 | startTx(TX_SSB);
457 | active_delay(50); //debounce the PTT
458 | }
459 |
460 | if (digitalRead(PTT) == 1 && inTx == 1)
461 | stopTx();
462 | }
463 |
464 | void checkButton(){
465 | int i, t1, t2, knob, new_knob;
466 |
467 | //only if the button is pressed
468 | if (!btnDown())
469 | return;
470 | active_delay(50);
471 | if (!btnDown()) //debounce
472 | return;
473 |
474 | doMenu();
475 | //wait for the button to go up again
476 | while(btnDown())
477 | active_delay(10);
478 | active_delay(50);//debounce
479 | }
480 |
481 |
482 | /**
483 | * The tuning jumps by 50 Hz on each step when you tune slowly
484 | * As you spin the encoder faster, the jump size also increases
485 | * This way, you can quickly move to another band by just spinning the
486 | * tuning knob
487 | */
488 |
489 |
490 | void doTuning(){
491 | int s;
492 | unsigned long prev_freq;
493 |
494 | s = enc_read();
495 | if (s != 0){
496 | prev_freq = frequency;
497 |
498 | if (s > 4)
499 | frequency += 10000l;
500 | else if (s > 2)
501 | frequency += 500;
502 | else if (s > 0)
503 | frequency += 50l;
504 | else if (s > -2)
505 | frequency -= 50l;
506 | else if (s > -4)
507 | frequency -= 500l;
508 | else
509 | frequency -= 10000l;
510 |
511 | if (prev_freq < 10000000l && frequency > 10000000l)
512 | isUSB = true;
513 |
514 | if (prev_freq > 10000000l && frequency < 10000000l)
515 | isUSB = false;
516 |
517 | setFrequency(frequency);
518 | updateDisplay();
519 | }
520 | }
521 |
522 | /**
523 | * RIT only steps back and forth by 100 hz at a time
524 | */
525 | void doRIT(){
526 | unsigned long newFreq;
527 |
528 | int knob = enc_read();
529 | unsigned long old_freq = frequency;
530 |
531 | if (knob < 0)
532 | frequency -= 100l;
533 | else if (knob > 0)
534 | frequency += 100;
535 |
536 | if (old_freq != frequency){
537 | setFrequency(frequency);
538 | updateDisplay();
539 | }
540 | }
541 |
542 | /**
543 | * The settings are read from EEPROM. The first time around, the values may not be
544 | * present or out of range, in this case, some intelligent defaults are copied into the
545 | * variables.
546 | */
547 | void initSettings(){
548 | byte x;
549 | //read the settings from the eeprom and restore them
550 | //if the readings are off, then set defaults
551 | EEPROM.get(MASTER_CAL, calibration);
552 | EEPROM.get(USB_CAL, usbCarrier);
553 | EEPROM.get(VFO_A, vfoA);
554 | EEPROM.get(VFO_B, vfoB);
555 | EEPROM.get(CW_SIDETONE, sideTone);
556 | EEPROM.get(CW_SPEED, cwSpeed);
557 |
558 |
559 | if (usbCarrier > 11060000l || usbCarrier < 11048000l)
560 | usbCarrier = 11052000l;
561 | if (vfoA > 35000000l || 3500000l > vfoA)
562 | vfoA = 7150000l;
563 | if (vfoB > 35000000l || 3500000l > vfoB)
564 | vfoB = 14150000l;
565 | if (sideTone < 100 || 2000 < sideTone)
566 | sideTone = 800;
567 | if (cwSpeed < 10 || 1000 < cwSpeed)
568 | cwSpeed = 100;
569 |
570 | /*
571 | * The VFO modes are read in as either 2 (USB) or 3(LSB), 0, the default
572 | * is taken as 'uninitialized
573 | */
574 |
575 | EEPROM.get(VFO_A_MODE, x);
576 |
577 | switch(x){
578 | case VFO_MODE_USB:
579 | isUsbVfoA = 1;
580 | break;
581 | case VFO_MODE_LSB:
582 | isUsbVfoA = 0;
583 | break;
584 | default:
585 | if (vfoA > 10000000l)
586 | isUsbVfoA = 1;
587 | else
588 | isUsbVfoA = 0;
589 | }
590 |
591 | EEPROM.get(VFO_B_MODE, x);
592 | switch(x){
593 | case VFO_MODE_USB:
594 | isUsbVfoB = 1;
595 | break;
596 | case VFO_MODE_LSB:
597 | isUsbVfoB = 0;
598 | break;
599 | default:
600 | if (vfoA > 10000000l)
601 | isUsbVfoB = 1;
602 | else
603 | isUsbVfoB = 0;
604 | }
605 |
606 | //set the current mode
607 | isUSB = isUsbVfoA;
608 |
609 | /*
610 | * The keyer type splits into two variables
611 | */
612 | EEPROM.get(CW_KEY_TYPE, x);
613 |
614 | if (x == 0)
615 | Iambic_Key = false;
616 | else if (x == 1){
617 | Iambic_Key = true;
618 | keyerControl &= ~IAMBICB;
619 | }
620 | else if (x == 2){
621 | Iambic_Key = true;
622 | keyerControl |= IAMBICB;
623 | }
624 |
625 | }
626 |
627 | void initPorts(){
628 |
629 | analogReference(DEFAULT);
630 |
631 | //??
632 | pinMode(ENC_A, INPUT_PULLUP);
633 | pinMode(ENC_B, INPUT_PULLUP);
634 | pinMode(FBUTTON, INPUT_PULLUP);
635 |
636 | //configure the function button to use the external pull-up
637 | // pinMode(FBUTTON, INPUT);
638 | // digitalWrite(FBUTTON, HIGH);
639 |
640 | pinMode(PTT, INPUT_PULLUP);
641 | pinMode(ANALOG_KEYER, INPUT_PULLUP);
642 |
643 | pinMode(CW_TONE, OUTPUT);
644 | digitalWrite(CW_TONE, 0);
645 |
646 | pinMode(TX_RX,OUTPUT);
647 | digitalWrite(TX_RX, 0);
648 |
649 | pinMode(TX_LPF_A, OUTPUT);
650 | pinMode(TX_LPF_B, OUTPUT);
651 | pinMode(TX_LPF_C, OUTPUT);
652 | digitalWrite(TX_LPF_A, 0);
653 | digitalWrite(TX_LPF_B, 0);
654 | digitalWrite(TX_LPF_C, 0);
655 |
656 | pinMode(CW_KEY, OUTPUT);
657 | digitalWrite(CW_KEY, 0);
658 | }
659 |
660 | void setup()
661 | {
662 | Serial.begin(38400);
663 | Serial.flush();
664 |
665 | lcd.begin(16, 2);
666 |
667 | //we print this line so this shows up even if the raduino
668 | //crashes later in the code
669 | printLine2("uBITX v5.1");
670 | //active_delay(500);
671 |
672 | // initMeter(); //not used in this build
673 | initSettings();
674 | initPorts();
675 | initOscillators();
676 |
677 | frequency = vfoA;
678 | setFrequency(vfoA);
679 | updateDisplay();
680 |
681 | if (btnDown())
682 | factory_alignment();
683 | }
684 |
685 |
686 | /**
687 | * The loop checks for keydown, ptt, function button and tuning.
688 | */
689 |
690 | byte flasher = 0;
691 | void loop(){
692 |
693 | cwKeyer();
694 | if (!txCAT)
695 | checkPTT();
696 | checkButton();
697 |
698 | //tune only when not tranmsitting
699 | if (!inTx){
700 | if (ritOn)
701 | doRIT();
702 | else
703 | doTuning();
704 | }
705 |
706 | //we check CAT after the encoder as it might put the radio into TX
707 | checkCAT();
708 | }
709 |
--------------------------------------------------------------------------------
/ubitx_v5.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afarhan/ubitx_v5/c519a75934e691f8e42a8a5254f568a5abeac899/ubitx_v5.pdf
--------------------------------------------------------------------------------