194 Commits

Author SHA1 Message Date
Rob French
da58606409 Added some more debug code. Compiles. 2021-01-30 07:49:19 -06:00
Rob French
091f414409 Update to include basic audio functionality. Compiles. Need to add more debug checking. 2021-01-30 00:02:57 -06:00
Rob French
87b6e3fbde compiles successfully 2021-01-26 22:49:07 -06:00
Rob French
48cb6cf304 Additional missing files. 2021-01-26 22:22:23 -06:00
Rob French
c59d53fb9e Lots of updates prior to first compile. 2021-01-26 22:22:02 -06:00
Rob French
16b350cb0f More reorg changes in the DSP code. Working towards creating a separate ADC 'process' that will continually update the applicable variables, and then they'll be reported upon request via I2C or Serial as applicable. 2021-01-21 22:00:35 -06:00
Rob French
bb31ccfbe4 Additional modifications to retarget the code for Teensy with the Audio Adapter. 2021-01-21 11:37:27 -06:00
Rob French
c1c4dd3f19 Some code realignment, including changing from millis to elapsedMillis. 2021-01-21 09:44:06 -06:00
Rob French
d97f282f7b Merge branch 'master' of ssh://git.sdf.org:2222/kc4upr/ubitx-v5x 2021-01-20 23:30:13 -06:00
Rob French
c93e191dfd More reorg. 2021-01-20 23:26:38 -06:00
Rob French
b50ad3275a Initial commit 2021-01-21 05:08:16 +00:00
Rob French
04b70450ae Reorganized. 2021-01-20 20:50:27 -06:00
Rob French
3364cb78d5 Merge remote-tracking branch 'teensydsp/master' 2021-01-20 20:43:32 -06:00
Rob French
cfa6f8699d Move raduino files into subdir 2021-01-20 20:42:20 -06:00
Rob French
48344923cc Merge remote-tracking branch 'raduino/master' 2021-01-20 20:36:04 -06:00
Rob French
dec1d1edec Initial commit before I start merging in other projects. 2021-01-20 20:31:27 -06:00
phdlee
e77a3715a8 Update README.md 2020-09-08 17:46:57 +09:00
phdlee
1a60adaf2f Merge pull request #2 from phdlee/version0.8
added SWR, PWR sensor
2019-04-11 22:38:52 +09:00
phdlee
02c0066df4 added SWR, PWR sensor 2019-04-11 22:37:24 +09:00
phdlee
262ef3947a Merge pull request #46 from phdlee/version1.20
changed version number for nextion lcd protocol
2019-04-06 16:38:44 +09:00
phdlee
a4d9f6e6c5 changed version number for nextion lcd protocol 2019-04-06 16:35:46 +09:00
phdlee
395dd42459 Update README.md 2019-04-02 23:20:04 +09:00
phdlee
f25bf57556 Update README.md 2019-04-02 23:18:54 +09:00
phdlee
171f889f4a Merge pull request #45 from phdlee/version1.20
Version1.20
2019-04-02 23:16:03 +09:00
phdlee
05de66a038 uBITX V5 suppoort and SDR Frequency Change 2019-04-02 23:09:18 +09:00
phdlee
2c075d5236 for uBITX v5 2019-02-15 19:32:07 +09:00
phdlee
37fcc5975a Merge pull request #44 from phdlee/version1.11
Added Custom LPF Control
2018-09-22 19:14:22 +09:00
phdlee
450f57ae0f Added Custom LPF Control 2018-09-22 18:56:23 +09:00
phdlee
c34e798313 Update README.md 2018-09-11 18:09:22 +09:00
phdlee
df2c493700 Merge pull request #43 from phdlee/version1.1
Add Custom LPF Filter and Changed Version Number
2018-09-07 23:39:25 +09:00
phdlee
9ff8365c3f Add Custom LPF Filter and Changed Version Number 2018-09-07 23:37:23 +09:00
phdlee
948267bb39 Merge pull request #40 from phdlee/version1.098
Version1.098
2018-08-10 16:08:13 +09:00
phdlee
e79dbdbbe7 for Release Version 1.097 2018-08-06 13:59:55 +09:00
phdlee
265188dc86 Merge pull request #1 from phdlee/version0.7
added delay time at startup
2018-08-06 12:11:41 +09:00
phdlee
aee410fd19 added delay time at startup 2018-08-06 11:58:41 +09:00
phdlee
16e173b109 add Init version files 2018-08-04 11:23:20 +09:00
phdlee
d5db04ff0e Init and add comment for licnese 2018-08-04 11:04:51 +09:00
phdlee
0586bb75a7 Initial commit 2018-08-04 10:55:39 +09:00
phdlee
7c1ee29500 Before Release V1.096 2018-07-28 18:53:28 +09:00
phdlee
4ee3631db0 Change menu type (selectable functions) 2018-07-17 21:10:45 +09:00
phdlee
c27bbf1b6b Apply DSP meter to all lcd types 2018-07-17 20:41:17 +09:00
phdlee
b984f62dfd Add I2C Scan, Change DSP Meter I2C 2018-07-17 20:13:06 +09:00
phdlee
41548163cf Support I2C S-Meter 2018-07-17 11:21:24 +09:00
phdlee
1ce889eef0 Release v1.095 Beta 2018-07-05 19:18:22 +09:00
phdlee
dd43ba4c33 Modified about Loopback protocol 2018-06-28 23:29:06 +09:00
phdlee
fe44c703c5 define eeprom map for external device and send eeprom data to nextion lcd 2018-06-19 11:17:58 +09:00
phdlee
22bb9ee112 Release 1.093Beta 2018-06-17 01:19:37 +09:00
phdlee
c73fffb25b Modified Spectrum Protocol 2018-06-16 23:03:47 +09:00
phdlee
82177199c4 Increase Buffer for SW Serial and Modified Protocol for EEProm 2018-06-16 21:45:55 +09:00
phdlee
0e13dd0267 modified Checksum logic for Nextion LCD 2018-06-15 21:43:56 +09:00
phdlee
c602fdde7c Add EEProm Read by Nextion LCD Reversed order 2018-06-15 20:48:51 +09:00
phdlee
edadce7d89 add protocol about eeprom 2018-06-15 10:34:52 +09:00
phdlee
9da71429cb added protocol 2018-06-13 23:15:58 +09:00
phdlee
3050374504 Second Deploy for Nextion LCD 2018-06-12 00:30:50 +09:00
phdlee
152b63a9ed Added SW Trigger, Spectrum Protocol, Get ADC Protocol 2018-06-11 22:06:42 +09:00
phdlee
72ccd3b0e4 modified protocol for nextion lcd 2018-06-09 18:26:11 +09:00
phdlee
e81413fa02 Support Nextion LCD 2018-06-09 17:13:26 +09:00
phdlee
c6b020fa70 Update README.md 2018-05-23 18:32:55 +09:00
phdlee
2e8c97f19b Update README.md 2018-05-23 18:32:01 +09:00
phdlee
337320b433 Merge pull request #37 from phdlee/version1.080
add comment
2018-05-23 16:00:25 +09:00
phdlee
7c8088f753 add comment 2018-05-23 15:58:50 +09:00
phdlee
b172527d00 Merge pull request #36 from phdlee/version1.080
Version1.080
2018-05-23 15:46:01 +09:00
phdlee
67cdd14945 modified comments 2018-05-23 15:28:00 +09:00
phdlee
b375b7e9e4 modified some comments 2018-05-23 15:20:10 +09:00
phdlee
27092d23e0 Merge pull request #35 from phdlee/version1.080
Version1.080
2018-05-23 15:09:43 +09:00
phdlee
8a6e01e289 improve external switch check routine 2018-05-23 15:07:37 +09:00
phdlee
83dc1de18e fixed mode change 2018-05-22 11:37:10 +09:00
phdlee
2de1c873a1 Merge pull request #34 from phdlee/version1.075
Version1.075
2018-05-09 16:55:47 +09:00
phdlee
4d97ac2283 Merge pull request #33 from phdlee/version1.074
Version1.074
2018-05-09 16:54:51 +09:00
phdlee
65d21aba77 Fixed Band Select Bug 2018-05-09 16:53:49 +09:00
phdlee
6a2369bc27 Fixed Band Select Bug 2018-05-09 16:53:40 +09:00
phdlee
76d5c362d0 complete test for Factory Recovery 2018-05-07 14:08:22 +09:00
phdlee
70fc6aeba8 Add Factory Recovery function 2018-05-07 13:56:46 +09:00
phdlee
75d952718b Merge pull request #32 from phdlee/version1.073
reduce compiller warning
2018-05-06 22:34:15 +09:00
phdlee
1d28f3e7e9 update versioninfo.txt 2018-05-03 21:23:10 +09:00
phdlee
51f690ef85 change frequency display in WSPR Menu 2018-05-03 17:57:06 +09:00
phdlee
12984486a6 Modfied SMeter and CAT 2018-05-03 16:20:09 +09:00
phdlee
e961cd8ac9 reduce compiller warning 2018-04-24 18:00:41 +09:00
phdlee
5c40718bec Merge pull request #31 from phdlee/version1.073
Version1.073
2018-04-24 17:33:58 +09:00
phdlee
6add092391 Extended key (select key type) 2018-04-24 17:26:34 +09:00
phdlee
3b4bdafacc Merge pull request #30 from phdlee/version1.072
Version1.072
2018-04-23 21:43:56 +09:00
phdlee
82d9682ee9 Merge branch 'master' into version1.072 2018-04-23 21:43:50 +09:00
phdlee
6be127d811 test lcd 2018-04-23 21:40:45 +09:00
phdlee
5b13ede65b test of extended key and dual lcd 2018-04-23 08:29:19 +09:00
phdlee
0aafe32e27 Added Dual LCD 2018-04-21 16:09:21 +09:00
phdlee
289ae1bd77 Merge pull request #29 from phdlee/version1.071
Improve receive perforamnce for USB, CWU, custom uBITX
2018-04-18 20:25:32 +09:00
phdlee
5611e1c0ff lcdtest and extended ubutton tested 2018-04-18 20:22:52 +09:00
phdlee
86797181cf Merge pull request #28 from RichNeese/master
Tuning step change
2018-04-18 08:32:53 +09:00
phdlee
f600c18541 add extended Keys (mode, band, tunestep) and i2clcd working 2018-04-17 21:26:29 +09:00
Richard Neese
11b6fbc1f4 Tuning step change
changed tuning steps to 10/50/100/500/1000
2018-04-16 21:56:20 -04:00
phdlee
0e245fc488 Add 20x04LCD and S.Meter 2018-04-16 23:56:32 +09:00
phdlee
d721816039 LCD Work step1 2018-04-12 22:08:43 +09:00
phdlee
34be2d0845 Improve receive perforamnce for USB, CWU, custom uBITX 2018-04-09 23:35:13 +09:00
phdlee
0996870154 Merge pull request #27 from phdlee/version1.07
Version1.07
2018-04-07 21:33:30 +09:00
phdlee
689cfda09e Add Support SDR Receiver and improve ATT 2018-04-07 21:32:01 +09:00
phdlee
23f1b7cd5c Added IF Tune, ATT, SDR Functions 2018-04-06 21:43:36 +09:00
phdlee
d4ed0589e5 Applied 1602 Tiny LCD Library for reduce program Memory 2018-04-05 22:57:07 +09:00
phdlee
5f906a4497 To Support various LCD Type 2018-04-05 22:16:54 +09:00
phdlee
1210f56cd1 move display routine ui to idle 2018-04-05 21:30:35 +09:00
phdlee
e8d6792073 complete setup menu ui for reduce program memory 2018-04-05 17:36:16 +09:00
phdlee
9c4b694ce2 Update README.md 2018-04-05 10:19:38 +09:00
phdlee
02f22d66e5 Change Menu codes 2018-04-05 09:50:29 +09:00
phdlee
11e47fdccc Added Version Info at top of ubitx_20.ino 2018-04-04 22:20:04 +09:00
phdlee
7aafed9e95 rename ubitx_wspr.cpp to ubitx_wspr.ino 2018-04-04 20:29:27 +09:00
phdlee
5afcdf2583 Update README.md 2018-04-04 20:22:42 +09:00
phdlee
075f585a1e Update README.md 2018-03-29 22:31:36 +09:00
phdlee
d0c04df9d8 Merge pull request #26 from phdlee/version1.06
Version1.06
2018-03-25 03:22:29 +09:00
phdlee
dd6d4555a8 Update ubitx_20.ino 2018-03-25 03:21:31 +09:00
phdlee
8f8850f4da Update ubitx_wspr.cpp 2018-03-25 03:17:04 +09:00
phdlee
4e9437a735 Merge pull request #25 from phdlee/version1.06
Change Version Name
2018-03-24 21:34:17 +09:00
phdlee
bad62ef728 Change Version Name 2018-03-24 21:33:01 +09:00
phdlee
384c3c41b2 Merge pull request #24 from phdlee/version1.05
Version1.05
2018-03-21 14:21:28 +09:00
phdlee
93727e6b22 fixed Cat in IFSifht setup routine 2018-03-21 14:20:09 +09:00
phdlee
31a7f79569 ifshift store, cw mode shift change 2018-03-20 21:41:24 +09:00
phdlee
d7858e35c3 if shift bfo modified 2018-03-20 17:06:28 +09:00
phdlee
ecd104b686 Fixed IF Shift Bug (USB and TX Mode) 2018-03-19 21:35:41 +09:00
phdlee
bd52de59d2 bug fixed (found gereld) Autokey on Rit bug 2018-03-19 10:13:30 +09:00
phdlee
f0409d641d Auto key Bug fixed, LZ1LDO found bug 2018-03-17 11:11:27 +09:00
phdlee
8326b1ade3 bug fixed : cw start delay option 2018-03-15 21:00:42 +09:00
phdlee
94a3e5ca1b Test and some mod about WSPR Calibration 2018-03-13 01:17:06 +09:00
phdlee
a26978f573 Added WSPR and Reduce Program size 2018-03-09 22:02:10 +09:00
phdlee
a21dbe2fa5 Update README.md 2018-03-05 13:03:05 +09:00
phdlee
9faa8bb44c Merge pull request #23 from phdlee/version1.04
Optimized from Version1.03
2018-03-05 12:56:55 +09:00
phdlee
d926b15e3d Merge pull request #22 from phdlee/version1.03
Version1.03
2018-03-05 12:55:41 +09:00
phdlee
fb2c9d2cc3 Optimized from Version1.03 2018-03-05 12:51:14 +09:00
phdlee
bf68dd6c26 Change Version Number 2018-02-22 13:27:51 +09:00
phdlee
4a6909f361 Change BFO Cal Step(50 to 5), Change CW Frequency Method 2018-02-22 12:26:18 +09:00
phdlee
c911d26163 Merge pull request #21 from phdlee/version1.02
Version1.02
2018-02-14 12:11:38 +09:00
phdlee
98e3b41f5a Merge pull request #20 from phdlee/version1.0
Version1.0
2018-02-14 12:10:38 +09:00
phdlee
e0f9148972 Change RIT tune step (freq tune step) 2018-02-13 19:54:19 +09:00
phdlee
277666f82f Konstantinos (SV1ONW) shared the usage of uBITX Manager on Linux.
Konstantinos (SV1ONW) shared the usage of uBITX Manager on Linux.
2018-02-10 18:34:21 +09:00
phdlee
e532dccce7 Update README.md 2018-02-10 15:10:55 +09:00
phdlee
81333e7af4 modified CW Key Logic for AutoKey and reduce cpu use rate, reduce program memory 2018-02-10 15:07:56 +09:00
phdlee
04949cdb93 Update README.md 2018-02-10 13:41:12 +09:00
phdlee
bbdd0947d3 Update README.md 2018-02-10 13:31:51 +09:00
phdlee
ed767f2e34 CW Start Delay applied New CW Logic 2018-02-10 13:29:30 +09:00
phdlee
a374297d49 Update README.md 2018-02-09 13:42:36 +09:00
phdlee
1e9576ddc2 fixed cat with cw key (IA, IB) 2018-02-09 01:11:48 +09:00
phdlee
a7684284d2 write eeprom cycle test and reconvery 2018-02-08 12:45:54 +09:00
phdlee
c1d81d9d5b Update README.md 2018-02-08 01:15:39 +09:00
phdlee
3b4aaa664c version0.35 2018-02-06 16:13:05 +09:00
phdlee
d69588d999 Merge pull request #19 from phdlee/version0.35
Version0.35
2018-02-05 16:48:56 +09:00
phdlee
14888bb7d7 change channel name display code 2018-02-05 16:46:37 +09:00
phdlee
57cd385b8a add vfo to channel, channel to vfo 2018-02-05 15:07:25 +09:00
phdlee
e915c21412 Merge pull request #18 from phdlee/version0.34
Version0.34
2018-02-03 17:17:43 +09:00
phdlee
60777178a8 TX Check in auto keysend 2018-02-03 17:07:11 +09:00
phdlee
dd68b38454 Optimize codes 2018-02-03 16:35:27 +09:00
phdlee
d229a10092 change tune step size and fixed bug 2018-02-02 20:49:00 +09:00
phdlee
3d019cdd44 change IF Shift Step 1 -> 50Hz 2018-01-31 17:53:20 +09:00
phdlee
55cfeeb924 Update README.md 2018-01-31 12:13:44 +09:00
phdlee
c8879e0e59 Update README.md 2018-01-31 12:12:58 +09:00
phdlee
4f5ac283b7 Merge pull request #17 from phdlee/version0.33
Version0.33
2018-01-31 10:47:20 +09:00
phdlee
4745790dfa fixed Key select bug 2018-01-31 10:44:23 +09:00
phdlee
85832de034 change confirmation key PTT->function key for easy interface 2018-01-30 20:02:49 +09:00
phdlee
4830db78cb change IF Shift setup type 2018-01-30 18:43:08 +09:00
phdlee
5eca64d2a9 vfo changed buf fixed, added BFO feature with Mike 2018-01-30 17:44:15 +09:00
phdlee
0d9ec08bd7 Added CWL, CWU Mode, need test 2018-01-30 13:20:52 +09:00
phdlee
3058d52551 Merge pull request #16 from phdlee/version0.32
Version0.32
2018-01-30 12:20:18 +09:00
phdlee
98c26730c6 display test and split TX/RX added 2018-01-30 12:13:52 +09:00
phdlee
3a306429ea display exaam (scroll freq) #2 2018-01-30 00:00:43 +09:00
phdlee
4f634a8277 line2 display example1.1 2018-01-29 23:02:46 +09:00
phdlee
a49d5e85b8 line2 display sample1 2018-01-29 22:49:30 +09:00
phdlee
04699ba074 Merge pull request #15 from phdlee/version0.31
Fixed Bug CW Key Range
Append Feature : Display Line Toggle, (Between line1 and line2)
 Append function : for other users / using s.meter, p.meter ... (when idle time execute function)
2018-01-29 18:44:05 +09:00
phdlee
282c196f63 fixed cw adc range bug 2018-01-29 18:38:48 +09:00
phdlee
aa61281c38 Merge pull request #14 from phdlee/version0.296
rename version to 0.30
2018-01-27 18:39:22 +09:00
phdlee
ee23827def rename version to 0.30 2018-01-27 18:38:18 +09:00
phdlee
261215b1ad Merge pull request #13 from phdlee/version0.296
Version0.296 => Version 0.30
2018-01-27 18:36:07 +09:00
phdlee
1a2f5b4fde Update README.md 2018-01-27 18:33:51 +09:00
phdlee
8d4c788e11 1st Test new CW Keyer and add cat message processing 2018-01-27 18:05:08 +09:00
phdlee
cc7dd752e6 add function adjust CW ADC Range 2018-01-27 16:39:54 +09:00
phdlee
4506ff1c1b for Reduce CW Keying error 2018-01-26 21:47:15 +09:00
phdlee
8203427808 Merge pull request #12 from phdlee/version0.296
Add Comment
2018-01-26 18:25:48 +09:00
phdlee
db543c43e1 Add Comment 2018-01-26 18:23:52 +09:00
phdlee
4e15f2150c Update README.md 2018-01-25 23:39:33 +09:00
phdlee
82a5fd7df9 Merge pull request #11 from phdlee/version0.296
Version0.296
2018-01-25 23:33:04 +09:00
phdlee
981db341db change defautl key type 2018-01-25 23:31:47 +09:00
phdlee
020b34e504 add menu for new Keyer logic 2018-01-25 23:15:24 +09:00
phdlee
386a0b2d46 Update README.md 2018-01-25 22:33:20 +09:00
phdlee
c6401af7d1 Merge pull request #10 from phdlee/version0.29
Version0.29
2018-01-25 22:26:19 +09:00
phdlee
b153a305d6 Merge branch 'master' into version0.29 2018-01-25 22:25:35 +09:00
phdlee
c7be3dcd39 test for new cw keying logic 2018-01-24 21:41:15 +09:00
phdlee
bbb23bf817 default set for new users 2018-01-22 21:16:29 +09:00
phdlee
4d61cf4de9 freq tunes, and set defualt values 2018-01-22 19:46:50 +09:00
phdlee
e61e45d3dd Update README.md 2018-01-22 18:26:22 +09:00
phdlee
a1f941f965 Update README.md 2018-01-22 18:25:41 +09:00
phdlee
d1e72b3bd5 Update README.md 2018-01-22 18:24:29 +09:00
phdlee
032e7f919f Update README.md 2018-01-22 18:21:55 +09:00
phdlee
b6bc264332 Update README.md 2018-01-22 18:11:15 +09:00
phdlee
b1cc5eb98a Update README.md 2018-01-22 02:11:35 +09:00
phdlee
2fa8247501 v0.29 prepare 2018-01-20 22:05:04 +09:00
phdlee
2fe1662d67 Merge pull request #8 from qiwenmin/master
Fixed most compilation warnings and a delay issue
2018-01-20 21:24:15 +09:00
phdlee
ebbc5aae5e Merge pull request #9 from phdlee/version0.28
change delaytimes via cat
2018-01-18 11:47:21 +09:00
Qi Wenmin
209cd3a49c Fixed most compilation warnings and a delay issue
* Fixed most compilation warnings (Compiler warning level: All)
* Fixed a delay issue in enc_read function.
2018-01-17 14:42:15 +08:00
phdlee
587d4854c3 change delaytimes via cat 2018-01-17 14:05:20 +09:00
42 changed files with 11556 additions and 2529 deletions

129
README.md
View File

@@ -1,128 +1,3 @@
#IMPORTANT INFORMATION
----------------------------------------------------------------------------
- Beta 0.26 and Beta 0.261, Beta 0.262, Beta 0.27 is complete test
- You can download and use it.
# ubitx-v5x
#NOTICE
----------------------------------------------------------------------------
I received uBITX a month ago and found that many features are required, and began coding with the idea of implementing minimal functionality as a general hf transceiver rather than an experimental device.
- fixed bugs...
- Diallock for uBITX's sensitive encoders
- built in softare Memory keyer and cw options control for CW communication
- Implementation of CAT communication protocol for Digital Communication (as FT8, JT65, etc)
- Delay Options for external Linear.
- and more...
Most of the basic functions of the HF transceiver I thought were implemented.
The minimum basic specification for uBITX to operate as a radio, I think it is finished.
So I will release the 0.27 version and if I do not see the bug anymore, I will try to change the version name to 1.0.
Now uBITX is an HF radio and will be able to join you in your happy hams life.
Based on this source, you can use it by adding functions.
I am going to do a new project based on this source, linking with WSPR, WSJT-X and so on.
Of course, this repository is still running. If you have any bugs or ideas, please feel free to email me.
http://www.hamskey.com
DE KD8CEC
kd8cec@gmail.com
#uBITX
uBITX firmware, written for the Raduino/Arduino control of uBITX transceivers
This project is based on https://github.com/afarhan/ubitx and all copyright is inherited.
The copyright information of the original is below.
KD8CEC
----------------------------------------------------------------------------
Prepared or finished tasks for the next version
- Most of them are implemented and included in version 0.27.
- User Interface on LCD -> Option by user (not need)
- Include WSPR Beacone function - (implement other new repository)
complete experiment
need solve : Big code size (over 100%, then remove some functions for experment)
need replace Si5351 Library (increase risk and need more beta tester)
W3PM sent me his wonderful source - using BITX, GPS
----------------------------------------------------------------------------
## REVISION RECORD
0.27
(First alpha test version, This will be renamed to the major version 1.0)
- Dual VFO Dial Lock (vfoA Dial lock)
- Support Ham band on uBITX
default Hamband is regeion1 but customize by uBITX Manager Software
- Advanced ham band options (Tx control) for use in all countries. You can adjust it yourself.
- Convenience of band movement
0.26
- only Beta tester released & source code share
- find a bug on none initial eeprom uBITX - Fixed (Check -> initialized & compatible original source code)
- change the version number 0.26 -> 0.27
- Prevent overflow bugs
- bug with linux based Hamlib (raspberry pi), It was perfect for the 0.224 version, but there was a problem for the 0.25 version.
On Windows, ham deluxe, wsjt-x, jt65-hf, and fldigi were successfully run. Problem with Raspberry pi.
0.25
- Beta Version Released
http://www.hamskey.com/2018/01/release-beta-version-of-cat-support.html
- Added CAT Protocol for uBITX
- Modified the default usb carrier value used when the setting is wrong.
- Fixed a routine to repair when the CAT protocol was interrupted.
0.24
- Program optimization
reduce usage ram rate (string with M() optins)
- Optimized CAT protocol for wsjt-x, fldigi
0.23
- added delay_background() , replace almost delay() to delay_background for prevent timeout
- cat library compatible with FT-817 Command
switch VFOA / VFOB,
Read Write CW Speed
Read Write CW Delay Time
Read Write CW Pitch (with sidetone)
All of these can be controlled by Hamradio deluxe.
- modified cat libray function for protocol for CAT communication is not broken in CW or TX mode
- Ability to change CW Delay
- Added Dial Lock function
- Add functions CW Start dely (TX -> CW interval)
- Automatic storage of VFO frequency
It was implemented by storing it only once when the frequency stays 10 seconds or more after the change.
(protect eeprom life)
0.22
- fixed screen Update Problem
- Frequency Display Problem - Problems occur below 1Mhz
- added function Enhanced CAT communication
- replace ubitx_cat.ino to cat_libs.ino
- Save mode when switching to VFOA / VFOB
0.21
- fixed the cw side tone configuration.
- Fix the error that the frequency is over.
- fixed frequency display (alignment, point)
0.20
- original uBITX software (Ashhar Farhan)
## Original README.md
uBITX firmware, written for the Raduino/Arduino control of uBITX transceigers
Copyright (C) 2017, Ashhar Farhan
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"Extended" version of the uBITX v5, including both a Teensy-based DSP as well as a Nextion 3.2" display.

1496
Raduino/Raduino.ino Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
/*************************************************************************
KD8CEC's CAT Library for uBITX and HAM
This source code is written for uBITX, but it can also be used on other radios.
The CAT protocol is used by many radios to provide remote control to comptuers through
@@ -30,8 +31,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
#define printLineF1(x) (printLineF(1, x))
#define printLineF2(x) (printLineF(0, x))
#include "ubitx.h"
//for broken protocol
#define CAT_RECEIVE_TIMEOUT 500
@@ -108,7 +109,8 @@ void CatSetFreq(byte fromType)
//#define BCD_LEN 9
//PROTOCOL : 0x03
//Computer <-(frequency)-> TRCV CAT_BUFF
void CatGetFreqMode(unsigned long freq, byte fromType)
//void CatGetFreqMode(unsigned long freq, byte fromType)
void CatGetFreqMode(unsigned long freq) //for remove warning messages
{
int i;
byte tmpValue;
@@ -129,23 +131,40 @@ void CatGetFreqMode(unsigned long freq, byte fromType)
}
//Mode Check
if (isUSB)
CAT_BUFF[4] = CAT_MODE_USB;
if (cwMode == 0)
{
if (isUSB)
CAT_BUFF[4] = CAT_MODE_USB;
else
CAT_BUFF[4] = CAT_MODE_LSB;
}
else if (cwMode == 1)
{
CAT_BUFF[4] = CAT_MODE_CW;
}
else
CAT_BUFF[4] = CAT_MODE_LSB;
{
CAT_BUFF[4] = CAT_MODE_CW;
}
SendCatData(5);
}
void CatSetSplit(boolean isSplit, byte fromType)
//void CatSetSplit(boolean isSplit, byte fromType)
void CatSetSplit(boolean isSplit) //for remove warning messages
{
if (isSplit)
splitOn = 1;
else
splitOn = 0;
Serial.write(ACK);
}
void CatSetPTT(boolean isPTTOn, byte fromType)
{
if (fromType == 2 || fromType == 3) {
//
if ((!inTx) && (fromType == 2 || fromType == 3)) {
Serial.write(ACK);
return;
}
@@ -197,12 +216,18 @@ void CatSetMode(byte tmpMode, byte fromType)
if (!inTx)
{
if (tmpMode == CAT_MODE_USB)
if (tmpMode == CAT_MODE_CW)
{
cwMode = 1;
}
else if (tmpMode == CAT_MODE_USB)
{
cwMode = 0;
isUSB = true;
}
else
{
cwMode = 0;
isUSB = false;
}
@@ -214,7 +239,8 @@ void CatSetMode(byte tmpMode, byte fromType)
}
//Read EEProm by uBITX Manager Software
void ReadEEPRom(byte fromType)
//void ReadEEPRom(byte fromType)
void ReadEEPRom() //for remove warnings.
{
//5BYTES
//CAT_BUFF[0] [1] [2] [3] [4] //4 COMMAND
@@ -226,18 +252,42 @@ void ReadEEPRom(byte fromType)
Serial.write(0x02); //STX
checkSum = 0x02;
for (uint16_t i = 0; i < eepromReadLength; i++)
//I2C Scanner
//Magic Key Start 59414, Length : 48583
//if (eepromStartIndex == 59414 && eepromReadLength == 48583)
if (CAT_BUFF[0] == 0x16 && CAT_BUFF[1] == 0xe8)
{
read1Byte = EEPROM.read(eepromStartIndex + i);
checkSum += read1Byte;
Serial.write(read1Byte);
for (uint8_t i = 1; i < 127; i++)
{
Wire.beginTransmission(i);
read1Byte = Wire.endTransmission();
if (read1Byte == 0)
{
Serial.write(i);
}
else
{
Serial.write(0);
}
}
}
else
{
for (uint16_t i = 0; i < eepromReadLength; i++)
{
read1Byte = EEPROM.read(eepromStartIndex + i);
checkSum += read1Byte;
Serial.write(read1Byte);
}
}
Serial.write(checkSum);
Serial.write(ACK);
}
//Write just proecess 1byes
void WriteEEPRom(byte fromType)
//void WriteEEPRom(byte fromType)
void WriteEEPRom(void) //for remove warning
{
//5BYTES
uint16_t eepromStartIndex = CAT_BUFF[0] + CAT_BUFF[1] * 256;
@@ -251,13 +301,26 @@ void WriteEEPRom(byte fromType)
}
else
{
EEPROM.write(eepromStartIndex, write1Byte);
//Special Command
if (eepromStartIndex == 13131) //Magic Key
{
if (write1Byte == 0x51) //Restart
{
asm volatile (" jmp 0");
}
}
else
{
EEPROM.write(eepromStartIndex, write1Byte);
}
Serial.write(0x77); //OK
Serial.write(ACK);
}
}
void ReadEEPRom_FT817(byte fromType)
//void ReadEEPRom_FT817(byte fromType)
void ReadEEPRom_FT817(void) //for remove warnings
{
byte temp0 = CAT_BUFF[0];
byte temp1 = CAT_BUFF[1];
@@ -357,10 +420,21 @@ void ReadEEPRom_FT817(byte fromType)
CAT_BUFF[1] = 0xB2;
break; case 0x69 : //FM Mic (#29) Contains 0-100 (decimal) as displayed
case 0x78 :
if (isUSB)
CAT_BUFF[0] = CAT_MODE_USB;
else
CAT_BUFF[0] = CAT_MODE_LSB;
if (cwMode == 0)
{
if (isUSB)
CAT_BUFF[0] = CAT_MODE_USB;
else
CAT_BUFF[0] = CAT_MODE_LSB;
}
else if (cwMode == 1)
{
CAT_BUFF[0] = CAT_MODE_CW;
}
else if (cwMode == 2)
{
CAT_BUFF[0] = CAT_MODE_CW;
}
if (CAT_BUFF[0] != 0) CAT_BUFF[0] = 1 << 5;
break;
@@ -383,7 +457,7 @@ void ReadEEPRom_FT817(byte fromType)
//7A 6 ? ?
//7A 7 SPL On/Off 0 = Off, 1 = On
CAT_BUFF[0] = (isSplitOn ? 0xFF : 0x7F);
CAT_BUFF[0] = (splitOn ? 0xFF : 0x7F);
break;
case 0xB3 : //
CAT_BUFF[0] = 0x00;
@@ -398,7 +472,7 @@ void ReadEEPRom_FT817(byte fromType)
void WriteEEPRom_FT817(byte fromType)
{
byte temp0 = CAT_BUFF[0];
//byte temp0 = CAT_BUFF[0];
byte temp1 = CAT_BUFF[1];
CAT_BUFF[0] = 0;
@@ -470,8 +544,8 @@ void WriteEEPRom_FT817(byte fromType)
sideTone = (sideTonePitch * 50 + 300) + sideToneSub;
printLineF2(F("Sidetone set! CAT"));
EEPROM.put(CW_SIDETONE, sideTone);
delay(500);
printLine2("");
delay(300); //If timeout errors occur in the calling software, remove them
clearLine2();
}
break;
@@ -482,8 +556,9 @@ void WriteEEPRom_FT817(byte fromType)
sideTone = (sideTonePitch * 50 + 300) + sideToneSub;
printLineF2(F("Sidetone set! CAT"));
EEPROM.put(CW_SIDETONE, sideTone);
delay(500);
printLine2("");
delay(300); //If timeout errors occur in the calling software, remove them
clearLine2();
line2DisplayStatus = 0;
}
break;
@@ -502,8 +577,8 @@ void WriteEEPRom_FT817(byte fromType)
cwDelayTime = CAT_BUFF[2];
printLineF2(F("CW Speed set!"));
EEPROM.put(CW_DELAY, cwDelayTime);
delay(500);
printLine2("");
delay(300);
clearLine2();
break;
case 0x62 : //
//5-0 CW Speed (4-60 WPM) (#21) From 0 to 38 (HEX) with 0 = 4 WPM and 38 = 60 WPM (1 WPM steps)
@@ -511,8 +586,8 @@ void WriteEEPRom_FT817(byte fromType)
cwSpeed = 1200 / ((CAT_BUFF[2] & 0x3F) + 4);
printLineF2(F("CW Speed set!"));
EEPROM.put(CW_SPEED, cwSpeed);
delay(500);
printLine2("");
delay(300);
clearLine2();
break;
/*
@@ -571,9 +646,38 @@ void WriteEEPRom_FT817(byte fromType)
Serial.write(ACK);
}
void CatRxStatus(byte fromType)
const byte anlogPinIndex[6] = {A0, A1, A2, A3, A6, A7};
//Read ADC Value by uBITX Manager Software
void ReadADCValue(void)
{
byte sMeterValue = 1;
//ADC MAP for uBITX
int readedADCValue;
//5BYTES
//CAT_BUFF[0] [1] [2] [3] [4] //4 COMMAND
//0 READ ADDRESS
readedADCValue = analogRead(anlogPinIndex[CAT_BUFF[0]]);
CAT_BUFF[0] = readedADCValue >> 8;
CAT_BUFF[1] = readedADCValue;
SendCatData(2);
Serial.write(ACK);
}
void SetIFSValue(void)
{
//Set IFShift Value
isIFShift = CAT_BUFF[0];
ifShiftValue = CAT_BUFF[1] + CAT_BUFF[2] * 256;
setFrequency(frequency);
SetCarrierFreq();
updateLine2Buffer(1); //option, perhap not need
Serial.write(ACK);
}
//void CatRxStatus(byte fromType)
void CatRxStatus(void) //for remove warning
{
byte sMeterValue = 0;
/*
http://www.ka7oei.com/ft817_meow.html
@@ -586,12 +690,40 @@ void CatRxStatus(byte fromType)
Bit 7 is 0 if there is a signal present, or 1 if the receiver is squelched.
*/
// The lower 4 bits (0-3) of this byte indicate the current S-meter reading. 00 refers to an S-Zero reading, 04 = S4, 09 = S9, 0A = "10 over," 0B = "20 over" and so on up to 0F.
//0~8
switch (scaledSMeter)
{
case 8 : sMeterValue = 0x0B;
break;
case 7 : sMeterValue = 0x0A;
break;
case 6 : sMeterValue = 0x09;
break;
case 5 : sMeterValue = 0x07;
break;
case 4 : sMeterValue = 0x05;
break;
case 3 : sMeterValue = 0x04;
break;
case 2 : sMeterValue = 0x02;
break;
case 1 : sMeterValue = 0x01;
break;
}
/*
sMeterValue = (scaledSMeter * 2) -1;
if (sMeterValue > 0)
sMeterValue--;
*/
CAT_BUFF[0] = sMeterValue & 0b00001111;
SendCatData(1);
}
void CatTxStatus(byte fromType)
//void CatTxStatus(byte fromType)
void CatTxStatus(void) //for remove warning
{
boolean isHighSWR = false;
boolean isSplitOn = false;
@@ -629,7 +761,6 @@ void Check_Cat(byte fromType)
}
else if (Serial.available() < 5)
{
/*
//First Arrived
if (rxBufferCheckCount == 0)
{
@@ -649,8 +780,6 @@ void Check_Cat(byte fromType)
rxBufferCheckCount = Serial.available();
rxBufferArriveTime = millis() + CAT_RECEIVE_TIMEOUT; //Set time for timeout
}
*/
return;
}
@@ -695,11 +824,11 @@ void Check_Cat(byte fromType)
case 0x02 : //Split On
case 0x82: //Split Off
CatSetSplit(CAT_BUFF[4] == 0x02, fromType);
CatSetSplit(CAT_BUFF[4] == 0x02);
break;
case 0x03 : //Read Frequency and mode
CatGetFreqMode(frequency, fromType);
CatGetFreqMode(frequency);
break;
case 0x07 : //Set Operating Mode
@@ -716,24 +845,32 @@ void Check_Cat(byte fromType)
break;
case 0xDB: //Read uBITX EEPROM Data
ReadEEPRom(fromType); //Call by uBITX Manager Program
ReadEEPRom(); //Call by uBITX Manager Program
break;
case 0xBB: //Read FT-817 EEPROM Data (for comfirtable)
ReadEEPRom_FT817(fromType);
ReadEEPRom_FT817();
break;
case 0xDC: //Write uBITX EEPROM Data
WriteEEPRom(fromType); //Call by uBITX Manager Program
WriteEEPRom(); //Call by uBITX Manager Program
break;
case 0xBC: //Write FT-817 EEPROM Data (for comfirtable)
WriteEEPRom_FT817(fromType);
break;
case 0xDD: //Read uBITX ADC Data
ReadADCValue(); //Call by uBITX Manager Program
break;
case 0xDE: //IF-Shift Control by CAT
SetIFSValue(); //
break;
case 0xE7 : //Read RX Status
CatRxStatus(fromType);
CatRxStatus();
break;
case 0xF7: //Read TX Status
CatTxStatus(fromType);
CatTxStatus();
break;
default:
/*

View File

@@ -1,4 +1,6 @@
/*************************************************************************
KD8CEC's Memory Keyer for HAM
This source code is written for All amateur radio operator,
I have not had amateur radio communication for a long time. CW has been
around for a long time, and I do not know what kind of keyer and keying
@@ -13,6 +15,7 @@
I wrote this code myself, so there is no license restriction.
So this code allows anyone to write with confidence.
But keep it as long as the original author of the code.
DE Ian KD8CEC
-----------------------------------------------------------------------------
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -33,7 +36,7 @@
//27 + 10 + 18 + 1(SPACE) = //56
const PROGMEM uint8_t cwAZTable[27] = {0b00100100 , 0b01001000 , 0b01001010 , 0b00111000 , 0b00010000, 0b01000010, 0b00111100, 0b01000000 , //A ~ H
0b00100000, 0b01000111 ,0b00111010, 0b01000100, 0b00101100, 0b00101000 , 0b00111110, 0b01000110, 0b01001101, 0b00110100, //I ~ R
0b00110000, 0b00011000, 0b00110010, 0b01000001, 0b00110110, 0b01001001, 0b01001011, 0b00111000}; //S ~ Z
0b00110000, 0b00011000, 0b00110010, 0b01000001, 0b00110110, 0b01001001, 0b01001011, 0b01001100}; //S ~ Z
PGM_P pCwAZTable = reinterpret_cast<PGM_P>(cwAZTable);
const PROGMEM uint8_t cw09Table[27] = {0b00011111, 0b00001111, 0b00000111, 0b00000011, 0b00000001, 0b00000000, 0b00010000, 0b00011000, 0b00011100, 0b00011110};
@@ -208,10 +211,14 @@ void sendCWChar(char cwKeyChar)
charLength = ((tmpChar >> 6) & 0x03) + 3;
for (j = 0; j < charLength; j++)
sendBuff[j] = (tmpChar << j + 2) & 0x80;
sendBuff[j] = (tmpChar << (j + 2)) & 0x80;
break;
}
else
{
charLength = 0;
}
}
}
@@ -228,36 +235,12 @@ void sendCWChar(char cwKeyChar)
}
}
/*
void sendAutoCW(int cwSendLength, char *sendString)
{
byte i;
if (!inTx){
keyDown = 0;
cwTimeout = millis() + cwDelayTime * 10;
startTx(TX_CW, 0); //disable updateDisplay Command for reduce latency time
updateDisplay();
delay_background(delayBeforeCWStartTime * 2, 2);
}
for (i = 0; i < cwSendLength; i++)
{
sendCWChar(sendString[i]);
if (i != cwSendLength -1) delay_background(cwSpeed * 3, 3);
}
delay_background(cwDelayTime * 10, 2);
stopTx();
}
*/
byte isNeedScroll = 0;
unsigned long scrollDispayTime = 0;
#define scrollSpeed 500
byte displayScrolStep = 0;
int controlAutoCW(){
void controlAutoCW(){
int knob = 0;
byte i;
@@ -289,13 +272,19 @@ int controlAutoCW(){
{
displayScrolStep = 0;
}
printLineFromEEPRom(0, 2, cwStartIndex + displayScrolStep + CW_DATA_OFSTADJ, cwEndIndex + CW_DATA_OFSTADJ);
lcd.setCursor(0,0);
lcd.write(byteToChar(selectedCWTextIndex));
lcd.write(':');
#ifdef USE_SW_SERIAL
//Not need Scroll
//Display_AutoKeyTextIndex(selectedCWTextIndex);
SendCommand1Num('w', selectedCWTextIndex); //Index
SendEEPromData('a', cwStartIndex + CW_DATA_OFSTADJ, cwEndIndex + CW_DATA_OFSTADJ, 0) ; //Data
SendCommand1Num('y', 1); //Send YN
isNeedScroll = 0;
#else
printLineFromEEPRom(0, 2, cwStartIndex + displayScrolStep + CW_DATA_OFSTADJ, cwEndIndex + CW_DATA_OFSTADJ, 0);
isNeedScroll = (cwEndIndex - cwStartIndex) > 14 ? 1 : 0;
Display_AutoKeyTextIndex(selectedCWTextIndex);
#endif
scrollDispayTime = millis() + scrollSpeed;
beforeCWTextIndex = selectedCWTextIndex;
}
@@ -354,6 +343,11 @@ int controlAutoCW(){
//check interval time, if you want adjust interval between chars, modify below
if (isAutoCWHold == 0 && (millis() - autoCWbeforeTime > cwSpeed * 3))
{
if (!inTx){ //if not TX Status, change RX -> TX
keyDown = 0;
startTx(TX_CW, 0); //disable updateDisplay Command for reduce latency time
}
sendCWChar(EEPROM.read(CW_AUTO_DATA + autoCWSendCharIndex++));
if (autoCWSendCharIndex > autoCWSendCharEndIndex) { //finish auto cw send

334
Raduino/softserial_tiny.cpp Normal file
View File

@@ -0,0 +1,334 @@
/*
Softserial for Nextion LCD and Control MCU
KD8CEC, Ian Lee
-----------------------------------------------------------------------
It is a library rewritten in C format based on SoftwareSerial.c.
I tried to use as much as possible without modifying the SoftwareSerial.
But eventually I had to modify the code.
I rewrote it in C for the following reasons.
- Problems occurred when increasing Program Size and Program Memory
- We had to reduce the program size.
Of course, Software Serial is limited to one.
- reduce the steps for transmitting and receiving
useage
extern void SWSerial_Begin(long speedBaud);
extern void SWSerial_Write(uint8_t b);
extern int SWSerial_Available(void);
extern int SWSerial_Read(void);
extern void SWSerial_Print(uint8_t *b);
If you use Softwreserial library instead of this library, you can modify the code as shown below.
I kept the function name of SoftwareSerial so you only need to modify a few lines of code.
define top of source code
#include <SoftwareSerial.h>
SoftwareSerial sSerial(10, 11); // RX, TX
replace source code
SWSerial_Begin to sSerial.begin
SWSerial_Write to sSerial.write
SWSerial_Available to sSerial.available
SWSerial_Read to sSerial.read
KD8CEC, Ian Lee
-----------------------------------------------------------------------
License
All licenses for the source code are subject to the license of the original source SoftwareSerial Library.
However, if you use or modify this code, please keep the all comments in this source code.
KD8CEC
-----------------------------------------------------------------------
License from SoftwareSerial
-----------------------------------------------------------------------
SoftwareSerial.cpp (formerly NewSoftSerial.cpp) -
Multi-instance software serial library for Arduino/Wiring
-- Interrupt-driven receive and other improvements by ladyada
(http://ladyada.net)
-- Tuning, circular buffer, derivation from class Print/Stream,
multi-instance support, porting to 8MHz processors,
various optimizations, PROGMEM delay tables, inverse logic and
direct port writing by Mikal Hart (http://www.arduiniana.org)
-- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com)
-- 20MHz processor support by Garrett Mace (http://www.macetech.com)
-- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
The latest version of this library can always be found at
http://arduiniana.org.
*/
#include <Arduino.h>
//================================================================
//Public Variable
//================================================================
#define TX_PIN 9
#define RX_PIN 8
#define _SS_MAX_RX_BUFF 35 // RX buffer size
#define PRINT_MAX_LENGTH 30
//================================================================
//Internal Variable from SoftwareSerial.c and SoftwareSerial.h
//================================================================
//variable from softwareserial.c and softwareserial.h
static uint8_t swr_receive_buffer[_SS_MAX_RX_BUFF];
volatile uint8_t *_transmitPortRegister; //Write Port Register
uint8_t transmit_RegMask; //use Mask bit 1
uint8_t transmit_InvMask; //use mask bit 0
volatile uint8_t *_receivePortRegister; //Read Port Register
uint8_t _receiveBitMask;
//delay value for Bit
uint16_t _tx_delay;
//delay value for Receive
uint16_t _rx_delay_stopbit;
uint16_t _rx_delay_centering;
uint16_t _rx_delay_intrabit;
//Customize for uBITX Protocol
int8_t receiveIndex = 0;
uint8_t receivedCommandLength = 0;
int8_t ffCount = 0;
//Values for Receive Buffer
//uint16_t _buffer_overflow;
//static volatile uint8_t _receive_buffer_head;
//static volatile uint8_t _receive_buffer_tail;
//Values for Interrupt (check Start Bit)
volatile uint8_t *_pcint_maskreg;
uint8_t _pcint_maskvalue;
//================================================================
//Internal Function from SoftwareSerial.c
//================================================================
uint16_t subtract_cap(uint16_t num, uint16_t sub)
{
if (num > sub)
return num - sub;
else
return 1;
}
inline void tunedDelay(uint16_t delay)
{
_delay_loop_2(delay);
}
void setRxIntMsk(bool enable)
{
if (enable)
*_pcint_maskreg |= _pcint_maskvalue;
else
*_pcint_maskreg &= ~_pcint_maskvalue;
}
uint8_t rx_pin_read()
{
return *_receivePortRegister & _receiveBitMask;
}
//
// The receive routine called by the interrupt handler
//
void softSerail_Recv()
{
#if GCC_VERSION < 40302
// Work-around for avr-gcc 4.3.0 OSX version bug
// Preserve the registers that the compiler misses
// (courtesy of Arduino forum user *etracer*)
asm volatile(
"push r18 \n\t"
"push r19 \n\t"
"push r20 \n\t"
"push r21 \n\t"
"push r22 \n\t"
"push r23 \n\t"
"push r26 \n\t"
"push r27 \n\t"
::);
#endif
uint8_t d = 0;
// If RX line is high, then we don't see any start bit
// so interrupt is probably not for us
if (!rx_pin_read()) //Start Bit
{
// Disable further interrupts during reception, this prevents
// triggering another interrupt directly after we return, which can
// cause problems at higher baudrates.
setRxIntMsk(false);
// Wait approximately 1/2 of a bit width to "center" the sample
tunedDelay(_rx_delay_centering);
// Read each of the 8 bits
for (uint8_t i=8; i > 0; --i)
{
tunedDelay(_rx_delay_intrabit);
d >>= 1;
if (rx_pin_read())
d |= 0x80;
}
if (receivedCommandLength == 0) //check Already Command
{
//Set Received Data
swr_receive_buffer[receiveIndex++] = d;
//Finded Command
if (d == 0x73 && ffCount > 1 && receiveIndex > 6)
{
receivedCommandLength = receiveIndex;
receiveIndex = 0;
ffCount = 0;
}
else if (receiveIndex > _SS_MAX_RX_BUFF)
{
//Buffer Overflow
receiveIndex = 0;
ffCount = 0;
}
else if (d == 0xFF)
{
ffCount++;
}
else
{
ffCount = 0;
}
}
// skip the stop bit
tunedDelay(_rx_delay_stopbit);
// Re-enable interrupts when we're sure to be inside the stop bit
setRxIntMsk(true);
}
#if GCC_VERSION < 40302
// Work-around for avr-gcc 4.3.0 OSX version bug
// Restore the registers that the compiler misses
asm volatile(
"pop r27 \n\t"
"pop r26 \n\t"
"pop r23 \n\t"
"pop r22 \n\t"
"pop r21 \n\t"
"pop r20 \n\t"
"pop r19 \n\t"
"pop r18 \n\t"
::);
#endif
}
ISR(PCINT0_vect)
{
softSerail_Recv();
}
//================================================================
//Public Function from SoftwareSerial.c and modified and create
//================================================================
// Read data from buffer
void SWSerial_Read(uint8_t * receive_cmdBuffer)
{
for (int i = 0; i < receivedCommandLength; i++)
receive_cmdBuffer[i] = swr_receive_buffer[i];
}
void SWSerial_Write(uint8_t b)
{
volatile uint8_t *reg = _transmitPortRegister;
uint8_t oldSREG = SREG;
uint16_t delay = _tx_delay;
cli(); // turn off interrupts for a clean txmit
// Write the start bit
*reg &= transmit_InvMask;
tunedDelay(delay);
// Write each of the 8 bits
for (uint8_t i = 8; i > 0; --i)
{
if (b & 1) // choose bit
*reg |= transmit_RegMask; // send 1
else
*reg &= transmit_InvMask; // send 0
tunedDelay(delay);
b >>= 1;
}
// restore pin to natural state
*reg |= transmit_RegMask;
SREG = oldSREG; // turn interrupts back on
tunedDelay(_tx_delay);
}
void SWSerial_Print(uint8_t *b)
{
for (int i = 0; i < PRINT_MAX_LENGTH; i++)
{
if (b[i] == 0x00)
break;
else
SWSerial_Write(b[i]);
}
}
void SWSerial_Begin(long speedBaud)
{
//INT TX_PIN
digitalWrite(TX_PIN, HIGH);
pinMode(TX_PIN, OUTPUT);
transmit_RegMask = digitalPinToBitMask(TX_PIN); //use Bit 1
transmit_InvMask = ~digitalPinToBitMask(TX_PIN); //use Bit 0
_transmitPortRegister = portOutputRegister(digitalPinToPort(TX_PIN));
//INIT RX_PIN
pinMode(RX_PIN, INPUT);
digitalWrite(RX_PIN, HIGH); // pullup for normal logic!
_receiveBitMask = digitalPinToBitMask(RX_PIN);
_receivePortRegister = portInputRegister(digitalPinToPort(RX_PIN));
//Set Values
uint16_t bit_delay = (F_CPU / speedBaud) / 4;
_tx_delay = subtract_cap(bit_delay, 15 / 4);
if (digitalPinToPCICR(RX_PIN))
{
_rx_delay_centering = subtract_cap(bit_delay / 2, (4 + 4 + 75 + 17 - 23) / 4);
_rx_delay_intrabit = subtract_cap(bit_delay, 23 / 4);
_rx_delay_stopbit = subtract_cap(bit_delay * 3 / 4, (37 + 11) / 4);
*digitalPinToPCICR(RX_PIN) |= _BV(digitalPinToPCICRbit(RX_PIN));
_pcint_maskreg = digitalPinToPCMSK(RX_PIN);
_pcint_maskvalue = _BV(digitalPinToPCMSKbit(RX_PIN));
tunedDelay(_tx_delay); // if we were low this establishes the end
}
//Start Listen
setRxIntMsk(true);
}

335
Raduino/ubitx.h Normal file
View File

@@ -0,0 +1,335 @@
/*************************************************************************
header file for C++ by KD8CEC
-----------------------------------------------------------------------------
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
#ifndef _UBITX_HEADER__
#define _UBITX_HEADER__
#include <Arduino.h> //for Linux, On Linux it is case sensitive.
//==============================================================================
// Compile Option
//==============================================================================
//Ubitx Board Version
#define UBITX_BOARD_VERSION 2 //v1 ~ v4 : 4, v5: 5
//Depending on the type of LCD mounted on the uBITX, uncomment one of the options below.
//You must select only one.
//#define UBITX_DISPLAY_LCD1602P //LCD mounted on unmodified uBITX (Parallel)
//#define UBITX_DISPLAY_LCD1602I //I2C type 16 x 02 LCD
//#define UBITX_DISPLAY_LCD1602I_DUAL //I2C type 16 x02 LCD Dual
//#define UBITX_DISPLAY_LCD2004P //24 x 04 LCD (Parallel)
//#define UBITX_DISPLAY_LCD2004I //I2C type 24 x 04 LCD
#define UBITX_DISPLAY_NEXTION //NEXTION LCD
//#define UBITX_DISPLAY_NEXTION_SAFE //Only EEProm Write 770~775
#define I2C_LCD_MASTER_ADDRESS_DEFAULT 0x27 //0x27 //DEFAULT, if Set I2C Address by uBITX Manager, read from EEProm
#define I2C_LCD_SECOND_ADDRESS_DEFAULT 0x3F //0x27 //only using Dual LCD Mode
//Select betwen Analog S-Meter and DSP (I2C) Meter
#define USE_I2CSMETER
#define EXTEND_KEY_GROUP1 //MODE, BAND(-), BAND(+), STEP
//#define EXTEND_KEY_GROUP2 //Numeric (0~9), Point(.), Enter //Not supported in Version 1.0x
//Custom LPF Filter Mod
//#define USE_CUSTOM_LPF_FILTER //LPF FILTER MOD
//#define ENABLE_FACTORYALIGN
#define FACTORY_RECOVERY_BOOTUP //Whether to enter Factory Recovery mode by pressing FKey and turning on power
#define ENABLE_ADCMONITOR //Starting with Version 1.07, you can read ADC values directly from uBITX Manager. So this function is not necessary.
extern byte I2C_LCD_MASTER_ADDRESS; //0x27 //if Set I2C Address by uBITX Manager, read from EEProm
extern byte I2C_LCD_SECOND_ADDRESS; //only using Dual LCD Mode
#define SMeterLatency 3 //1 is 0.25 sec
//==============================================================================
// User Select feather list
//==============================================================================
//Enable all features
#define FN_BAND 1 //592
#define FN_VFO_TOGGLE 1 //78
#define FN_MODE 1 //20
#define FN_RIT 1 //58
#define FN_SPLIT 1 //62
#define FN_IFSHIFT 1 //238
#define FN_ATT 1 //128
#define FN_CW_SPEED 1 //152
#define FN_VFOTOMEM 1 //254
#define FN_MEMTOVFO 1 //188
#define FN_MEMORYKEYER 1 //156
#define FN_WSPR 1 //1044
#define FN_SDRMODE 1 //68
#define FN_CALIBRATION 1 //666
#define FN_CARRIER 1 //382
#define FN_CWCARRIER 1 //346
#define FN_CWTONE 1 //148
#define FN_CWDELAY 1 //98
#define FN_TXCWDELAY 1 //94
#define FN_KEYTYPE 1 //168
#define FN_ADCMONITOR 1 //516
#define FN_TXONOFF 1 //58
/*
//Test Configuration (88%)
#define FN_BAND 0 //592
#define FN_VFO_TOGGLE 0 //78
#define FN_MODE 0 //20
#define FN_RIT 0 //58
#define FN_SPLIT 0 //62
#define FN_IFSHIFT 0 //238
#define FN_ATT 0 //128
#define FN_CW_SPEED 1 //152
#define FN_VFOTOMEM 0 //254
#define FN_MEMTOVFO 0 //188
#define FN_MEMORYKEYER 1 //156
#define FN_WSPR 0 //1044
#define FN_SDRMODE 1 //68
#define FN_CALIBRATION 1 //666
#define FN_CARRIER 1 //382
#define FN_CWCARRIER 1 //346
#define FN_CWTONE 1 //148
#define FN_CWDELAY 1 //98
#define FN_TXCWDELAY 1 //94
#define FN_KEYTYPE 1 //168
#define FN_ADCMONITOR 1 //516
#define FN_TXONOFF 1 //58
*/
/*
//Recommended Character LCD Developer 87%
#define FN_BAND 1 //592
#define FN_VFO_TOGGLE 1 //78
#define FN_MODE 1 //20
#define FN_RIT 1 //58
#define FN_SPLIT 1 //62
#define FN_IFSHIFT 1 //238
#define FN_ATT 0 //128
#define FN_CW_SPEED 0 //152 //using MM
#define FN_VFOTOMEM 1 //254
#define FN_MEMTOVFO 1 //188
#define FN_MEMORYKEYER 1 //156
#define FN_WSPR 1 //1044
#define FN_SDRMODE 1 //68
#define FN_CALIBRATION 0 //667 //using MM
#define FN_CARRIER 0 //382 //using MM
#define FN_CWCARRIER 0 //346 //using MM
#define FN_CWTONE 0 //148 //using MM
#define FN_CWDELAY 0 //98 //using MM
#define FN_TXCWDELAY 0 //94 //using MM
#define FN_KEYTYPE 0 //168 //using MM
#define FN_ADCMONITOR 0 //516 //using MM
#define FN_TXONOFF 1 //58
*/
/*
//Recommended for Nextion, TJC LCD 88%
#define FN_BAND 1 //600
#define FN_VFO_TOGGLE 1 //90
#define FN_MODE 1 //318
#define FN_RIT 1 //62
#define FN_SPLIT 1 //2
#define FN_IFSHIFT 1 //358
#define FN_ATT 1 //250
#define FN_CW_SPEED 0 //286
#define FN_VFOTOMEM 0 //276
#define FN_MEMTOVFO 0 //234
#define FN_MEMORYKEYER 1 //168
#define FN_WSPR 1 //1130
#define FN_SDRMODE 1 //70
#define FN_CALIBRATION 0 //790
#define FN_CARRIER 0 //500
#define FN_CWCARRIER 0 //464
#define FN_CWTONE 0 //158
#define FN_CWDELAY 0 //108
#define FN_TXCWDELAY 0 //106
#define FN_KEYTYPE 0 //294
#define FN_ADCMONITOR 0 //526 //not available with Nextion or Serial UI
#define FN_TXONOFF 1 //70
*/
//==============================================================================
// End of User Select Mode and Compil options
//==============================================================================
#ifdef UBITX_DISPLAY_LCD1602I
#define USE_I2C_LCD
#elif defined(UBITX_DISPLAY_LCD1602I_DUAL)
#define USE_I2C_LCD
#elif defined(UBITX_DISPLAY_LCD2004I)
#define USE_I2C_LCD
#endif
#ifdef UBITX_DISPLAY_NEXTION
#define USE_SW_SERIAL
#undef ENABLE_ADCMONITOR
#undef FACTORY_RECOVERY_BOOTUP
#elif defined(UBITX_CONTROL_MCU)
#define USE_SW_SERIAL
#undef ENABLE_ADCMONITOR
#undef FACTORY_RECOVERY_BOOTUP
#endif
//==============================================================================
// Hardware, Define PIN Usage
//==============================================================================
/**
* We need to carefully pick assignment of pin for various purposes.
* There are two sets of completely programmable pins on the Raduino.
* First, on the top of the board, in line with the LCD connector is an 8-pin connector
* that is largely meant for analog inputs and front-panel control. It has a regulated 5v output,
* ground and six pins. Each of these six pins can be individually programmed
* either as an analog input, a digital input or a digital output.
* The pins are assigned as follows (left to right, display facing you):
* Pin 1 (Violet), A7, SPARE => Analog S-Meter
* Pin 2 (Blue), A6, KEYER (DATA)
* Pin 3 (Green), +5v
* Pin 4 (Yellow), Gnd
* Pin 5 (Orange), A3, PTT
* Pin 6 (Red), A2, F BUTTON
* Pin 7 (Brown), A1, ENC B
* Pin 8 (Black), A0, ENC A
*Note: A5, A4 are wired to the Si5351 as I2C interface
* *
* Though, this can be assigned anyway, for this application of the Arduino, we will make the following
* assignment
* A2 will connect to the PTT line, which is the usually a part of the mic connector
* A3 is connected to a push button that can momentarily ground this line. This will be used for RIT/Bandswitching, etc.
* A6 is to implement a keyer, it is reserved and not yet implemented
* A7 is connected to a center pin of good quality 100K or 10K linear potentiometer with the two other ends connected to
* ground and +5v lines available on the connector. This implments the tuning mechanism
*/
#define ENC_A (A0)
#define ENC_B (A1)
#define FBUTTON (A2)
#define PTT (A3)
#define ANALOG_KEYER (A6)
#define ANALOG_SPARE (A7)
#define ANALOG_SMETER (A7) //by KD8CEC
/**
* 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.
* This assignment is as follows :
* Pin 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
* GND +5V CLK2 GND GND CLK1 GND GND CLK0 GND D2 D3 D4 D5 D6 D7
* These too are flexible with what you may do with them, for the Raduino, we use them to :
* - TX_RX line : Switches between Transmit and Receive after sensing the PTT or the morse keyer
* - CW_KEY line : turns on the carrier for CW
*/
#define TX_RX (7) //Relay
#define CW_TONE (6)
#define TX_LPF_A (5) //Relay
#define TX_LPF_B (4) //Relay
#define TX_LPF_C (3) //Relay
#define CW_KEY (2)
//******************************************************
//DSP (I2C) Meter
//******************************************************
//S-Meter Address
#define I2CMETER_ADDR 0x58
//VALUE TYPE============================================
//Signal
#define I2CMETER_CALCS 0x59 //Calculated Signal Meter
#define I2CMETER_UNCALCS 0x58 //Uncalculated Signal Meter
//Power
#define I2CMETER_CALCP 0x57 //Calculated Power Meter
#define I2CMETER_UNCALCP 0x56 //UnCalculated Power Meter
//SWR
#define I2CMETER_CALCR 0x55 //Calculated SWR Meter
#define I2CMETER_UNCALCR 0x54 //Uncalculated SWR Meter
//==============================================================================
// for public, Variable, functions
//==============================================================================
#define WSPR_BAND_COUNT 3
#define TX_SSB 0
#define TX_CW 1
#define printLineF1(x) (printLineF(1, x))
#define printLineF2(x) (printLineF(0, x))
//0x00 : None, 0x01 : MODE, 0x02:BAND+, 0x03:BAND-, 0x04:TUNE_STEP, 0x05:VFO Toggle, 0x06:SplitOn/Off, 0x07:TX/ON-OFF, 0x08:SDR Mode On / Off, 0x09:Rit Toggle
#define FUNCTION_KEY_ADC 80 //MODE, BAND(-), BAND(+), STEP
#define FKEY_PRESS 0x78
#define FKEY_MODE 0x01
#define FKEY_BANDUP 0x02
#define FKEY_BANDDOWN 0x03
#define FKEY_STEP 0x04
#define FKEY_VFOCHANGE 0x05
#define FKEY_SPLIT 0x06
#define FKEY_TXOFF 0x07
#define FKEY_SDRMODE 0x08
#define FKEY_RIT 0x09
#define FKEY_ENTER 0x0A
#define FKEY_POINT 0x0B
#define FKEY_DELETE 0x0C
#define FKEY_CANCEL 0x0D
#define FKEY_NUM0 0x10
#define FKEY_NUM1 0x11
#define FKEY_NUM2 0x12
#define FKEY_NUM3 0x13
#define FKEY_NUM4 0x14
#define FKEY_NUM5 0x15
#define FKEY_NUM6 0x16
#define FKEY_NUM7 0x17
#define FKEY_NUM8 0x18
#define FKEY_NUM9 0x19
#define FKEY_TYPE_MAX 0x1F
extern uint8_t SI5351BX_ADDR; //change typical -> variable at Version 1.097, address read from eeprom, default value is 0x60
//EEProm Address : 63
extern unsigned long frequency;
extern byte WsprMSGCount;
extern byte sMeterLevels[9];
extern int currentSMeter; //ADC Value for S.Meter
extern byte scaledSMeter; //Calculated S.Meter Level
extern byte KeyValues[16][3]; //Set : Start Value, End Value, Key Type, 16 Set (3 * 16 = 48)
extern byte TriggerBySW; //Action Start from Nextion LCD, Other MCU
extern void printLine1(const char *c);
extern void printLine2(const char *c);
extern void printLineF(char linenmbr, const __FlashStringHelper *c);
extern void printLineFromEEPRom(char linenmbr, char lcdColumn, byte eepromStartIndex, byte eepromEndIndex, char offsetType);
extern byte delay_background(unsigned delayTime, byte fromType);
extern int btnDown(void);
extern char c[30];
extern char b[30];
extern int enc_read(void);
extern void si5351bx_init(void);
extern void si5351bx_setfreq(uint8_t clknum, uint32_t fout);
extern void si5351_set_calibration(int32_t cal);
extern void initOscillators(void);
extern void Set_WSPR_Param(void);
extern void TXSubFreq(unsigned long P2);
extern void startTx(byte txMode, byte isDisplayUpdate);
extern void stopTx(void);
extern void setTXFilters(unsigned long freq);
extern void SendWSPRManage(void);
extern char byteToChar(byte srcByte);
extern void DisplayCallsign(byte callSignLength);
extern void DisplayVersionInfo(const char* fwVersionInfo);
//I2C Signal Meter, Version 1.097
extern int GetI2CSmeterValue(int valueType); //ubitx_ui.ino
#endif //end of if header define

152
Raduino/ubitx_eemap.h Normal file
View File

@@ -0,0 +1,152 @@
/*************************************************************************
header file for EEProm Address Map by KD8CEC
It must be protected to protect the factory calibrated calibration.
-----------------------------------------------------------------------------
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
#ifndef _UBITX_EEPOM_HEADER__
#define _UBITX_EEPOM_HEADER__
//==============================================================================
// Factory-shipped EEProm address
// (factory Firmware)
// Address : 0 ~ 31
//==============================================================================
#define MASTER_CAL 0
#define LSB_CAL 4
#define USB_CAL 8
#define SIDE_TONE 12
//these are ids of the vfos as well as their offset into the eeprom storage, don't change these 'magic' values
#define VFO_A 16
#define VFO_B 20
#define CW_SIDETONE 24
#define CW_SPEED 28
//==============================================================================
// The spare space available in the original firmware #1
// Address : 32 ~ 62
//==============================================================================
#define RESERVE_FOR_FACTORY1 32
//==============================================================================
// custom LPF Filter
// 48 : Using Custom LPF Filter (48 = 0x57 or 0x58 => Using Custom LPF Filter, 0x58 = using A7 IO
// 49, 50 : LPF1 (49 : MHz (~ Mhz), 50 : Enabled PIN
// 51, 52 : LPF2
// 53, 54 : LPF3
// 55, 56 : LPF4
// 57, 58 : LPF5
// 59, 60 : LPF6
// 61, 62 : LPF7
//==============================================================================
#define CUST_LPF_ENABLED 48
#define CUST_LPF_START 49
//SI5351 I2C Address (Version 1.097)
#define I2C_ADDR_SI5351 63
//==============================================================================
// The spare space available in the original firmware #2
// (Enabled if the EEProm address is insufficient)
// Address : 64 ~ 100
//==============================================================================
#define RESERVE_FOR_FACTORY2 64 //use Factory backup from Version 1.075
#define FACTORY_BACKUP_YN 64 //Check Backup //Magic : 0x13
#define FACTORY_VALUES 65 //65 ~ 65 + 32
//==============================================================================
// KD8CEC EEPROM MAP
// Address : 101 ~ 1023
// 256 is the base address
// 256 ~ 1023 (EEProm Section #1)
// 255 ~ 101 (EEProm Section #2)
//==============================================================================
//0x00 : None, 0x01 : MODE, 0x02:BAND+, 0x03:BAND-, 0x04:TUNE_STEP, 0x05:VFO Toggle, 0x06:SplitOn/Off, 0x07:TX/ON-OFF, 0x08:SDR Mode On / Off, 0x09:Rit Toggle
#define EXTENDED_KEY_RANGE 140 //Extended Key => Set : Start Value, End Value, Key Type, 16 Set (3 * 16 = 48)
#define I2C_LCD_MASTER 190
#define I2C_LCD_SECOND 191
#define S_METER_LEVELS 230 //LEVEL0 ~ LEVEL7
#define ADVANCED_FREQ_OPTION1 240 //Bit0: use IFTune_Value, Bit1 : use Stored enabled SDR Mode, Bit2 : dynamic sdr frequency
#define IF1_CAL 241
#define ENABLE_SDR 242
#define SDR_FREQUNCY 243
#define CW_CAL 252
#define VFO_A_MODE 256
#define VFO_B_MODE 257
#define CW_DELAY 258
#define CW_START 259
#define HAM_BAND_COUNT 260 //
#define TX_TUNE_TYPE 261 //
#define HAM_BAND_RANGE 262 //FROM (2BYTE) TO (2BYTE) * 10 = 40byte
#define HAM_BAND_FREQS 302 //40, 1 BAND = 4Byte most bit is mode
#define TUNING_STEP 342 //TUNING STEP * 6 (index 1 + STEPS 5) //1STEP :
//for reduce cw key error, eeprom address
#define CW_ADC_MOST_BIT1 348 //most 2bits of DOT_TO , DOT_FROM, ST_TO, ST_FROM
#define CW_ADC_ST_FROM 349 //CW ADC Range STRAIGHT KEY from (Lower 8 bit)
#define CW_ADC_ST_TO 350 //CW ADC Range STRAIGHT KEY to (Lower 8 bit)
#define CW_ADC_DOT_FROM 351 //CW ADC Range DOT from (Lower 8 bit)
#define CW_ADC_DOT_TO 352 //CW ADC Range DOT to (Lower 8 bit)
#define CW_ADC_MOST_BIT2 353 //most 2bits of BOTH_TO, BOTH_FROM, DASH_TO, DASH_FROM
#define CW_ADC_DASH_FROM 354 //CW ADC Range DASH from (Lower 8 bit)
#define CW_ADC_DASH_TO 355 //CW ADC Range DASH to (Lower 8 bit)
#define CW_ADC_BOTH_FROM 356 //CW ADC Range BOTH from (Lower 8 bit)
#define CW_ADC_BOTH_TO 357 //CW ADC Range BOTH to (Lower 8 bit)
#define CW_KEY_TYPE 358
#define CW_DISPLAY_SHIFT 359 //Transmits on CWL, CWU Mode, LCD Frequency shifts Sidetone Frequency.
//(7:Enable / Disable //0: enable, 1:disable, (default is applied shift)
//6 : 0 : Adjust Pulus, 1 : Adjust Minus
//0~5: Adjust Value : * 10 = Adjust Value (0~300)
#define COMMON_OPTION0 360 //0: Confirm : CW Frequency Shift
//1 : IF Shift Save
#define IF_SHIFTVALUE 363
#define DISPLAY_OPTION1 361 //Display Option1
#define DISPLAY_OPTION2 362 //Display Option2
#define WSPR_COUNT 443 //WSPR_MESSAGE_COUNT
#define WSPR_MESSAGE1 444 //
#define WSPR_MESSAGE2 490 //
#define WSPR_MESSAGE3 536 //
#define WSPR_MESSAGE4 582 //
#define CHANNEL_FREQ 630 //Channel 1 ~ 20, 1 Channel = 4 bytes
#define CHANNEL_DESC 710 //Channel 1 ~ 20, 1 Channel = 4 bytes
#define EXTERNAL_DEVICE_OPT1 770 //for External Deivce 4byte
#define EXTERNAL_DEVICE_OPT2 774 //for External Deivce 2byte
//Check Firmware type and version
#define FIRMWAR_ID_ADDR 776 //776 : 0x59, 777 :0x58, 778 : 0x68 : Id Number, if not found id, erase eeprom(32~1023) for prevent system error.
#define VERSION_ADDRESS 779 //check Firmware version
//USER INFORMATION
#define USER_CALLSIGN_KEY 780 //0x59
#define USER_CALLSIGN_LEN 781 //1BYTE (OPTION + LENGTH) + CALLSIGN (MAXIMUM 18)
#define USER_CALLSIGN_DAT 782 //CALL SIGN DATA //direct EEPROM to LCD basic offset
//AUTO KEY STRUCTURE
//AUTO KEY USE 800 ~ 1023
#define CW_AUTO_MAGIC_KEY 800 //0x73
#define CW_AUTO_COUNT 801 //0 ~ 255
#define CW_AUTO_DATA 803 //[INDEX, INDEX, INDEX,DATA,DATA, DATA (Positon offset is CW_AUTO_DATA
#define CW_DATA_OFSTADJ CW_AUTO_DATA - USER_CALLSIGN_DAT //offset adjust for ditect eeprom to lcd (basic offset is USER_CALLSIGN_DAT
#define CW_STATION_LEN 1023 //value range : 4 ~ 30
#endif //end of if header define

View File

@@ -1,3 +1,4 @@
#include "ubitx.h"
/**
* This procedure is only for those who have a signal generator/transceiver tuned to exactly 7.150 and a dummy load
@@ -14,6 +15,7 @@ void btnWaitForClick(){
void factory_alignment(){
factoryCalibration(1);
line2DisplayStatus = 1;
if (calibration == 0){
printLine2("Setup Aborted");
@@ -26,16 +28,28 @@ void factory_alignment(){
printLine2("#2 BFO");
delay(1000);
#if UBITX_BOARD_VERSION == 5
usbCarrier = 11053000l;
menuSetupCarrier(1);
if (usbCarrier == 11053000l){
printLine2("Setup Aborted");
return;
}
#else
usbCarrier = 11994999l;
menuSetupCarrier(1);
if (usbCarrier == 11994999l){
printLine2("Setup Aborted");
return;
}
#endif
printLine2("#3:Test 3.5MHz");
cwMode = 0;
isUSB = false;
setFrequency(3500000l);
updateDisplay();
@@ -58,6 +72,7 @@ void factory_alignment(){
btnWaitForClick();
printLine2("#5:Test 14MHz");
cwMode = 0;
isUSB = true;
setFrequency(14000000l);
updateDisplay();
@@ -79,9 +94,9 @@ void factory_alignment(){
printLine2("Alignment done");
delay(1000);
cwMode = 0;
isUSB = false;
setFrequency(7150000l);
updateDisplay();
}

369
Raduino/ubitx_keyer.ino Normal file
View File

@@ -0,0 +1,369 @@
/**
CW Keyer
CW Key logic change with ron's code (ubitx_keyer.cpp)
Ron's logic has been modified to work with the original uBITX by KD8CEC
Original Comment ----------------------------------------------------------------------------
* The CW keyer handles either a straight key or an iambic / paddle key.
* They all use just one analog input line. This is how it works.
* The analog line has the internal pull-up resistor enabled.
* When a straight key is connected, it shorts the pull-up resistor, analog input is 0 volts
* When a paddle is connected, the dot and the dash are connected to the analog pin through
* a 10K and a 2.2K resistors. These produce a 4v and a 2v input to the analog pins.
* So, the readings are as follows :
* 0v - straight key
* 1-2.5 v - paddle dot
* 2.5 to 4.5 v - paddle dash
* 2.0 to 0.5 v - dot and dash pressed
*
* The keyer is written to transparently handle all these cases
*
* Generating CW
* The CW is cleanly generated by unbalancing the front-end mixer
* and putting the local oscillator directly at the CW transmit frequency.
* The sidetone, generated by the Arduino is injected into the volume control
*/
// in milliseconds, this is the parameter that determines how long the tx will hold between cw key downs
//#define CW_TIMEOUT (600l) //Change to CW Delaytime for value save to eeprom
#define PADDLE_DOT 1
#define PADDLE_DASH 2
#define PADDLE_BOTH 3
#define PADDLE_STRAIGHT 4
//we store the last padde's character
//to alternatively send dots and dashes
//when both are simultaneously pressed
char lastPaddle = 0;
//reads the analog keyer pin and reports the paddle
byte getPaddle(){
int paddle = analogRead(ANALOG_KEYER);
if (paddle > 800) // above 4v is up
return 0;
if (paddle > 600) // 4-3v is dot
return PADDLE_DASH;
else if (paddle > 300) //1-2v is dash
return PADDLE_DOT;
else if (paddle > 50)
return PADDLE_BOTH; //both are between 1 and 2v
else
return PADDLE_STRAIGHT; //less than 1v is the straight key
}
/**
* Starts transmitting the carrier with the sidetone
* It assumes that we have called cwTxStart and not called cwTxStop
* each time it is called, the cwTimeOut is pushed further into the future
*/
void cwKeydown(){
keyDown = 1; //tracks the CW_KEY
tone(CW_TONE, (int)sideTone);
digitalWrite(CW_KEY, 1);
//Modified by KD8CEC, for CW Delay Time save to eeprom
//cwTimeout = millis() + CW_TIMEOUT;
cwTimeout = millis() + cwDelayTime * 10;
}
/**
* Stops the cw carrier transmission along with the sidetone
* Pushes the cwTimeout further into the future
*/
void cwKeyUp(){
keyDown = 0; //tracks the CW_KEY
noTone(CW_TONE);
digitalWrite(CW_KEY, 0);
//Modified by KD8CEC, for CW Delay Time save to eeprom
//cwTimeout = millis() + CW_TIMEOUT;
cwTimeout = millis() + cwDelayTime * 10;
}
//Variables for Ron's new logic
#define DIT_L 0x01 // DIT latch
#define DAH_L 0x02 // DAH latch
#define DIT_PROC 0x04 // DIT is being processed
#define PDLSWAP 0x08 // 0 for normal, 1 for swap
#define IAMBICB 0x10 // 0 for Iambic A, 1 for Iambic B
enum KSTYPE {IDLE, CHK_DIT, CHK_DAH, KEYED_PREP, KEYED, INTER_ELEMENT };
static unsigned long ktimer;
unsigned char keyerState = IDLE;
//Below is a test to reduce the keying error. do not delete lines
//create by KD8CEC for compatible with new CW Logic
char update_PaddleLatch(byte isUpdateKeyState) {
unsigned char tmpKeyerControl = 0;
int paddle = analogRead(ANALOG_KEYER);
if (paddle >= cwAdcDashFrom && paddle <= cwAdcDashTo)
tmpKeyerControl |= DAH_L;
else if (paddle >= cwAdcDotFrom && paddle <= cwAdcDotTo)
tmpKeyerControl |= DIT_L;
else if (paddle >= cwAdcBothFrom && paddle <= cwAdcBothTo)
tmpKeyerControl |= (DAH_L | DIT_L) ;
else
{
if (Iambic_Key)
tmpKeyerControl = 0 ;
else if (paddle >= cwAdcSTFrom && paddle <= cwAdcSTTo)
tmpKeyerControl = DIT_L ;
else
tmpKeyerControl = 0 ;
}
if (isUpdateKeyState == 1)
keyerControl |= tmpKeyerControl;
return tmpKeyerControl;
}
/*****************************************************************************
// New logic, by RON
// modified by KD8CEC
******************************************************************************/
void cwKeyer(void){
lastPaddle = 0;
bool continue_loop = true;
unsigned tmpKeyControl = 0;
if( Iambic_Key ) {
while(continue_loop) {
switch (keyerState) {
case IDLE:
tmpKeyControl = update_PaddleLatch(0);
if ( tmpKeyControl == DAH_L || tmpKeyControl == DIT_L ||
tmpKeyControl == (DAH_L | DIT_L) || (keyerControl & 0x03)) {
update_PaddleLatch(1);
keyerState = CHK_DIT;
}else{
if (0 < cwTimeout && cwTimeout < millis()){
cwTimeout = 0;
stopTx();
}
continue_loop = false;
}
break;
case CHK_DIT:
if (keyerControl & DIT_L) {
keyerControl |= DIT_PROC;
ktimer = cwSpeed;
keyerState = KEYED_PREP;
}else{
keyerState = CHK_DAH;
}
break;
case CHK_DAH:
if (keyerControl & DAH_L) {
ktimer = cwSpeed*3;
keyerState = KEYED_PREP;
}else{
keyerState = IDLE;
}
break;
case KEYED_PREP:
//modified KD8CEC
/*
ktimer += millis(); // set ktimer to interval end time
keyerControl &= ~(DIT_L + DAH_L); // clear both paddle latch bits
keyerState = KEYED; // next state
if (!inTx){
//DelayTime Option
delay_background(delayBeforeCWStartTime * 2, 2);
keyDown = 0;
cwTimeout = millis() + cwDelayTime * 10; //+ CW_TIMEOUT;
startTx(TX_CW, 1);
}
*/
if (!inTx){
//DelayTime Option
delay_background(delayBeforeCWStartTime * 2, 2);
keyDown = 0;
cwTimeout = millis() + cwDelayTime * 10; //+ CW_TIMEOUT;
startTx(TX_CW, 1);
}
ktimer += millis(); // set ktimer to interval end time
keyerControl &= ~(DIT_L + DAH_L); // clear both paddle latch bits
keyerState = KEYED; // next state
cwKeydown();
break;
case KEYED:
if (millis() > ktimer) { // are we at end of key down ?
cwKeyUp();
ktimer = millis() + cwSpeed; // inter-element time
keyerState = INTER_ELEMENT; // next state
}else if (keyerControl & IAMBICB) {
update_PaddleLatch(1); // early paddle latch in Iambic B mode
}
break;
case INTER_ELEMENT:
// Insert time between dits/dahs
update_PaddleLatch(1); // latch paddle state
if (millis() > ktimer) { // are we at end of inter-space ?
if (keyerControl & DIT_PROC) { // was it a dit or dah ?
keyerControl &= ~(DIT_L + DIT_PROC); // clear two bits
keyerState = CHK_DAH; // dit done, check for dah
}else{
keyerControl &= ~(DAH_L); // clear dah latch
keyerState = IDLE; // go idle
}
}
break;
}
Check_Cat(2);
} //end of while
}
else{
while(1){
if (update_PaddleLatch(0) == DIT_L) {
// if we are here, it is only because the key is pressed
if (!inTx){
//DelayTime Option
delay_background(delayBeforeCWStartTime * 2, 2);
keyDown = 0;
cwTimeout = millis() + cwDelayTime * 10; //+ CW_TIMEOUT;
startTx(TX_CW, 1);
}
cwKeydown();
while ( update_PaddleLatch(0) == DIT_L )
delay_background(1, 3);
cwKeyUp();
}
else{
if (0 < cwTimeout && cwTimeout < millis()){
cwTimeout = 0;
keyDown = 0;
stopTx();
}
//if (!cwTimeout) //removed by KD8CEC
// return;
// got back to the beginning of the loop, if no further activity happens on straight key
// we will time out, and return out of this routine
//delay(5);
//delay_background(5, 3); //removed by KD8CEC
//continue; //removed by KD8CEC
return; //Tx stop control by Main Loop
}
Check_Cat(2);
} //end of while
} //end of elese
}
//=======================================================================================
//Before logic
//by Farhan and modified by KD8CEC
//======================================================================================
/**
* The keyer handles the straight key as well as the iambic key
* This module keeps looping until the user stops sending cw
* if the cwTimeout is set to 0, then it means, we have to exit the keyer loop
* Each time the key is hit the cwTimeout is pushed to a time in the future by cwKeyDown()
*/
/*
void cwKeyer(){
byte paddle;
lastPaddle = 0;
while(1){
paddle = getPaddle();
// do nothing if the paddle has not been touched, unless
// we are in the cw mode and we have timed out
if (!paddle){
//modifed by KD8CEC for auto CW Send
if (isCWAutoMode > 1) //if while auto cw sending, dont stop tx by paddle position
return;
if (0 < cwTimeout && cwTimeout < millis()){
cwTimeout = 0;
keyDown = 0;
stopTx();
}
if (!cwTimeout)
return;
Check_Cat(2); //for uBITX on Raspberry pi, when straight keying, disconnect / test complete
continue;
}
//if while auto cw send, stop auto cw
//but isAutoCWHold for Manual Keying with cwAutoSend
if (isCWAutoMode > 1 && isAutoCWHold == 0)
isCWAutoMode = 1; //read status
//Remoark Debug code / Serial Use by CAT Protocol
//Serial.print("paddle:");Serial.println(paddle);
// if we are here, it is only because the key or the paddle is pressed
if (!inTx){
keyDown = 0;
//Modified by KD8CEC, for CW Delay Time save to eeprom
//cwTimeout = millis() + CW_TIMEOUT;
cwTimeout = millis() + cwDelayTime * 10;
startTx(TX_CW, 0); //disable updateDisplay Command for reduce latency time
updateDisplay();
//DelayTime Option
delay_background(delayBeforeCWStartTime * 2, 2);
}
// star the transmission)
// we store the transmitted character in the lastPaddle
cwKeydown();
if (paddle == PADDLE_DOT){
//delay(cwSpeed);
delay_background(cwSpeed, 3);
lastPaddle = PADDLE_DOT;
}
else if (paddle == PADDLE_DASH){
//delay(cwSpeed * 3);
delay_background(cwSpeed * 3, 3);
lastPaddle = PADDLE_DASH;
}
else if (paddle == PADDLE_BOTH){ //both paddles down
//depending upon what was sent last, send the other
if (lastPaddle == PADDLE_DOT) {
//delay(cwSpeed * 3);
delay_background(cwSpeed * 3, 3);
lastPaddle = PADDLE_DASH;
}else{
//delay(cwSpeed);
delay_background(cwSpeed, 3);
lastPaddle = PADDLE_DOT;
}
}
else if (paddle == PADDLE_STRAIGHT){
while (getPaddle() == PADDLE_STRAIGHT) {
delay(1);
Check_Cat(2);
}
lastPaddle = PADDLE_STRAIGHT;
}
cwKeyUp();
//introduce a dot long gap between characters if the keyer was used
if (lastPaddle != PADDLE_STRAIGHT)
delay(cwSpeed);
}
}
*/

64
Raduino/ubitx_lcd.h Normal file
View File

@@ -0,0 +1,64 @@
/*************************************************************************
header file for LCD by KD8CEC
-----------------------------------------------------------------------------
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
#ifndef _UBITX_LCD_HEADER__
#define _UBITX_LCD_HEADER__
//Common Defines *********************************************************
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// flags for display entry mode
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// flags for display on/off control
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// flags for display/cursor shift
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// flags for function set
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
// flags for backlight control
#define LCD_BACKLIGHT 0x08
#define LCD_NOBACKLIGHT 0x00
#endif //end of if header define

790
Raduino/ubitx_lcd_1602.ino Normal file
View File

@@ -0,0 +1,790 @@
/*************************************************************************
KD8CEC's uBITX Display Routine for LCD1602 Parrel
1.This is the display code for the default LCD mounted in uBITX.
2.Some functions moved from uBITX_Ui.
-----------------------------------------------------------------------------
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
#include "ubitx.h"
#include "ubitx_lcd.h"
//========================================================================
//Begin of TinyLCD Library by KD8CEC
//========================================================================
#ifdef UBITX_DISPLAY_LCD1602P
/*************************************************************************
LCD1602_TINY Library for 16 x 2 LCD
Referecnce Source : LiquidCrystal.cpp
KD8CEC
This source code is modified version for small program memory
from Arduino LiquidCrystal Library
I wrote this code myself, so there is no license restriction.
So this code allows anyone to write with confidence.
But keep it as long as the original author of the code.
DE Ian KD8CEC
**************************************************************************/
#define LCD_Command(x) (LCD_Send(x, LOW))
#define LCD_Write(x) (LCD_Send(x, HIGH))
#define UBITX_DISPLAY_LCD1602_BASE
//Define connected PIN
#define LCD_PIN_RS 8
#define LCD_PIN_EN 9
uint8_t LCD_PIN_DAT[4] = {10, 11, 12, 13};
void write4bits(uint8_t value)
{
for (int i = 0; i < 4; i++)
digitalWrite(LCD_PIN_DAT[i], (value >> i) & 0x01);
digitalWrite(LCD_PIN_EN, LOW);
delayMicroseconds(1);
digitalWrite(LCD_PIN_EN, HIGH);
delayMicroseconds(1); // enable pulse must be >450ns
digitalWrite(LCD_PIN_EN, LOW);
delayMicroseconds(100); // commands need > 37us to settle
}
void LCD_Send(uint8_t value, uint8_t mode)
{
digitalWrite(LCD_PIN_RS, mode);
write4bits(value>>4);
write4bits(value);
}
void LCD1602_Init()
{
pinMode(LCD_PIN_RS, OUTPUT);
pinMode(LCD_PIN_EN, OUTPUT);
for (int i = 0; i < 4; i++)
pinMode(LCD_PIN_DAT[i], OUTPUT);
delayMicroseconds(50);
// Now we pull both RS and R/W low to begin commands
digitalWrite(LCD_PIN_RS, LOW);
digitalWrite(LCD_PIN_EN, LOW);
// we start in 8bit mode, try to set 4 bit mode
write4bits(0x03);
delayMicroseconds(4500); // wait min 4.1ms
// second try
write4bits(0x03);
delayMicroseconds(4500); // wait min 4.1ms
// third go!
write4bits(0x03);
delayMicroseconds(150);
// finally, set to 4-bit interface
write4bits(0x02);
// finally, set # lines, font size, etc.
LCD_Command(LCD_FUNCTIONSET | LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS | LCD_2LINE);
// turn the display on with no cursor or blinking default
LCD_Command(LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF);
// clear it off
LCD_Command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
delayMicroseconds(2000); // this command takes a long time!
LCD_Command(LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT);
}
#endif
//========================================================================
//End of TinyLCD Library by KD8CEC
//========================================================================
//========================================================================
//Begin of I2CTinyLCD Library by KD8CEC
//========================================================================
#ifdef UBITX_DISPLAY_LCD1602I
#include <Wire.h>
/*************************************************************************
I2C Tiny LCD Library
Referecnce Source : LiquidCrystal_I2C.cpp // Based on the work by DFRobot
KD8CEC
This source code is modified version for small program memory
from Arduino LiquidCrystal_I2C Library
I wrote this code myself, so there is no license restriction.
So this code allows anyone to write with confidence.
But keep it as long as the original author of the code.
Ian KD8CEC
**************************************************************************/
#define UBITX_DISPLAY_LCD1602_BASE
#define En B00000100 // Enable bit
#define Rw B00000010 // Read/Write bit
#define Rs B00000001 // Register select bit
#define LCD_Command(x) (LCD_Send(x, 0))
#define LCD_Write(x) (LCD_Send(x, Rs))
uint8_t _Addr;
uint8_t _displayfunction;
uint8_t _displaycontrol;
uint8_t _displaymode;
uint8_t _numlines;
uint8_t _cols;
uint8_t _rows;
uint8_t _backlightval;
#define printIIC(args) Wire.write(args)
void expanderWrite(uint8_t _data)
{
Wire.beginTransmission(_Addr);
printIIC((int)(_data) | _backlightval);
Wire.endTransmission();
}
void pulseEnable(uint8_t _data){
expanderWrite(_data | En); // En high
delayMicroseconds(1); // enable pulse must be >450ns
expanderWrite(_data & ~En); // En low
delayMicroseconds(50); // commands need > 37us to settle
}
void write4bits(uint8_t value)
{
expanderWrite(value);
pulseEnable(value);
}
void LCD_Send(uint8_t value, uint8_t mode)
{
uint8_t highnib=value&0xf0;
uint8_t lownib=(value<<4)&0xf0;
write4bits((highnib)|mode);
write4bits((lownib)|mode);
}
// Turn the (optional) backlight off/on
void noBacklight(void) {
_backlightval=LCD_NOBACKLIGHT;
expanderWrite(0);
}
void backlight(void) {
_backlightval=LCD_BACKLIGHT;
expanderWrite(0);
}
void LCD1602_Init()
{
//I2C Init
_Addr = I2C_LCD_MASTER_ADDRESS;
_cols = 16;
_rows = 2;
_backlightval = LCD_NOBACKLIGHT;
Wire.begin();
delay(50);
// Now we pull both RS and R/W low to begin commands
expanderWrite(_backlightval); // reset expanderand turn backlight off (Bit 8 =1)
delay(1000);
//put the LCD into 4 bit mode
// this is according to the hitachi HD44780 datasheet
// figure 24, pg 46
// we start in 8bit mode, try to set 4 bit mode
write4bits(0x03 << 4);
delayMicroseconds(4500); // wait min 4.1ms
// second try
write4bits(0x03 << 4);
delayMicroseconds(4500); // wait min 4.1ms
// third go!
write4bits(0x03 << 4);
delayMicroseconds(150);
// finally, set to 4-bit interface
write4bits(0x02 << 4);
// finally, set # lines, font size, etc.
LCD_Command(LCD_FUNCTIONSET | LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS | LCD_2LINE);
// turn the display on with no cursor or blinking default
LCD_Command(LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF);
// clear it off
LCD_Command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
//delayMicroseconds(2000); // this command takes a long time!
delayMicroseconds(1000); // this command takes a long time!
LCD_Command(LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT);
backlight();
}
/*
void LCD_Print(const char *c)
{
for (uint8_t i = 0; i < strlen(c); i++)
{
if (*(c + i) == 0x00) return;
LCD_Write(*(c + i));
}
}
void LCD_SetCursor(uint8_t col, uint8_t row)
{
LCD_Command(LCD_SETDDRAMADDR | (col + row * 0x40)); //0 : 0x00, 1 : 0x40, only for 16 x 2 lcd
}
void LCD_CreateChar(uint8_t location, uint8_t charmap[])
{
location &= 0x7; // we only have 8 locations 0-7
LCD_Command(LCD_SETCGRAMADDR | (location << 3));
for (int i=0; i<8; i++)
LCD_Write(charmap[i]);
}
*/
#endif
//========================================================================
//End of I2CTinyLCD Library by KD8CEC
//========================================================================
//========================================================================
// 16 X 02 LCD Routines
//Begin of Display Base Routines (Init, printLine..)
//========================================================================
#ifdef UBITX_DISPLAY_LCD1602_BASE
//SWR GRAPH, DrawMeter and drawingMeter Logic function by VK2ETA
#define OPTION_SKINNYBARS
char c[30], b[30];
char printBuff[2][17]; //mirrors what is showing on the two lines of the display
void LCD_Print(const char *c)
{
for (uint8_t i = 0; i < strlen(c); i++)
{
if (*(c + i) == 0x00) return;
LCD_Write(*(c + i));
}
}
void LCD_SetCursor(uint8_t col, uint8_t row)
{
LCD_Command(LCD_SETDDRAMADDR | (col + row * 0x40)); //0 : 0x00, 1 : 0x40, only for 16 x 2 lcd
}
void LCD_CreateChar(uint8_t location, uint8_t charmap[])
{
location &= 0x7; // we only have 8 locations 0-7
LCD_Command(LCD_SETCGRAMADDR | (location << 3));
for (int i=0; i<8; i++)
LCD_Write(charmap[i]);
}
void LCD_Init(void)
{
LCD1602_Init();
initMeter(); //for Meter Display
}
// The generic routine to display one line on the LCD
void printLine(unsigned char linenmbr, const char *c) {
if ((displayOption1 & 0x01) == 0x01)
linenmbr = (linenmbr == 0 ? 1 : 0); //Line Toggle
if (strcmp(c, printBuff[linenmbr])) { // only refresh the display when there was a change
LCD_SetCursor(0, linenmbr); // place the cursor at the beginning of the selected line
LCD_Print(c);
strcpy(printBuff[linenmbr], c);
for (byte i = strlen(c); i < 16; i++) { // add white spaces until the end of the 16 characters line is reached
LCD_Write(' ');
}
}
}
void printLineF(char linenmbr, const __FlashStringHelper *c)
{
int i;
char tmpBuff[17];
PGM_P p = reinterpret_cast<PGM_P>(c);
for (i = 0; i < 17; i++){
unsigned char fChar = pgm_read_byte(p++);
tmpBuff[i] = fChar;
if (fChar == 0)
break;
}
printLine(linenmbr, tmpBuff);
}
#define LCD_MAX_COLUMN 16
void printLineFromEEPRom(char linenmbr, char lcdColumn, byte eepromStartIndex, byte eepromEndIndex, char offsetTtype) {
if ((displayOption1 & 0x01) == 0x01)
linenmbr = (linenmbr == 0 ? 1 : 0); //Line Toggle
LCD_SetCursor(lcdColumn, linenmbr);
for (byte i = eepromStartIndex; i <= eepromEndIndex; i++)
{
if (++lcdColumn <= LCD_MAX_COLUMN)
LCD_Write(EEPROM.read((offsetTtype == 0 ? USER_CALLSIGN_DAT : WSPR_MESSAGE1) + i));
else
break;
}
for (byte i = lcdColumn; i < 16; i++) //Right Padding by Space
LCD_Write(' ');
}
// short cut to print to the first line
void printLine1(const char *c)
{
printLine(1,c);
}
// short cut to print to the first line
void printLine2(const char *c)
{
printLine(0,c);
}
void clearLine2()
{
printLine2("");
line2DisplayStatus = 0;
}
// short cut to print to the first line
void printLine1Clear(){
printLine(1,"");
}
// short cut to print to the first line
void printLine2Clear(){
printLine(0, "");
}
void printLine2ClearAndUpdate(){
printLine(0, "");
line2DisplayStatus = 0;
updateDisplay();
}
//==================================================================================
//End of Display Base Routines
//==================================================================================
//==================================================================================
//Begin of User Interface Routines
//==================================================================================
//Main Display
// this builds up the top line of the display with frequency and mode
void updateDisplay() {
// tks Jack Purdum W8TEE
// replaced fsprint commmands by str commands for code size reduction
// replace code for Frequency numbering error (alignment, point...) by KD8CEC
int i;
unsigned long tmpFreq = frequency; //
memset(c, 0, sizeof(c));
if (inTx){
if (isCWAutoMode == 2) {
for (i = 0; i < 4; i++)
c[3-i] = (i < autoCWSendReservCount ? byteToChar(autoCWSendReserv[i]) : ' ');
//display Sending Index
c[4] = byteToChar(sendingCWTextIndex);
c[5] = '=';
}
else {
if (cwTimeout > 0)
strcpy(c, " CW:");
else
strcpy(c, " TX:");
}
}
else {
if (ritOn)
strcpy(c, "RIT ");
else {
if (cwMode == 0)
{
if (isUSB)
strcpy(c, "USB ");
else
strcpy(c, "LSB ");
}
else if (cwMode == 1)
{
strcpy(c, "CWL ");
}
else
{
strcpy(c, "CWU ");
}
}
if (vfoActive == VFO_A) // VFO A is active
strcat(c, "A:");
else
strcat(c, "B:");
}
//Fixed by Mitani Massaru (JE4SMQ)
if (isShiftDisplayCWFreq == 1)
{
if (cwMode == 1) //CWL
tmpFreq = tmpFreq - sideTone + shiftDisplayAdjustVal;
else if (cwMode == 2) //CWU
tmpFreq = tmpFreq + sideTone + shiftDisplayAdjustVal;
}
//display frequency
for (int i = 15; i >= 6; i--) {
if (tmpFreq > 0) {
if (i == 12 || i == 8) c[i] = '.';
else {
c[i] = tmpFreq % 10 + 0x30;
tmpFreq /= 10;
}
}
else
c[i] = ' ';
}
//remarked by KD8CEC
//already RX/TX status display, and over index (16 x 2 LCD)
//if (inTx)
// strcat(c, " TX");
printLine(1, c);
byte diplayVFOLine = 1;
if ((displayOption1 & 0x01) == 0x01)
diplayVFOLine = 0;
if ((vfoActive == VFO_A && ((isDialLock & 0x01) == 0x01)) ||
(vfoActive == VFO_B && ((isDialLock & 0x02) == 0x02))) {
LCD_SetCursor(5,diplayVFOLine);
LCD_Write((uint8_t)0);
}
else if (isCWAutoMode == 2){
LCD_SetCursor(5,diplayVFOLine);
LCD_Write(0x7E);
}
else
{
LCD_SetCursor(5,diplayVFOLine);
LCD_Write(':');
}
}
char line2Buffer[17];
//KD8CEC 200Hz ST
//L14.150 200Hz ST
//U14.150 +150khz
int freqScrollPosition = 0;
//Example Line2 Optinal Display
//immediate execution, not call by scheulder
//warning : unused parameter 'displayType' <-- ignore, this is reserve
void updateLine2Buffer(char displayType)
{
unsigned long tmpFreq = 0;
if (ritOn)
{
strcpy(line2Buffer, "RitTX:");
//display frequency
tmpFreq = ritTxFrequency;
//Fixed by Mitani Massaru (JE4SMQ)
if (isShiftDisplayCWFreq == 1)
{
if (cwMode == 1) //CWL
tmpFreq = tmpFreq - sideTone + shiftDisplayAdjustVal;
else if (cwMode == 2) //CWU
tmpFreq = tmpFreq + sideTone + shiftDisplayAdjustVal;
}
for (int i = 15; i >= 6; i--) {
if (tmpFreq > 0) {
if (i == 12 || i == 8) line2Buffer[i] = '.';
else {
line2Buffer[i] = tmpFreq % 10 + 0x30;
tmpFreq /= 10;
}
}
else
line2Buffer[i] = ' ';
}
return;
} //end of ritOn display
//other VFO display
if (vfoActive == VFO_B)
{
tmpFreq = vfoA;
}
else
{
tmpFreq = vfoB;
}
// EXAMPLE 1 & 2
//U14.150.100
//display frequency
for (int i = 9; i >= 0; i--) {
if (tmpFreq > 0) {
if (i == 2 || i == 6) line2Buffer[i] = '.';
else {
line2Buffer[i] = tmpFreq % 10 + 0x30;
tmpFreq /= 10;
}
}
else
line2Buffer[i] = ' ';
}
//EXAMPLE #1
if ((displayOption1 & 0x04) == 0x00) //none scroll display
line2Buffer[6] = 'M';
else
{
//example #2
if (freqScrollPosition++ > 18) //none scroll display time
{
line2Buffer[6] = 'M';
if (freqScrollPosition > 25)
freqScrollPosition = -1;
}
else //scroll frequency
{
line2Buffer[10] = 'H';
line2Buffer[11] = 'z';
if (freqScrollPosition < 7)
{
for (int i = 11; i >= 0; i--)
if (i - (7 - freqScrollPosition) >= 0)
line2Buffer[i] = line2Buffer[i - (7 - freqScrollPosition)];
else
line2Buffer[i] = ' ';
}
else
{
for (int i = 0; i < 11; i++)
if (i + (freqScrollPosition - 7) <= 11)
line2Buffer[i] = line2Buffer[i + (freqScrollPosition - 7)];
else
line2Buffer[i] = ' ';
}
}
} //scroll
line2Buffer[7] = ' ';
if (isIFShift)
{
// if (isDirectCall == 1)
// for (int i = 0; i < 16; i++)
// line2Buffer[i] = ' ';
//IFShift Offset Value
line2Buffer[8] = 'I';
line2Buffer[9] = 'F';
line2Buffer[10] = ifShiftValue >= 0 ? '+' : 0;
line2Buffer[11] = 0;
line2Buffer[12] = ' ';
//11, 12, 13, 14, 15
memset(b, 0, sizeof(b));
ltoa(ifShiftValue, b, DEC);
strncat(line2Buffer, b, 5);
//if (isDirectCall == 1) //if call by encoder (not scheduler), immediate print value
printLine2(line2Buffer);
} // end of display IF
else // step & Key Type display
{
//if (isDirectCall != 0)
// return;
memset(&line2Buffer[8], ' ', 8);
//Step
long tmpStep = arTuneStep[tuneStepIndex -1];
byte isStepKhz = 0;
if (tmpStep >= 1000)
{
isStepKhz = 2;
}
for (int i = 10; i >= 8 - isStepKhz; i--) {
if (tmpStep > 0) {
line2Buffer[i + isStepKhz] = tmpStep % 10 + 0x30;
tmpStep /= 10;
}
else
line2Buffer[i +isStepKhz] = ' ';
}
if (isStepKhz == 0)
{
line2Buffer[11] = 'H';
line2Buffer[12] = 'z';
}
line2Buffer[13] = ' ';
//Check CW Key cwKeyType = 0; //0: straight, 1 : iambica, 2: iambicb
if (sdrModeOn == 1)
{
line2Buffer[13] = 'S';
line2Buffer[14] = 'D';
line2Buffer[15] = 'R';
}
else if (cwKeyType == 0)
{
line2Buffer[14] = 'S';
line2Buffer[15] = 'T';
}
else if (cwKeyType == 1)
{
line2Buffer[14] = 'I';
line2Buffer[15] = 'A';
}
else
{
line2Buffer[14] = 'I';
line2Buffer[15] = 'B';
}
}
}
//meterType : 0 = S.Meter, 1 : P.Meter
void DisplayMeter(byte meterType, byte meterValue, char drawPosition)
{
if (meterType == 0 || meterType == 1 || meterType == 2)
{
drawMeter(meterValue);
int lineNumber = 0;
if ((displayOption1 & 0x01) == 0x01)
lineNumber = 1;
LCD_SetCursor(drawPosition, lineNumber);
LCD_Write(lcdMeter[0]);
LCD_Write(lcdMeter[1]);
LCD_Write(lcdMeter[2]);
}
}
char checkCount = 0;
char checkCountSMeter = 0;
void idle_process()
{
//space for user graphic display
if (menuOn == 0)
{
if ((displayOption1 & 0x10) == 0x10) //always empty topline
return;
//if line2DisplayStatus == 0 <-- this condition is clear Line, you can display any message
if (line2DisplayStatus == 0 || (((displayOption1 & 0x04) == 0x04) && line2DisplayStatus == 2)) {
if (checkCount++ > 1)
{
updateLine2Buffer(0); //call by scheduler
printLine2(line2Buffer);
line2DisplayStatus = 2;
checkCount = 0;
}
}
//S-Meter Display
if (((displayOption1 & 0x08) == 0x08 && (sdrModeOn == 0)) && (++checkCountSMeter > SMeterLatency))
{
int newSMeter;
#ifdef USE_I2CSMETER
scaledSMeter = GetI2CSmeterValue(I2CMETER_CALCS);
#else
//VK2ETA S-Meter from MAX9814 TC pin / divide 4 by KD8CEC for reduce EEPromSize
newSMeter = analogRead(ANALOG_SMETER) / 4;
//Faster attack, Slower release
//currentSMeter = (newSMeter > currentSMeter ? ((currentSMeter * 3 + newSMeter * 7) + 5) / 10 : ((currentSMeter * 7 + newSMeter * 3) + 5) / 10) / 4;
currentSMeter = newSMeter;
scaledSMeter = 0;
for (byte s = 8; s >= 1; s--) {
if (currentSMeter > sMeterLevels[s]) {
scaledSMeter = s;
break;
}
}
#endif
DisplayMeter(0, scaledSMeter, 13);
checkCountSMeter = 0; //Reset Latency time
} //end of S-Meter
}
}
//AutoKey LCD Display Routine
void Display_AutoKeyTextIndex(byte textIndex)
{
byte diplayAutoCWLine = 0;
if ((displayOption1 & 0x01) == 0x01)
diplayAutoCWLine = 1;
LCD_SetCursor(0, diplayAutoCWLine);
LCD_Write(byteToChar(textIndex));
LCD_Write(':');
}
void DisplayCallsign(byte callSignLength)
{
printLineFromEEPRom(0, 0, 0, userCallsignLength -1, 0); //eeprom to lcd use offset (USER_CALLSIGN_DAT)
//delay(500);
}
void DisplayVersionInfo(const __FlashStringHelper * fwVersionInfo)
{
printLineF(1, fwVersionInfo);
}
#endif

View File

@@ -0,0 +1,727 @@
/*************************************************************************
KD8CEC's uBITX Display Routine for LCD1602 Dual LCD
1.This is the display code for the 16x02 Dual LCD
2.Some functions moved from uBITX_Ui.
-----------------------------------------------------------------------------
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
#include "ubitx.h"
#include "ubitx_lcd.h"
//========================================================================
//Begin of I2CTinyLCD Library for Dual LCD by KD8CEC
//========================================================================
#ifdef UBITX_DISPLAY_LCD1602I_DUAL
#include <Wire.h>
/*************************************************************************
I2C Tiny LCD Library
Referecnce Source : LiquidCrystal_I2C.cpp // Based on the work by DFRobot
KD8CEC
This source code is modified version for small program memory
from Arduino LiquidCrystal_I2C Library
I wrote this code myself, so there is no license restriction.
So this code allows anyone to write with confidence.
But keep it as long as the original author of the code.
Ian KD8CEC
**************************************************************************/
#define UBITX_DISPLAY_LCD1602_BASE
#define En B00000100 // Enable bit
#define Rw B00000010 // Read/Write bit
#define Rs B00000001 // Register select bit
#define LCD_Command(x) (LCD_Send(x, 0))
#define LCD_Write(x) (LCD_Send(x, Rs))
uint8_t _Addr;
uint8_t _displayfunction;
uint8_t _displaycontrol;
uint8_t _displaymode;
uint8_t _numlines;
uint8_t _cols;
uint8_t _rows;
uint8_t _backlightval;
#define printIIC(args) Wire.write(args)
void expanderWrite(uint8_t _data)
{
Wire.beginTransmission(_Addr);
printIIC((int)(_data) | _backlightval);
Wire.endTransmission();
}
void pulseEnable(uint8_t _data){
expanderWrite(_data | En); // En high
delayMicroseconds(1); // enable pulse must be >450ns
expanderWrite(_data & ~En); // En low
delayMicroseconds(50); // commands need > 37us to settle
}
void write4bits(uint8_t value)
{
expanderWrite(value);
pulseEnable(value);
}
void LCD_Send(uint8_t value, uint8_t mode)
{
uint8_t highnib=value&0xf0;
uint8_t lownib=(value<<4)&0xf0;
write4bits((highnib)|mode);
write4bits((lownib)|mode);
}
// Turn the (optional) backlight off/on
void noBacklight(void) {
_backlightval=LCD_NOBACKLIGHT;
expanderWrite(0);
}
void backlight(void) {
_backlightval=LCD_BACKLIGHT;
expanderWrite(0);
}
void LCD1602_Dual_Init()
{
//I2C Init
_cols = 16;
_rows = 2;
_backlightval = LCD_NOBACKLIGHT;
Wire.begin();
delay(50);
// Now we pull both RS and R/W low to begin commands
_Addr = I2C_LCD_MASTER_ADDRESS;
expanderWrite(_backlightval); // reset expanderand turn backlight off (Bit 8 =1)
_Addr = I2C_LCD_SECOND_ADDRESS;
expanderWrite(_backlightval); // reset expanderand turn backlight off (Bit 8 =1)
delay(1000);
//put the LCD into 4 bit mode
// this is according to the hitachi HD44780 datasheet
// figure 24, pg 46
_Addr = I2C_LCD_MASTER_ADDRESS;
// we start in 8bit mode, try to set 4 bit mode
write4bits(0x03 << 4);
delayMicroseconds(4500); // wait min 4.1ms
// second try
write4bits(0x03 << 4);
delayMicroseconds(4500); // wait min 4.1ms
// third go!
write4bits(0x03 << 4);
delayMicroseconds(150);
// finally, set to 4-bit interface
write4bits(0x02 << 4);
// finally, set # lines, font size, etc.
LCD_Command(LCD_FUNCTIONSET | LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS | LCD_2LINE);
// turn the display on with no cursor or blinking default
LCD_Command(LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF);
// clear it off
LCD_Command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
//delayMicroseconds(2000); // this command takes a long time!
delayMicroseconds(1000); // this command takes a long time!
LCD_Command(LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT);
backlight();
_Addr = I2C_LCD_SECOND_ADDRESS;
// we start in 8bit mode, try to set 4 bit mode
write4bits(0x03 << 4);
delayMicroseconds(4500); // wait min 4.1ms
// second try
write4bits(0x03 << 4);
delayMicroseconds(4500); // wait min 4.1ms
// third go!
write4bits(0x03 << 4);
delayMicroseconds(150);
// finally, set to 4-bit interface
write4bits(0x02 << 4);
// finally, set # lines, font size, etc.
LCD_Command(LCD_FUNCTIONSET | LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS | LCD_2LINE);
// turn the display on with no cursor or blinking default
LCD_Command(LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF);
// clear it off
LCD_Command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
//delayMicroseconds(2000); // this command takes a long time!
delayMicroseconds(1000); // this command takes a long time!
LCD_Command(LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT);
backlight();
//Change to Default LCD (Master)
_Addr = I2C_LCD_MASTER_ADDRESS;
}
//========================================================================
// 16 X 02 LCD Routines
//Begin of Display Base Routines (Init, printLine..)
//========================================================================
void LCD_Print(const char *c)
{
for (uint8_t i = 0; i < strlen(c); i++)
{
if (*(c + i) == 0x00) return;
LCD_Write(*(c + i));
}
}
const int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
void LCD_SetCursor(uint8_t col, uint8_t row)
{
LCD_Command(LCD_SETDDRAMADDR | (col + row_offsets[row])); //0 : 0x00, 1 : 0x40, only for 20 x 4 lcd
}
void LCD_CreateChar(uint8_t location, uint8_t charmap[])
{
location &= 0x7; // we only have 8 locations 0-7
LCD_Command(LCD_SETCGRAMADDR | (location << 3));
for (int i=0; i<8; i++)
LCD_Write(charmap[i]);
}
//SWR GRAPH, DrawMeter and drawingMeter Logic function by VK2ETA
//#define OPTION_SKINNYBARS
char c[30], b[30];
char printBuff[4][20]; //mirrors what is showing on the two lines of the display
void LCD_Init(void)
{
LCD1602_Dual_Init();
_Addr = I2C_LCD_SECOND_ADDRESS;
initMeter(); //for Meter Display //when dual LCD, S.Meter on second LCD
_Addr = I2C_LCD_MASTER_ADDRESS;
}
// The generic routine to display one line on the LCD
void printLine(unsigned char linenmbr, const char *c) {
if ((displayOption1 & 0x01) == 0x01)
linenmbr = (linenmbr == 0 ? 1 : 0); //Line Toggle
if (strcmp(c, printBuff[linenmbr])) { // only refresh the display when there was a change
LCD_SetCursor(0, linenmbr); // place the cursor at the beginning of the selected line
LCD_Print(c);
strcpy(printBuff[linenmbr], c);
for (byte i = strlen(c); i < 20; i++) { // add white spaces until the end of the 20 characters line is reached
LCD_Write(' ');
}
}
}
void printLineF(char linenmbr, const __FlashStringHelper *c)
{
int i;
char tmpBuff[21];
PGM_P p = reinterpret_cast<PGM_P>(c);
for (i = 0; i < 21; i++){
unsigned char fChar = pgm_read_byte(p++);
tmpBuff[i] = fChar;
if (fChar == 0)
break;
}
printLine(linenmbr, tmpBuff);
}
#define LCD_MAX_COLUMN 20
void printLineFromEEPRom(char linenmbr, char lcdColumn, byte eepromStartIndex, byte eepromEndIndex, char offsetTtype) {
if ((displayOption1 & 0x01) == 0x01)
linenmbr = (linenmbr == 0 ? 1 : 0); //Line Toggle
LCD_SetCursor(lcdColumn, linenmbr);
for (byte i = eepromStartIndex; i <= eepromEndIndex; i++)
{
if (++lcdColumn <= LCD_MAX_COLUMN)
LCD_Write(EEPROM.read((offsetTtype == 0 ? USER_CALLSIGN_DAT : WSPR_MESSAGE1) + i));
else
break;
}
for (byte i = lcdColumn; i < 20; i++) //Right Padding by Space
LCD_Write(' ');
}
// short cut to print to the first line
void printLine1(const char *c)
{
printLine(1,c);
}
// short cut to print to the first line
void printLine2(const char *c)
{
printLine(0,c);
}
void clearLine2()
{
printLine2("");
line2DisplayStatus = 0;
}
// short cut to print to the first line
void printLine1Clear(){
printLine(1,"");
}
// short cut to print to the first line
void printLine2Clear(){
printLine(0, "");
}
void printLine2ClearAndUpdate(){
printLine(0, "");
line2DisplayStatus = 0;
updateDisplay();
}
//==================================================================================
//End of Display Base Routines
//==================================================================================
//==================================================================================
//Begin of User Interface Routines
//==================================================================================
//Main Display
// this builds up the top line of the display with frequency and mode
void updateDisplay() {
// tks Jack Purdum W8TEE
// replaced fsprint commmands by str commands for code size reduction
// replace code for Frequency numbering error (alignment, point...) by KD8CEC
// i also Very TNX Purdum for good source code
int i;
unsigned long tmpFreq = frequency; //
memset(c, 0, sizeof(c));
if (inTx){
if (isCWAutoMode == 2) {
for (i = 0; i < 4; i++)
c[3-i] = (i < autoCWSendReservCount ? byteToChar(autoCWSendReserv[i]) : ' ');
//display Sending Index
c[4] = byteToChar(sendingCWTextIndex);
c[5] = '=';
}
else {
if (cwTimeout > 0)
strcpy(c, " CW:");
else
strcpy(c, " TX:");
}
}
else {
if (ritOn)
strcpy(c, "RIT ");
else {
if (cwMode == 0)
{
if (isUSB)
strcpy(c, "USB ");
else
strcpy(c, "LSB ");
}
else if (cwMode == 1)
{
strcpy(c, "CWL ");
}
else
{
strcpy(c, "CWU ");
}
}
if (vfoActive == VFO_A) // VFO A is active
strcat(c, "A:");
else
strcat(c, "B:");
}
//Fixed by Mitani Massaru (JE4SMQ)
if (isShiftDisplayCWFreq == 1)
{
if (cwMode == 1) //CWL
tmpFreq = tmpFreq - sideTone + shiftDisplayAdjustVal;
else if (cwMode == 2) //CWU
tmpFreq = tmpFreq + sideTone + shiftDisplayAdjustVal;
}
//display frequency
for (int i = 15; i >= 6; i--) {
if (tmpFreq > 0) {
if (i == 12 || i == 8) c[i] = '.';
else {
c[i] = tmpFreq % 10 + 0x30;
tmpFreq /= 10;
}
}
else
c[i] = ' ';
}
//remarked by KD8CEC
//already RX/TX status display, and over index (16 x 2 LCD)
printLine(1, c);
byte diplayVFOLine = 1;
if ((displayOption1 & 0x01) == 0x01)
diplayVFOLine = 0;
if ((vfoActive == VFO_A && ((isDialLock & 0x01) == 0x01)) ||
(vfoActive == VFO_B && ((isDialLock & 0x02) == 0x02))) {
LCD_SetCursor(5,diplayVFOLine);
LCD_Write((uint8_t)0);
}
else if (isCWAutoMode == 2){
LCD_SetCursor(5,diplayVFOLine);
LCD_Write(0x7E);
}
else
{
LCD_SetCursor(5,diplayVFOLine);
LCD_Write(':');
}
}
char line2Buffer[20];
//KD8CEC 200Hz ST
//L14.150 200Hz ST
//U14.150 +150khz
int freqScrollPosition = 0;
//Example Line2 Optinal Display
//immediate execution, not call by scheulder
//warning : unused parameter 'displayType' <-- ignore, this is reserve
void updateLine2Buffer(char displayType)
{
unsigned long tmpFreq = 0;
if (ritOn)
{
strcpy(line2Buffer, "RitTX:");
//display frequency
tmpFreq = ritTxFrequency;
//Fixed by Mitani Massaru (JE4SMQ)
if (isShiftDisplayCWFreq == 1)
{
if (cwMode == 1) //CWL
tmpFreq = tmpFreq - sideTone + shiftDisplayAdjustVal;
else if (cwMode == 2) //CWU
tmpFreq = tmpFreq + sideTone + shiftDisplayAdjustVal;
}
for (int i = 15; i >= 6; i--) {
if (tmpFreq > 0) {
if (i == 12 || i == 8) line2Buffer[i] = '.';
else {
line2Buffer[i] = tmpFreq % 10 + 0x30;
tmpFreq /= 10;
}
}
else
line2Buffer[i] = ' ';
}
return;
} //end of ritOn display
//other VFO display
if (vfoActive == VFO_B)
{
tmpFreq = vfoA;
}
else
{
tmpFreq = vfoB;
}
// EXAMPLE 1 & 2
//U14.150.100
//display frequency
for (int i = 9; i >= 0; i--) {
if (tmpFreq > 0) {
if (i == 2 || i == 6) line2Buffer[i] = '.';
else {
line2Buffer[i] = tmpFreq % 10 + 0x30;
tmpFreq /= 10;
}
}
else
line2Buffer[i] = ' ';
}
memset(&line2Buffer[10], ' ', 10);
if (isIFShift)
{
line2Buffer[6] = 'M';
line2Buffer[7] = ' ';
//IFShift Offset Value
line2Buffer[8] = 'I';
line2Buffer[9] = 'F';
line2Buffer[10] = ifShiftValue >= 0 ? '+' : 0;
line2Buffer[11] = 0;
line2Buffer[12] = ' ';
//11, 12, 13, 14, 15
memset(b, 0, sizeof(b));
ltoa(ifShiftValue, b, DEC);
strncat(line2Buffer, b, 5);
for (int i = 12; i < 17; i++)
{
if (line2Buffer[i] == 0)
line2Buffer[i] = ' ';
}
} // end of display IF
else // step & Key Type display
{
//Step
long tmpStep = arTuneStep[tuneStepIndex -1];
byte isStepKhz = 0;
if (tmpStep >= 1000)
{
isStepKhz = 2;
}
for (int i = 13; i >= 11 - isStepKhz; i--) {
if (tmpStep > 0) {
line2Buffer[i + isStepKhz] = tmpStep % 10 + 0x30;
tmpStep /= 10;
}
else
line2Buffer[i +isStepKhz] = ' ';
}
if (isStepKhz == 0)
{
line2Buffer[14] = 'H';
line2Buffer[15] = 'z';
}
}
//line2Buffer[17] = ' ';
/* ianlee
//Check CW Key cwKeyType = 0; //0: straight, 1 : iambica, 2: iambicb
if (cwKeyType == 0)
{
line2Buffer[18] = 'S';
line2Buffer[19] = 'T';
}
else if (cwKeyType == 1)
{
line2Buffer[18] = 'I';
line2Buffer[19] = 'A';
}
else
{
line2Buffer[18] = 'I';
line2Buffer[19] = 'B';
}
*/
}
//meterType : 0 = S.Meter, 1 : P.Meter
void DisplayMeter(byte meterType, byte meterValue, char drawPosition)
{
if (meterType == 0 || meterType == 1 || meterType == 2)
{
drawMeter(meterValue);
LCD_SetCursor(drawPosition, 0);
LCD_Write('S');
LCD_Write(':');
for (int i = 0; i < 7; i++)
LCD_Write(lcdMeter[i]);
}
}
char checkCount = 0;
char checkCountSMeter = 0;
char beforeKeyType = -1;
char displaySDRON = 0;
//execute interval : 0.25sec
void idle_process()
{
//space for user graphic display
if (menuOn == 0)
{
if ((displayOption1 & 0x10) == 0x10) //always empty topline
return;
//if line2DisplayStatus == 0 <-- this condition is clear Line, you can display any message
if (line2DisplayStatus == 0 || (((displayOption1 & 0x04) == 0x04) && line2DisplayStatus == 2)) {
if (checkCount++ > 1)
{
updateLine2Buffer(0); //call by scheduler
printLine2(line2Buffer);
line2DisplayStatus = 2;
checkCount = 0;
//check change CW Key Type
if (beforeKeyType != cwKeyType)
{
_Addr = I2C_LCD_SECOND_ADDRESS;
LCD_SetCursor(10, 0);
LCD_Write('K');
LCD_Write('E');
LCD_Write('Y');
LCD_Write(':');
//Check CW Key cwKeyType = 0; //0: straight, 1 : iambica, 2: iambicb
if (cwKeyType == 0)
{
LCD_Write('S');
LCD_Write('T');
}
else if (cwKeyType == 1)
{
LCD_Write('I');
LCD_Write('A');
}
else
{
LCD_Write('I');
LCD_Write('B');
}
beforeKeyType = cwKeyType;
_Addr = I2C_LCD_MASTER_ADDRESS;
} //Display Second Screen
}
}
//EX for Meters
//S-Meter Display
_Addr = I2C_LCD_SECOND_ADDRESS;
if (sdrModeOn == 1)
{
if (displaySDRON == 0) //once display
{
displaySDRON = 1;
LCD_SetCursor(0, 0);
LCD_Write('S');
LCD_Write('D');
LCD_Write('R');
LCD_Write(' ');
LCD_Write('M');
LCD_Write('O');
LCD_Write('D');
LCD_Write('E');
}
}
else if (((displayOption1 & 0x08) == 0x08) && (++checkCountSMeter > 3))
{
int newSMeter;
displaySDRON = 0;
#ifdef USE_I2CSMETER
scaledSMeter = GetI2CSmeterValue(I2CMETER_CALCS);
#else
//VK2ETA S-Meter from MAX9814 TC pin / divide 4 by KD8CEC for reduce EEPromSize
newSMeter = analogRead(ANALOG_SMETER) / 4;
//Faster attack, Slower release
//currentSMeter = (newSMeter > currentSMeter ? ((currentSMeter * 3 + newSMeter * 7) + 5) / 10 : ((currentSMeter * 7 + newSMeter * 3) + 5) / 10);
//currentSMeter = (currentSMeter * 3 + newSMeter * 7) / 10; //remarked becaused of have already Latency time
currentSMeter = newSMeter;
scaledSMeter = 0;
for (byte s = 8; s >= 1; s--) {
if (currentSMeter > sMeterLevels[s]) {
scaledSMeter = s;
break;
}
}
#endif
DisplayMeter(0, scaledSMeter, 0);
checkCountSMeter = 0;
} //end of S-Meter
_Addr = I2C_LCD_MASTER_ADDRESS;
}
}
//AutoKey LCD Display Routine
void Display_AutoKeyTextIndex(byte textIndex)
{
byte diplayAutoCWLine = 0;
if ((displayOption1 & 0x01) == 0x01)
diplayAutoCWLine = 1;
LCD_SetCursor(0, diplayAutoCWLine);
LCD_Write(byteToChar(textIndex));
LCD_Write(':');
}
void DisplayCallsign(byte callSignLength)
{
_Addr = I2C_LCD_SECOND_ADDRESS;
printLineFromEEPRom(1, 16 - userCallsignLength, 0, userCallsignLength -1, 0); //eeprom to lcd use offset (USER_CALLSIGN_DAT)
_Addr = I2C_LCD_MASTER_ADDRESS;
}
void DisplayVersionInfo(const __FlashStringHelper * fwVersionInfo)
{
_Addr = I2C_LCD_SECOND_ADDRESS;
printLineF(1, fwVersionInfo);
_Addr = I2C_LCD_MASTER_ADDRESS;
}
#endif

743
Raduino/ubitx_lcd_2004.ino Normal file
View File

@@ -0,0 +1,743 @@
/*************************************************************************
KD8CEC's uBITX Display Routine for LCD2004 Parrel & I2C
1.This is the display code for the 20x04 LCD
2.Some functions moved from uBITX_Ui.
-----------------------------------------------------------------------------
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
#include "ubitx.h"
#include "ubitx_lcd.h"
//========================================================================
//Begin of TinyLCD Library by KD8CEC
//========================================================================
#ifdef UBITX_DISPLAY_LCD2004P
/*************************************************************************
LCD2004TINY Library for 20 x 4 LCD
Referecnce Source : LiquidCrystal.cpp
KD8CEC
This source code is modified version for small program memory
from Arduino LiquidCrystal Library
I wrote this code myself, so there is no license restriction.
So this code allows anyone to write with confidence.
But keep it as long as the original author of the code.
DE Ian KD8CEC
**************************************************************************/
#define LCD_Command(x) (LCD_Send(x, LOW))
#define LCD_Write(x) (LCD_Send(x, HIGH))
#define UBITX_DISPLAY_LCD2004_BASE
//Define connected PIN
#define LCD_PIN_RS 8
#define LCD_PIN_EN 9
uint8_t LCD_PIN_DAT[4] = {10, 11, 12, 13};
void write4bits(uint8_t value)
{
for (int i = 0; i < 4; i++)
digitalWrite(LCD_PIN_DAT[i], (value >> i) & 0x01);
digitalWrite(LCD_PIN_EN, LOW);
delayMicroseconds(1);
digitalWrite(LCD_PIN_EN, HIGH);
delayMicroseconds(1); // enable pulse must be >450ns
digitalWrite(LCD_PIN_EN, LOW);
delayMicroseconds(100); // commands need > 37us to settle
}
void LCD_Send(uint8_t value, uint8_t mode)
{
digitalWrite(LCD_PIN_RS, mode);
write4bits(value>>4);
write4bits(value);
}
void LCD2004_Init()
{
pinMode(LCD_PIN_RS, OUTPUT);
pinMode(LCD_PIN_EN, OUTPUT);
for (int i = 0; i < 4; i++)
pinMode(LCD_PIN_DAT[i], OUTPUT);
delayMicroseconds(50);
// Now we pull both RS and R/W low to begin commands
digitalWrite(LCD_PIN_RS, LOW);
digitalWrite(LCD_PIN_EN, LOW);
// we start in 8bit mode, try to set 4 bit mode
write4bits(0x03);
delayMicroseconds(4500); // wait min 4.1ms
// second try
write4bits(0x03);
delayMicroseconds(4500); // wait min 4.1ms
// third go!
write4bits(0x03);
delayMicroseconds(150);
// finally, set to 4-bit interface
write4bits(0x02);
// finally, set # lines, font size, etc.
LCD_Command(LCD_FUNCTIONSET | LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS | LCD_2LINE);
// turn the display on with no cursor or blinking default
LCD_Command(LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF);
// clear it off
LCD_Command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
delayMicroseconds(2000); // this command takes a long time!
LCD_Command(LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT);
}
#endif
//========================================================================
//End of TinyLCD Library by KD8CEC
//========================================================================
//========================================================================
//Begin of I2CTinyLCD Library by KD8CEC
//========================================================================
#ifdef UBITX_DISPLAY_LCD2004I
#include <Wire.h>
/*************************************************************************
I2C Tiny LCD Library
Referecnce Source : LiquidCrystal_I2C.cpp // Based on the work by DFRobot
KD8CEC
This source code is modified version for small program memory
from Arduino LiquidCrystal_I2C Library
I wrote this code myself, so there is no license restriction.
So this code allows anyone to write with confidence.
But keep it as long as the original author of the code.
Ian KD8CEC
**************************************************************************/
#define UBITX_DISPLAY_LCD2004_BASE
#define En B00000100 // Enable bit
#define Rw B00000010 // Read/Write bit
#define Rs B00000001 // Register select bit
#define LCD_Command(x) (LCD_Send(x, 0))
#define LCD_Write(x) (LCD_Send(x, Rs))
uint8_t _Addr;
uint8_t _displayfunction;
uint8_t _displaycontrol;
uint8_t _displaymode;
uint8_t _numlines;
uint8_t _cols;
uint8_t _rows;
uint8_t _backlightval;
#define printIIC(args) Wire.write(args)
void expanderWrite(uint8_t _data)
{
Wire.beginTransmission(_Addr);
printIIC((int)(_data) | _backlightval);
Wire.endTransmission();
}
void pulseEnable(uint8_t _data){
expanderWrite(_data | En); // En high
delayMicroseconds(1); // enable pulse must be >450ns
expanderWrite(_data & ~En); // En low
delayMicroseconds(50); // commands need > 37us to settle
}
void write4bits(uint8_t value)
{
expanderWrite(value);
pulseEnable(value);
}
void LCD_Send(uint8_t value, uint8_t mode)
{
uint8_t highnib=value&0xf0;
uint8_t lownib=(value<<4)&0xf0;
write4bits((highnib)|mode);
write4bits((lownib)|mode);
}
// Turn the (optional) backlight off/on
void noBacklight(void) {
_backlightval=LCD_NOBACKLIGHT;
expanderWrite(0);
}
void backlight(void) {
_backlightval=LCD_BACKLIGHT;
expanderWrite(0);
}
void LCD2004_Init()
{
//I2C Init
_Addr = I2C_LCD_MASTER_ADDRESS;
_cols = 20;
_rows = 4;
_backlightval = LCD_NOBACKLIGHT;
Wire.begin();
delay(50);
// Now we pull both RS and R/W low to begin commands
expanderWrite(_backlightval); // reset expanderand turn backlight off (Bit 8 =1)
delay(1000);
//put the LCD into 4 bit mode
// this is according to the hitachi HD44780 datasheet
// figure 24, pg 46
// we start in 8bit mode, try to set 4 bit mode
write4bits(0x03 << 4);
delayMicroseconds(4500); // wait min 4.1ms
// second try
write4bits(0x03 << 4);
delayMicroseconds(4500); // wait min 4.1ms
// third go!
write4bits(0x03 << 4);
delayMicroseconds(150);
// finally, set to 4-bit interface
write4bits(0x02 << 4);
// finally, set # lines, font size, etc.
LCD_Command(LCD_FUNCTIONSET | LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS | LCD_2LINE);
// turn the display on with no cursor or blinking default
LCD_Command(LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF);
// clear it off
LCD_Command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
//delayMicroseconds(2000); // this command takes a long time!
delayMicroseconds(1000); // this command takes a long time!
LCD_Command(LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT);
backlight();
}
#endif
//========================================================================
//End of I2CTinyLCD Library by KD8CEC
//========================================================================
//========================================================================
// 20 X 04 LCD Routines
//Begin of Display Base Routines (Init, printLine..)
//========================================================================
#ifdef UBITX_DISPLAY_LCD2004_BASE
void LCD_Print(const char *c)
{
for (uint8_t i = 0; i < strlen(c); i++)
{
if (*(c + i) == 0x00) return;
LCD_Write(*(c + i));
}
}
const int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
void LCD_SetCursor(uint8_t col, uint8_t row)
{
LCD_Command(LCD_SETDDRAMADDR | (col + row_offsets[row])); //0 : 0x00, 1 : 0x40, only for 20 x 4 lcd
}
void LCD_CreateChar(uint8_t location, uint8_t charmap[])
{
location &= 0x7; // we only have 8 locations 0-7
LCD_Command(LCD_SETCGRAMADDR | (location << 3));
for (int i=0; i<8; i++)
LCD_Write(charmap[i]);
}
//SWR GRAPH, DrawMeter and drawingMeter Logic function by VK2ETA
//#define OPTION_SKINNYBARS
char c[30], b[30];
char printBuff[4][21]; //mirrors what is showing on the two lines of the display
void LCD_Init(void)
{
LCD2004_Init();
initMeter(); //for Meter Display
}
// The generic routine to display one line on the LCD
void printLine(unsigned char linenmbr, const char *c) {
if ((displayOption1 & 0x01) == 0x01)
linenmbr = (linenmbr == 0 ? 1 : 0); //Line Toggle
if (strcmp(c, printBuff[linenmbr])) { // only refresh the display when there was a change
LCD_SetCursor(0, linenmbr); // place the cursor at the beginning of the selected line
LCD_Print(c);
strcpy(printBuff[linenmbr], c);
for (byte i = strlen(c); i < 20; i++) { // add white spaces until the end of the 20 characters line is reached
LCD_Write(' ');
}
}
}
void printLineF(char linenmbr, const __FlashStringHelper *c)
{
int i;
char tmpBuff[21];
PGM_P p = reinterpret_cast<PGM_P>(c);
for (i = 0; i < 21; i++){
unsigned char fChar = pgm_read_byte(p++);
tmpBuff[i] = fChar;
if (fChar == 0)
break;
}
printLine(linenmbr, tmpBuff);
}
#define LCD_MAX_COLUMN 20
void printLineFromEEPRom(char linenmbr, char lcdColumn, byte eepromStartIndex, byte eepromEndIndex, char offsetTtype) {
if ((displayOption1 & 0x01) == 0x01)
linenmbr = (linenmbr == 0 ? 1 : 0); //Line Toggle
LCD_SetCursor(lcdColumn, linenmbr);
for (byte i = eepromStartIndex; i <= eepromEndIndex; i++)
{
if (++lcdColumn <= LCD_MAX_COLUMN)
LCD_Write(EEPROM.read((offsetTtype == 0 ? USER_CALLSIGN_DAT : WSPR_MESSAGE1) + i));
else
break;
}
for (byte i = lcdColumn; i < 20; i++) //Right Padding by Space
LCD_Write(' ');
}
// short cut to print to the first line
void printLine1(const char *c)
{
printLine(1,c);
}
// short cut to print to the first line
void printLine2(const char *c)
{
printLine(0,c);
}
void clearLine2()
{
printLine2("");
line2DisplayStatus = 0;
}
// short cut to print to the first line
void printLine1Clear(){
printLine(1,"");
}
// short cut to print to the first line
void printLine2Clear(){
printLine(0, "");
}
void printLine2ClearAndUpdate(){
printLine(0, "");
line2DisplayStatus = 0;
updateDisplay();
}
//==================================================================================
//End of Display Base Routines
//==================================================================================
//==================================================================================
//Begin of User Interface Routines
//==================================================================================
//Main Display
// this builds up the top line of the display with frequency and mode
void updateDisplay() {
// tks Jack Purdum W8TEE
// replaced fsprint commmands by str commands for code size reduction
// replace code for Frequency numbering error (alignment, point...) by KD8CEC
// i also Very TNX Purdum for good source code
int i;
unsigned long tmpFreq = frequency; //
memset(c, 0, sizeof(c));
if (inTx){
if (isCWAutoMode == 2) {
for (i = 0; i < 4; i++)
c[3-i] = (i < autoCWSendReservCount ? byteToChar(autoCWSendReserv[i]) : ' ');
//display Sending Index
c[4] = byteToChar(sendingCWTextIndex);
c[5] = '=';
}
else {
if (cwTimeout > 0)
strcpy(c, " CW:");
else
strcpy(c, " TX:");
}
}
else {
if (ritOn)
strcpy(c, "RIT ");
else {
if (cwMode == 0)
{
if (isUSB)
strcpy(c, "USB ");
else
strcpy(c, "LSB ");
}
else if (cwMode == 1)
{
strcpy(c, "CWL ");
}
else
{
strcpy(c, "CWU ");
}
}
if (vfoActive == VFO_A) // VFO A is active
strcat(c, "A:");
else
strcat(c, "B:");
}
//Fixed by Mitani Massaru (JE4SMQ)
if (isShiftDisplayCWFreq == 1)
{
if (cwMode == 1) //CWL
tmpFreq = tmpFreq - sideTone + shiftDisplayAdjustVal;
else if (cwMode == 2) //CWU
tmpFreq = tmpFreq + sideTone + shiftDisplayAdjustVal;
}
//display frequency
for (int i = 15; i >= 6; i--) {
if (tmpFreq > 0) {
if (i == 12 || i == 8) c[i] = '.';
else {
c[i] = tmpFreq % 10 + 0x30;
tmpFreq /= 10;
}
}
else
c[i] = ' ';
}
if (sdrModeOn)
strcat(c, " SDR");
else
strcat(c, " SPK");
//remarked by KD8CEC
//already RX/TX status display, and over index (20 x 4 LCD)
//if (inTx)
// strcat(c, " TX");
printLine(1, c);
byte diplayVFOLine = 1;
if ((displayOption1 & 0x01) == 0x01)
diplayVFOLine = 0;
if ((vfoActive == VFO_A && ((isDialLock & 0x01) == 0x01)) ||
(vfoActive == VFO_B && ((isDialLock & 0x02) == 0x02))) {
LCD_SetCursor(5,diplayVFOLine);
LCD_Write((uint8_t)0);
}
else if (isCWAutoMode == 2){
LCD_SetCursor(5,diplayVFOLine);
LCD_Write(0x7E);
}
else
{
LCD_SetCursor(5,diplayVFOLine);
LCD_Write(':');
}
}
char line2Buffer[20];
//KD8CEC 200Hz ST
//L14.150 200Hz ST
//U14.150 +150khz
int freqScrollPosition = 0;
//Example Line2 Optinal Display
//immediate execution, not call by scheulder
//warning : unused parameter 'displayType' <-- ignore, this is reserve
void updateLine2Buffer(char displayType)
{
unsigned long tmpFreq = 0;
if (ritOn)
{
strcpy(line2Buffer, "RitTX:");
//display frequency
tmpFreq = ritTxFrequency;
//Fixed by Mitani Massaru (JE4SMQ)
if (isShiftDisplayCWFreq == 1)
{
if (cwMode == 1) //CWL
tmpFreq = tmpFreq - sideTone + shiftDisplayAdjustVal;
else if (cwMode == 2) //CWU
tmpFreq = tmpFreq + sideTone + shiftDisplayAdjustVal;
}
for (int i = 15; i >= 6; i--) {
if (tmpFreq > 0) {
if (i == 12 || i == 8) line2Buffer[i] = '.';
else {
line2Buffer[i] = tmpFreq % 10 + 0x30;
tmpFreq /= 10;
}
}
else
line2Buffer[i] = ' ';
}
return;
} //end of ritOn display
//other VFO display
if (vfoActive == VFO_B)
{
tmpFreq = vfoA;
}
else
{
tmpFreq = vfoB;
}
// EXAMPLE 1 & 2
//U14.150.100
//display frequency
for (int i = 9; i >= 0; i--) {
if (tmpFreq > 0) {
if (i == 2 || i == 6) line2Buffer[i] = '.';
else {
line2Buffer[i] = tmpFreq % 10 + 0x30;
tmpFreq /= 10;
}
}
else
line2Buffer[i] = ' ';
}
memset(&line2Buffer[10], ' ', 10);
if (isIFShift)
{
line2Buffer[6] = 'M';
line2Buffer[7] = ' ';
//IFShift Offset Value
line2Buffer[8] = 'I';
line2Buffer[9] = 'F';
line2Buffer[10] = ifShiftValue >= 0 ? '+' : 0;
line2Buffer[11] = 0;
line2Buffer[12] = ' ';
//11, 12, 13, 14, 15
memset(b, 0, sizeof(b));
ltoa(ifShiftValue, b, DEC);
strncat(line2Buffer, b, 5);
for (int i = 12; i < 17; i++)
{
if (line2Buffer[i] == 0)
line2Buffer[i] = ' ';
}
} // end of display IF
else // step & Key Type display
{
//Step
long tmpStep = arTuneStep[tuneStepIndex -1];
byte isStepKhz = 0;
if (tmpStep >= 1000)
{
isStepKhz = 2;
}
for (int i = 14; i >= 12 - isStepKhz; i--) {
if (tmpStep > 0) {
line2Buffer[i + isStepKhz] = tmpStep % 10 + 0x30;
tmpStep /= 10;
}
else
line2Buffer[i +isStepKhz] = ' ';
}
if (isStepKhz == 0)
{
line2Buffer[15] = 'H';
line2Buffer[16] = 'z';
}
}
line2Buffer[17] = ' ';
//Check CW Key cwKeyType = 0; //0: straight, 1 : iambica, 2: iambicb
if (cwKeyType == 0)
{
line2Buffer[18] = 'S';
line2Buffer[19] = 'T';
}
else if (cwKeyType == 1)
{
line2Buffer[18] = 'I';
line2Buffer[19] = 'A';
}
else
{
line2Buffer[18] = 'I';
line2Buffer[19] = 'B';
}
}
//meterType : 0 = S.Meter, 1 : P.Meter
void DisplayMeter(byte meterType, byte meterValue, char drawPosition)
{
if (meterType == 0 || meterType == 1 || meterType == 2)
{
drawMeter(meterValue);
LCD_SetCursor(drawPosition, 2);
LCD_Write('S');
LCD_Write(':');
for (int i = 0; i < 7; i++) //meter 5 + +db 1 = 6
LCD_Write(lcdMeter[i]);
}
}
char checkCount = 0;
char checkCountSMeter = 0;
//execute interval : 0.25sec
void idle_process()
{
//space for user graphic display
if (menuOn == 0)
{
if ((displayOption1 & 0x10) == 0x10) //always empty topline
return;
//if line2DisplayStatus == 0 <-- this condition is clear Line, you can display any message
if (line2DisplayStatus == 0 || (((displayOption1 & 0x04) == 0x04) && line2DisplayStatus == 2)) {
if (checkCount++ > 1)
{
updateLine2Buffer(0); //call by scheduler
printLine2(line2Buffer);
line2DisplayStatus = 2;
checkCount = 0;
}
}
//EX for Meters
/*
DisplayMeter(0, testValue++, 0);
if (testValue > 30)
testValue = 0;
*/
//Sample
//DisplayMeter(0, analogRead(ANALOG_SMETER) / 30, 0);
//DisplayMeter(0, analogRead(ANALOG_SMETER) / 10, 0);
//delay_background(10, 0);
//DisplayMeter(0, analogRead(ANALOG_SMETER), 0);
//if (testValue > 30)
// testValue = 0;
//S-Meter Display
if (((displayOption1 & 0x08) == 0x08 && (sdrModeOn == 0)) && (++checkCountSMeter > SMeterLatency))
{
int newSMeter;
#ifdef USE_I2CSMETER
scaledSMeter = GetI2CSmeterValue(I2CMETER_CALCS);
#else
//VK2ETA S-Meter from MAX9814 TC pin
newSMeter = analogRead(ANALOG_SMETER) / 4;
//Faster attack, Slower release
//currentSMeter = (newSMeter > currentSMeter ? ((currentSMeter * 3 + newSMeter * 7) + 5) / 10 : ((currentSMeter * 7 + newSMeter * 3) + 5) / 10);
//currentSMeter = ((currentSMeter * 7 + newSMeter * 3) + 5) / 10;
currentSMeter = newSMeter;
scaledSMeter = 0;
for (byte s = 8; s >= 1; s--) {
if (currentSMeter > sMeterLevels[s]) {
scaledSMeter = s;
break;
}
}
#endif
DisplayMeter(0, scaledSMeter, 0);
checkCountSMeter = 0; //Reset Latency time
} //end of S-Meter
}
}
//AutoKey LCD Display Routine
void Display_AutoKeyTextIndex(byte textIndex)
{
byte diplayAutoCWLine = 0;
if ((displayOption1 & 0x01) == 0x01)
diplayAutoCWLine = 1;
LCD_SetCursor(0, diplayAutoCWLine);
LCD_Write(byteToChar(textIndex));
LCD_Write(':');
}
void DisplayCallsign(byte callSignLength)
{
printLineFromEEPRom(3, 20 - userCallsignLength, 0, userCallsignLength -1, 0); //eeprom to lcd use offset (USER_CALLSIGN_DAT)
}
void DisplayVersionInfo(const __FlashStringHelper * fwVersionInfo)
{
printLineF(3, fwVersionInfo);
}
#endif

File diff suppressed because it is too large Load Diff

1716
Raduino/ubitx_menu.ino Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,21 @@
// ************* SI5315 routines - tks Jerry Gaffke, KE7ER ***********************
/************************************************************************************
* KD8CEC
* kd8cec@gmail.com http://www.hamskey.com
*
* Merge two SI5351 Librarys
* KE7ER's fixed vco and variable Clocks Configure values
* G3ZIL's fixed Clock Configure Value and variable VCO
* * I have combined the two libraries above. All licenses follow the above library.
*
* PLL-A is generated by fixing 850Mhz clock. All output clocks use PLL-A to
* generate the frequency. This is the method used in QRP radios such as uBITX.
* When switching to WSPR transmission mode, PLL-B operates for the base frequency to transmit WSPR.
* The output clock channel that controls the frequency is connected to the PLL-B.
* The WSPR protocol is generated by changing the clock of the PLL-B.
************************************************************************************/
#include "ubitx.h"
// ************* SI5315 routines - tks Jerry Gaffke, KE7ER ***********************
// An minimalist standalone set of Si5351 routines.
// VCOA is fixed at 875mhz, VCOB not used.
// The output msynth dividers are used to generate 3 independent clocks
@@ -32,7 +48,8 @@
#define BB1(x) ((uint8_t)(x>>8))
#define BB2(x) ((uint8_t)(x>>16))
#define SI5351BX_ADDR 0x60 // I2C address of Si5351 (typical)
//#define SI5351BX_ADDR 0x60 // I2C address of Si5351 (typical)
uint8_t SI5351BX_ADDR; // I2C address of Si5351 (variable from Version 1.097)
#define SI5351BX_XTALPF 2 // 1:6pf 2:8pf 3:10pf
// If using 27mhz crystal, set XTAL=27000000, MSA=33. Then vco=891mhz
@@ -42,7 +59,13 @@
// User program may have reason to poke new values into these 3 RAM variables
uint32_t si5351bx_vcoa = (SI5351BX_XTAL*SI5351BX_MSA); // 25mhzXtal calibrate
uint8_t si5351bx_rdiv = 0; // 0-7, CLK pin sees fout/(2**rdiv)
#if UBITX_BOARD_VERSION == 5
uint8_t si5351bx_drive[3] = {3, 3, 3}; // 0=2ma 1=4ma 2=6ma 3=8ma for CLK 0,1,2
#else
uint8_t si5351bx_drive[3] = {1, 1, 1}; // 0=2ma 1=4ma 2=6ma 3=8ma for CLK 0,1,2
#endif
uint8_t si5351bx_clken = 0xFF; // Private, all CLK output drivers off
int32_t calibration = 0;
@@ -60,19 +83,34 @@ void i2cWriten(uint8_t reg, uint8_t *vals, uint8_t vcnt) { // write array
Wire.endTransmission();
}
uint8_t si5351Val[8] = {0, 1, 0, 0, 0, 0, 0, 0}; //for reduce program memory size
void si5351bx_init() { // Call once at power-up, start PLLA
uint8_t reg; uint32_t msxp1;
uint32_t msxp1;
Wire.begin();
i2cWrite(149, 0); // SpreadSpectrum off
i2cWrite(3, si5351bx_clken); // Disable all CLK output drivers
i2cWrite(183, SI5351BX_XTALPF << 6); // Set 25mhz crystal load capacitance
msxp1 = 128 * SI5351BX_MSA - 512; // and msxp2=0, msxp3=1, not fractional
uint8_t vals[8] = {0, 1, BB2(msxp1), BB1(msxp1), BB0(msxp1), 0, 0, 0};
i2cWriten(26, vals, 8); // Write to 8 PLLA msynth regs
//uint8_t vals[8] = {0, 1, BB2(msxp1), BB1(msxp1), BB0(msxp1), 0, 0, 0};
si5351Val[2] = BB2(msxp1);
si5351Val[3] = BB1(msxp1);
si5351Val[4] = BB0(msxp1);
i2cWriten(26, si5351Val, 8); // Write to 8 PLLA msynth regs
i2cWrite(177, 0x20); // Reset PLLA (0x80 resets PLLB)
// for (reg=16; reg<=23; reg++) i2cWrite(reg, 0x80); // Powerdown CLK's
// i2cWrite(187, 0); // No fannout of clkin, xtal, ms0, ms4
#if UBITX_BOARD_VERSION == 5
//why? TODO : CHECK by KD8CEC
//initializing the ppl2 as well
i2cWriten(34, si5351Val, 8); // Write to 8 PLLA msynth regs
i2cWrite(177, 0xa0); // Reset PLLA & PPLB (0x80 resets PLLB)
#else
//
#endif
}
void si5351bx_setfreq(uint8_t clknum, uint32_t fout) { // Set a CLK to fout Hz
@@ -105,12 +143,48 @@ void si5351_set_calibration(int32_t cal){
si5351bx_setfreq(0, usbCarrier);
}
void SetCarrierFreq()
{
unsigned long appliedCarrier = ((cwMode == 0 ? usbCarrier : cwmCarrier) + (isIFShift && (inTx == 0) ? ifShiftValue : 0));
//si5351bx_setfreq(0, (sdrModeOn ? 0 : appliedCarrier));
si5351bx_setfreq(0, ((sdrModeOn && (inTx == 0)) ? 0 : appliedCarrier)); //found bug by KG4GEK
/*
if (cwMode == 0)
si5351bx_setfreq(0, usbCarrier + (isIFShift ? ifShiftValue : 0));
else
si5351bx_setfreq(0, cwmCarrier + (isIFShift ? ifShiftValue : 0));
*/
}
void initOscillators(){
//initialize the SI5351
si5351bx_init();
si5351bx_vcoa = (SI5351BX_XTAL * SI5351BX_MSA) + calibration; // apply the calibration correction factor
si5351bx_setfreq(0, usbCarrier);
SetCarrierFreq();
}
//============================================================
// ADD FUNCTIONS by KD8CEC
//============================================================
uint8_t Wspr_Reg1[8] = {0xFF,0xFE, 0x00, 0, 0, 0, 0, 0}; //3, 4, 5, 6, 7
uint8_t Wspr_Reg2[8] = {0, 1, 0, 0, 0, 0, 0, 0}; //2, 3, 4
void Set_WSPR_Param(void)
{
i2cWrite(18, 128);
i2cWriten(34, Wspr_Reg1, 8);
i2cWriten(58, Wspr_Reg2, 8);
i2cWrite(177, 128);
i2cWrite(18, 111);
si5351bx_clken &= ~(1 << 2);
i2cWrite(3, si5351bx_clken);
}
void TXSubFreq(unsigned long P2)
{
i2cWrite(40, (P2 & 65280) >> 8);
i2cWrite(41, P2 & 255);
}

299
Raduino/ubitx_ui.ino Normal file
View File

@@ -0,0 +1,299 @@
/**
* The user interface of the ubitx consists of the encoder, the push-button on top of it
* and the 16x2 LCD display.
* The upper line of the display is constantly used to display frequency and status
* of the radio. Occasionally, it is used to provide a two-line information that is
* quickly cleared up.
*/
/*
const PROGMEM uint8_t meters_bitmap[] = {
B10000, B10000, B10000, B10000, B10000, B10000, B10000, B10000 , //custom 1
B11000, B11000, B11000, B11000, B11000, B11000, B11000, B11000 , //custom 2
B11100, B11100, B11100, B11100, B11100, B11100, B11100, B11100 , //custom 3
B11110, B11110, B11110, B11110, B11110, B11110, B11110, B11110 , //custom 4
B11111, B11111, B11111, B11111, B11111, B11111, B11111, B11111 , //custom 5
B01000, B11100, B01000, B00000, B10111, B10101, B10101, B10111 //custom 6
};
*/
//SWR GRAPH, DrawMeter and drawingMeter Logic function by VK2ETA
#ifdef OPTION_SKINNYBARS //We want skninny bars with more text
//VK2ETA modded "Skinny" bitmaps
const PROGMEM uint8_t meters_bitmap[] = {
// B01110, B10001, B10001, B11111, B11011, B11011, B11111, B00000, //Padlock Symbol, for merging. Not working, see below
B00000, B00000, B00000, B00000, B00000, B00000, B00000, B10000, //shortest bar
B00000, B00000, B00000, B00000, B00000, B00000, B00100, B10100,
B00000, B00000, B00000, B00000, B00000, B00001, B00101, B10101,
B00000, B00000, B00000, B00000, B10000, B10000, B10000, B10000,
B00000, B00000, B00000, B00100, B10100, B10100, B10100, B10100,
B00000, B00000, B00001, B00101, B10101, B10101, B10101, B10101, //tallest bar
B00000, B00010, B00111, B00010, B01000, B11100, B01000, B00000, // ++ sign
};
#else
//VK2ETA "Fat" bars, easy to read, with less text
const PROGMEM uint8_t meters_bitmap[] = {
// B01110, B10001, B10001, B11111, B11011, B11011, B11111, B00000, //Padlock Symbol, for merging. Not working, see below
B00000, B00000, B00000, B00000, B00000, B00000, B00000, B11111, //shortest bar
B00000, B00000, B00000, B00000, B00000, B00000, B11111, B11111,
B00000, B00000, B00000, B00000, B00000, B11111, B11111, B11111,
B00000, B00000, B00000, B00000, B11111, B11111, B11111, B11111,
B00000, B00000, B00000, B11111, B11111, B11111, B11111, B11111,
B00000, B00000, B11111, B11111, B11111, B11111, B11111, B11111, //tallest bar
B00000, B00010, B00111, B00010, B01000, B11100, B01000, B00000, // ++ sign
};
#endif //OPTION_SKINNYBARS
PGM_P p_metes_bitmap = reinterpret_cast<PGM_P>(meters_bitmap);
const PROGMEM uint8_t lock_bitmap[8] = {
0b01110,
0b10001,
0b10001,
0b11111,
0b11011,
0b11011,
0b11111,
0b00000};
PGM_P plock_bitmap = reinterpret_cast<PGM_P>(lock_bitmap);
// initializes the custom characters
// we start from char 1 as char 0 terminates the string!
void initMeter(){
uint8_t tmpbytes[8];
byte i;
for (i = 0; i < 8; i++)
tmpbytes[i] = pgm_read_byte(plock_bitmap + i);
LCD_CreateChar(0, tmpbytes);
for (i = 0; i < 8; i++)
tmpbytes[i] = pgm_read_byte(p_metes_bitmap + i);
LCD_CreateChar(1, tmpbytes);
for (i = 0; i < 8; i++)
tmpbytes[i] = pgm_read_byte(p_metes_bitmap + i + 8);
LCD_CreateChar(2, tmpbytes);
for (i = 0; i < 8; i++)
tmpbytes[i] = pgm_read_byte(p_metes_bitmap + i + 16);
LCD_CreateChar(3, tmpbytes);
for (i = 0; i < 8; i++)
tmpbytes[i] = pgm_read_byte(p_metes_bitmap + i + 24);
LCD_CreateChar(4, tmpbytes);
for (i = 0; i < 8; i++)
tmpbytes[i] = pgm_read_byte(p_metes_bitmap + i + 32);
LCD_CreateChar(5, tmpbytes);
for (i = 0; i < 8; i++)
tmpbytes[i] = pgm_read_byte(p_metes_bitmap + i + 40);
LCD_CreateChar(6, tmpbytes);
for (i = 0; i < 8; i++)
tmpbytes[i] = pgm_read_byte(p_metes_bitmap + i + 48);
LCD_CreateChar(7, tmpbytes);
}
//by KD8CEC
//0 ~ 25 : 30 over : + 10
/*
void drawMeter(int needle) {
//5Char + O over
int i;
for (i = 0; i < 5; i++) {
if (needle >= 5)
lcdMeter[i] = 5; //full
else if (needle > 0)
lcdMeter[i] = needle; //full
else //0
lcdMeter[i] = 0x20;
needle -= 5;
}
if (needle > 0)
lcdMeter[5] = 6;
else
lcdMeter[5] = 0x20;
}
*/
//VK2ETA meter for S.Meter, power and SWR
void drawMeter(int needle)
{
#ifdef OPTION_SKINNYBARS
//Fill buffer with growing set of bars, up to needle value
lcdMeter[0] = 0x20;
lcdMeter[1] = 0x20;
for (int i = 0; i < 6; i++) {
if (needle > i)
lcdMeter[i / 3] = byte(i + 1); //Custom characters above
//else if (i == 1 || i == 4) {
// lcdMeter[i / 3] = 0x20; //blank
//}
}
if (needle > 7) {
lcdMeter[2] = byte(7); //Custom character "++"
} else if (needle > 6) {
lcdMeter[2] = '+'; //"+"
} else lcdMeter[2] = 0x20;
#else //Must be "fat" bars
//Fill buffer with growing set of bars, up to needle value
for (int i = 0; i < 6; i++) {
if (needle > i)
lcdMeter[i] = byte(i + 1); //Custom characters above
else
lcdMeter[i] = 0x20; //blank
}
if (needle > 7) {
lcdMeter[6] = byte(7); //Custom character "++"
} else if (needle > 6) {
lcdMeter[6] = '+'; //"+"
} else lcdMeter[6] = 0x20;
#endif //OPTION_FATBARS
}
char byteToChar(byte srcByte){
if (srcByte < 10)
return 0x30 + srcByte;
else
return 'A' + srcByte - 10;
}
//returns true if the button is pressed
int btnDown(void){
#ifdef EXTEND_KEY_GROUP1
if (analogRead(FBUTTON) > FUNCTION_KEY_ADC)
return 0;
else
return 1;
#else
if (digitalRead(FBUTTON) == HIGH)
return 0;
else
return 1;
#endif
}
#ifdef EXTEND_KEY_GROUP1
int getBtnStatus(void){
int readButtonValue = analogRead(FBUTTON);
if (analogRead(FBUTTON) < FUNCTION_KEY_ADC)
return FKEY_PRESS;
else
{
readButtonValue = readButtonValue / 4;
//return FKEY_VFOCHANGE;
for (int i = 0; i < 16; i++)
if (KeyValues[i][2] != 0 && KeyValues[i][0] <= readButtonValue && KeyValues[i][1] >= readButtonValue)
return KeyValues[i][2];
//return i;
}
return -1;
}
#endif
int enc_prev_state = 3;
/**
* The A7 And A6 are purely analog lines on the Arduino Nano
* These need to be pulled up externally using two 10 K resistors
*
* There are excellent pages on the Internet about how these encoders work
* and how they should be used. We have elected to use the simplest way
* to use these encoders without the complexity of interrupts etc to
* keep it understandable.
*
* The enc_state returns a two-bit number such that each bit reflects the current
* value of each of the two phases of the encoder
*
* The enc_read returns the number of net pulses counted over 50 msecs.
* If the puluses are -ve, they were anti-clockwise, if they are +ve, the
* were in the clockwise directions. Higher the pulses, greater the speed
* at which the enccoder was spun
*/
byte enc_state (void) {
return (analogRead(ENC_A) > 500 ? 1 : 0) + (analogRead(ENC_B) > 500 ? 2: 0);
}
int enc_read(void) {
int result = 0;
byte newState;
int enc_speed = 0;
unsigned long start_at = millis();
while (millis() - start_at < 50) { // check if the previous state was stable
newState = enc_state(); // Get current state
if (newState != enc_prev_state)
delay (1);
if (enc_state() != newState || newState == enc_prev_state)
continue;
//these transitions point to the encoder being rotated anti-clockwise
if ((enc_prev_state == 0 && newState == 2) ||
(enc_prev_state == 2 && newState == 3) ||
(enc_prev_state == 3 && newState == 1) ||
(enc_prev_state == 1 && newState == 0)){
result--;
}
//these transitions point o the enccoder being rotated clockwise
if ((enc_prev_state == 0 && newState == 1) ||
(enc_prev_state == 1 && newState == 3) ||
(enc_prev_state == 3 && newState == 2) ||
(enc_prev_state == 2 && newState == 0)){
result++;
}
enc_prev_state = newState; // Record state for next pulse interpretation
enc_speed++;
delay(1);
}
return(result);
}
//===================================================================
//I2C Signal Meter, Version 1.097
//===================================================================
// 0xA0 ~ 0xCF : CW Decode Mode + 100Hz ~
// 0xD0 ~ 0xF3 : RTTY Decode Mode + 100Hz ~
// 0x10 ~ 0x30 : Spectrum Mode
int GetI2CSmeterValue(int valueType)
{
if (valueType > 0)
{
Wire.beginTransmission(I2CMETER_ADDR); //j : S-Meter
Wire.write(valueType); //Y : Get Value Type
Wire.endTransmission();
}
Wire.requestFrom(I2CMETER_ADDR, 1);
if (Wire.available() > 0)
{
return Wire.read();
}
else
{
return 0;
}
}

198
Raduino/ubitx_wspr.ino Normal file
View File

@@ -0,0 +1,198 @@
/**********************************************************************************
WSPR SENDER for uBITX by KD8CEC
Some of the code that sends WSPR referenced the code in G3ZIL.
Thanks to G3ZIL for sharing great code.
Due to the limited memory of uBITX, I have implemented at least only a few of the codes in uBITX.
Thanks for testing
-----------------------------------------------------------------------------
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
**********************************************************************************/
#include <EEPROM.h>
#include "ubitx.h"
//begin of test
byte WsprToneCode[164];
unsigned long lastTime=0;
unsigned long TX_MSNB_P2; // Si5351 register MSNB_P2 PLLB for Tx
unsigned long TX_P2; // Variable values for MSNB_P2 which defines the frequencies for the data
extern int enc_read(void);
byte WsprMSGCount = 0;
#define WSPR_BAND1 401
extern uint8_t Wspr_Reg1[8]; //3, 4, 5, 6, 7
extern uint8_t Wspr_Reg2[8]; //2, 3, 4
void SendWSPRManage()
{
int knob = 0;
byte knobPosition = 0;
//char isNeedDisplayInfo = 0;
char nowSelectedIndex = 0;
char nowWsprStep = 0; //0 : select Message, 1 : select band, 2 : send
char selectedWsprMessageIndex = -1;
char selectedWsprBandIndex = -1;
unsigned long WsprTXFreq = 0;
unsigned int WsprMultiChan = 0;
//unsigned long prevFreq;
byte loopIndex;
delay_background(500, 0);
//Readed WsprMSGCount, WsprTone
while(1)
{
knob = enc_read();
if (knobPosition > 0 && knob < 0)
knobPosition--;
else if (knob > 0 && (knobPosition <= (nowWsprStep == 0 ? WsprMSGCount : WSPR_BAND_COUNT) * 10 -2))
knobPosition++;
nowSelectedIndex = knobPosition / 10;
if (nowWsprStep == 0) //select Message status
{
//printLineF2(F("WSPR:"));
if (selectedWsprMessageIndex != nowSelectedIndex)
{
selectedWsprMessageIndex = nowSelectedIndex;
int wsprMessageBuffIndex = selectedWsprMessageIndex * 46;
printLineF2(F("WSPR:"));
//Display WSPR Name tag
printLineFromEEPRom(0, 6, wsprMessageBuffIndex, wsprMessageBuffIndex + 4, 1);
//Load WSPR Tonecode
//Read Tone Code
for (int i = 0; i < 41; i++)
{
byte readData = EEPROM.read(WSPR_MESSAGE1 + 5 + (wsprMessageBuffIndex) + i); //NAME TAG 5, MESSAGE 41 = 46
WsprToneCode[i * 4 + 0] = readData & 3;
WsprToneCode[i * 4 + 1] = (readData >> 2) & 3;
WsprToneCode[i * 4 + 2] = (readData >> 4) & 3;
WsprToneCode[i * 4 + 3] = (readData >> 6) & 3;
}
}
else if (btnDown())
{
nowWsprStep = 1; //Change Status to Select Band
knobPosition = 0;
nowSelectedIndex = 0;
delay_background(500, 0);
}
}
else if (nowWsprStep == 1)
{
//printLineF2(F("Select Band"));
if (selectedWsprBandIndex != nowSelectedIndex)
{
selectedWsprBandIndex = nowSelectedIndex;
int bandBuffIndex = WSPR_BAND1 + selectedWsprBandIndex * 14;
EEPROM.get(bandBuffIndex, WsprTXFreq);
EEPROM.get(bandBuffIndex + 4, WsprMultiChan);
for (loopIndex = 3; loopIndex < 8; loopIndex++)
Wspr_Reg1[loopIndex] = EEPROM.read(bandBuffIndex + loopIndex + 3);
//2, 3, 4
for (loopIndex = 2; loopIndex < 5; loopIndex++)
Wspr_Reg2[loopIndex] = EEPROM.read(bandBuffIndex + loopIndex + 9);
TX_MSNB_P2 = ((unsigned long)Wspr_Reg1[5] & 0x0F) << 16 | ((unsigned long)Wspr_Reg1[6]) << 8 | Wspr_Reg1[7];
}
if (digitalRead(PTT) == 0)
strcpy(c, "SEND: ");
else
strcpy(c, "PTT-> ");
//ltoa(WsprTXFreq, b, DEC);
//strcat(c, b);
//display frequency, Frequency to String for KD8CEC
unsigned long tmpFreq = WsprTXFreq;
for (int i = 15; i >= 6; i--) {
if (tmpFreq > 0) {
if (i == 12 || i == 8) c[i] = '.';
else {
c[i] = tmpFreq % 10 + 0x30;
tmpFreq /= 10;
}
}
else
c[i] = ' ';
}
printLine1(c);
#ifdef USE_SW_SERIAL
SWS_Process();
if ((digitalRead(PTT) == 0) || (TriggerBySW == 1))
{
TriggerBySW = 0;
#else
if (digitalRead(PTT) == 0)
{
#endif
//SEND WSPR
//If you need to consider the Rit and Sprite modes, uncomment them below.
//remark = To reduce the size of the program
//prevFreq = frequency;
//frequency = WsprTXFreq;
startTx(TX_CW, 0);
setTXFilters(WsprTXFreq);
//Start WSPR
Set_WSPR_Param();
digitalWrite(CW_KEY, 1);
for (int i = 0; i < 162; i++)
{ // Now this is the message loop
lastTime = millis(); // Store away the time when the last message symbol was sent
TX_P2 = TX_MSNB_P2 + WsprMultiChan * WsprToneCode[i]; // This represents the 1.46 Hz shift and is correct only for the bands specified in the array
TXSubFreq(TX_P2); // TX at the appropriate channel frequency for....
//if (btnDown())
// break;
while (millis() < lastTime + 683){} // .... 0,683 seconds
}
digitalWrite(CW_KEY, 0);
stopTx(); //call setFrequency -> recovery TX Filter
//frequency = prevFreq;
selectedWsprBandIndex = -1;
} //end of PTT Check
else if (btnDown())
{
return;
}
} //end of status check
//delay_background(50, 1);
} //end of while
}

149
TeensyDSP/DSP.cpp Normal file
View File

@@ -0,0 +1,149 @@
//======================================================================
// DSP.cpp
//======================================================================
#include "DSP.h"
#include <Audio.h>
#include <i2c_t3.h>
//#include <Wire.h>
//#include <SPI.h>
//#include <SD.h>
//#include <SerialFlash.h>
#define RX_AUDIO_CH 0
#define TX_MIC_IN_CH 0
#define TX_LINE_IN_CH 0
#define TX_USB_IN_CH1 1
#define TX_USB_IN_CH2 2
UBitxDSP DSP;
//static struct {
// GUItool: begin automatically generated code
AudioInputI2S lineIn; //xy=137,220
AudioInputUSB usbIn; //xy=142,326
AudioMixer4 rxAudio; //xy=394,134
AudioMixer4 txAudio; //xy=398,322
AudioOutputAnalog spkrOut; //xy=774,104
AudioOutputUSB usbOut; //xy=774,138
AudioOutputI2S lineOut; //xy=776,236
AudioConnection patchCord1(lineIn, 0, rxAudio, 0);
AudioConnection patchCord2(lineIn, 1, txAudio, 0);
AudioConnection patchCord3(usbIn, 0, txAudio, 1);
AudioConnection patchCord4(usbIn, 1, txAudio, 2);
AudioConnection patchCord5(rxAudio, spkrOut);
AudioConnection patchCord6(rxAudio, 0, lineOut, 0);
AudioConnection patchCord7(rxAudio, 0, usbOut, 0);
AudioConnection patchCord8(rxAudio, 0, usbOut, 1);
AudioConnection patchCord9(txAudio, 0, lineOut, 1);
AudioControlSGTL5000 audioCtrl; //xy=403,463
// GUItool: end automatically generated code
//} audio;
void UBitxDSP::begin() {
AudioMemory(20);
audioCtrl.enable();
audioCtrl.volume(0.0); // headphone volume...
audioCtrl.muteHeadphone(); // ...not used by UBitxDSP
for (int i = 0; i < 4; i++) {
if (i == RX_AUDIO_CH)
rxAudio.gain(i, 1.0);
else
rxAudio.gain(i, 0.0);
}
for (int i = 0; i < 4; i++) {
txAudio.gain(i, 0.0);
}
// SETUP THE AUDIO INPUTS
// Rig (Line) Input (RX)
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
audioCtrl.unmuteLineout();
audioCtrl.lineInLevel(5, 5); // RX, TX
audioCtrl.lineOutLevel(29, 29); //RX, TX
// Mic Input (TX)
audioCtrl.micGain(0); // TODO: set value
// Line Input (TX)
// USB Input (TX)
// SETUP THE AUDIO OUTPUTS
// Speaker Output (RX)
spkrOut.analogReference(INTERNAL);
// Line Output (RX)
// USB Output (RX)
// Rig (Line) Output (TX)
// Default to RX.
rx();
}
void UBitxDSP::end() {
}
void UBitxDSP::rx() {
// mute all tx audio
for (int i = 0; i < 4; i++) {
txAudio.gain(i, 0.0);
}
// select line in for rx
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
// restore rx audio
rxAudio.gain(RX_AUDIO_CH, 1.0); // restore the RX audio
}
void UBitxDSP::txMicIn() {
// mute the rx audio
rxAudio.gain(RX_AUDIO_CH, 0.0);
// restore the tx mic audio
audioCtrl.inputSelect(AUDIO_INPUT_MIC);
for (int i = 0; i < 4; i++) {
if (i == TX_MIC_IN_CH)
txAudio.gain(i, 1.0);
else
txAudio.gain(i, 0.0);
}
}
void UBitxDSP::txLineIn() {
// mute the rx audio
rxAudio.gain(RX_AUDIO_CH, 0.0);
// restore the tx line in audio
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
for (int i = 0; i < 4; i++) {
if (i == TX_LINE_IN_CH)
txAudio.gain(i, 1.0);
else
txAudio.gain(i, 0.0);
}
}
void UBitxDSP::txUSBIn() {
// mute the rx audio
rxAudio.gain(RX_AUDIO_CH, 0.0);
// restore the tx usb in audio
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
for (int i = 0; i < 4; i++) {
if (i == TX_USB_IN_CH1 || i == TX_USB_IN_CH2)
txAudio.gain(i, 1.0);
else
txAudio.gain(i, 0.0);
}
}
//======================================================================
// EOF
//======================================================================

42
TeensyDSP/DSP.h Normal file
View File

@@ -0,0 +1,42 @@
//======================================================================
// DSP.h
//======================================================================
#ifndef __DSP_h__
#define __DSP_h__
#include "Debug.h"
enum TRState {
TRANSMIT,
RECEIVE
};
enum RxAudioIn {
RIG_AUDIO
};
enum TxAudioIn {
MIC_IN,
LINE_IN,
USB_IN
};
class UBitxDSP {
public:
UBitxDSP() {};
void begin();
void end();
void rx();
void txMicIn();
void txLineIn();
void txUSBIn();
};
extern UBitxDSP DSP;
#endif
//======================================================================
// EOF
//======================================================================

18
TeensyDSP/Debug.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef __Debug_h__
#define __Debug_h__
#define DEBUG
#ifdef DEBUG
#define DBGPRINT(MSG) do { Serial.print("DBG: "); Serial.print(MSG); } while (0)
#define DBGPRINTLN(MSG) do { Serial.print("DBG: "); Serial.println(MSG); } while (0)
#define DBGNEWLINE() do { Serial.println(); } while (0)
#define DBGCMD(CMD) do { Serial.println("DBG: "); Serial.println(#CMD); CMD; } while (0)
#else
#define DBGPRINT(MSG) do {} while (0)
#define DBGPRINTLN(MSG) do {} while (0)
#define DBGNEWLINE() do {} while (0)
#define DBGCMD(CMD) do { CMD; } while (0)
#endif
#endif

186
TeensyDSP/HamFuncs.h Normal file
View File

@@ -0,0 +1,186 @@
#ifndef __HamFuncs_h__
#define __HamFuncs_h__
/**********************************************************************/
#ifndef HF_PWR_DEFAULT_LOAD
#define HF_PWR_DEFAULT_LOAD 50.0
#endif
#ifndef HF_VSWR_MAX_REPORTED
#define HF_VSWR_MAX_REPORTED 9.9
#endif
#ifndef HF_BRIDGE_FWD_VRECT
#define HF_BRIDGE_FWD_VRECT 0.25
#endif
#ifndef HF_BRIDGE_FWD_TURNS
#define HF_BRIDGE_FWD_TURNS 10.0
#endif
#ifndef HF_BRIDGE_REV_VRECT
#define HF_BRIDGE_REV_VRECT 0.25
#endif
#ifndef HF_BRIDGE_REV_TURNS
#define HF_BRIDGE_REV_TURNS 10.0
#endif
#ifndef HF_ADC_DEFAULT_BITS
#define HF_ADC_DEFAULT_BITS 10
#endif
#ifndef HF_ADC_DEFAULT_VREF
#define HF_ADC_DEFAULT_VREF 3.3
#endif
/**********************************************************************/
namespace HF {
const float pwrDefaultLoad = HF_PWR_DEFAULT_LOAD;
const float vswrMaxReported = HF_VSWR_MAX_REPORTED;
const float bridgeFwdVrect = HF_BRIDGE_FWD_VRECT;
const float bridgeFwdTurns = HF_BRIDGE_FWD_TURNS;
const float bridgeRevVrect = HF_BRIDGE_REV_VRECT;
const float bridgeRevTurns = HF_BRIDGE_REV_TURNS;
const unsigned adcDefaultBits = HF_ADC_DEFAULT_BITS;
const float adcDefaultVref = HF_ADC_DEFAULT_VREF;
const float rms = sqrt(2.0) / 2.0;
/********************************************************************/
/*!
* @brief Calculate the output voltage of a resistive divider
* network, given the input voltage and the values of the
* resistors. The input voltage is applied to R1, the output
* voltage is taken from the junction of R1 and R2, and R2 is
* connected to ground.
* @param Vin
* Input voltage.
* @param R1
* Input resistor (ohms). Input voltage is measured between
* the top of this resistor and ground.
* @param R2
* Output resistor (ohms). Output voltage is measured
* between the top of this resistor and ground.
* @return Output voltage.
*/
inline float divOut(float Vin, float R1, float R2) {
return Vin * R2 / (R1 + R2);
}
/*!
* @brief Calculate the input voltage of a resistive divider
* network, given the output voltage and the values of the
* resistors. The input voltage is applied to R1, the output
* voltage is taken from the junction of R1 and R2, and R2 is
* connected to ground.
* @param Vout
* Output voltage.
* @param R1
* Input resistor (ohms). Input voltage is measured between
* the top of this resistor and ground.
* @param R2
* Output resistor (ohms). Output voltage is measured between
* the top of this resistor and ground.
* @return Input voltage.
*/
inline float divIn(float Vout, float R1, float R2) {
return Vout * (R1 + R2) / R2;
}
/*!
* @brief Calculate and return the power in watts, given a
* resistance and the voltage across the resistance.
* @param V
* Voltage across the load.
* @param R
* (optional) Resistance of the load (ohms). If not provided,
* a default is used (HF_PWR_DEFAULT_LOAD).
* @return Power dissipated (watts). This is calculated as
* P = V^2/R.
*/
inline float P(float V, float R = pwrDefaultLoad) {
return (V * V) / R;
}
/*!
* @brief Calculate and return the Voltage Standing Wave Ratio
* (VSWR) based on the given forward and reverse voltages.
* @param Vfwd
* Measured forward voltage.
* @param Vrev
* Measured reverse voltage.
* @param VSWRmax
* (optional) Maximum reported VSWR. The output will be
* clamped to this value if necessary (HF_VSWR_MAX_REPORTED).
* @return Voltage Standing Wave Ratio (VSWR). This is calculated
* as VSWR = (Vfwd + Vrev) / (Vfwd - Vrev).
*/
inline float VSWR(float Vfwd, float Vrev, float VSWRmax = vswrMaxReported) {
if (Vfwd - Vrev == 0.0) {
return VSWRmax;
} else {
float swr = (Vfwd + Vrev) / (Vfwd - Vrev);
return (swr > VSWRmax ? VSWRmax : swr);
}
}
/*!
* @brief Calculate and return the forward RMS input voltage across
* a Stockton bridge.
* @param Vout
* Rectified output voltage (e.g. read via an ADC).
* @param Vrect
* (optional) Voltage drop across the rectifier diode. If
* not provided, a default is used (HF_BRIDGE_FWD_VRECT).
* @param turns
* (optional) Coupling transformer turns ratio. If not
* provided, a default is used (HF_BRIDGE_FWD_TURNS).
* @return Input voltage (i.e. the actual forward voltage).
*/
inline float bridgeFwd(float Vout, float Vrect = bridgeFwdVrect, float turns = bridgeFwdTurns) {
return (Vout + Vrect) * turns * rms;
}
/*!
* @brief Calculate and return the reverse RMS input voltage across
* a Stockton bridge.
* @param Vout
* Rectified output voltage (e.g. read via an ADC).
* @param Vrect
* (optional) Voltage drop across the rectifier diode. If
* not provided, a default is used (HF_BRIDGE_REV_VRECT).
* @param turns
* (optional) Coupling transformer turns ratio. If not
* provided, a default is used (HF_BRIDGE_REV_TURNS).
* @return Input voltage (i.e. the actual reverse voltage).
*/
inline float bridgeRev(float Vout, float Vrect = bridgeRevVrect, float turns = bridgeRevTurns) {
return (Vout + Vrect) * turns * rms;
}
/*!
* @brief Calculate and return the input voltage to an Analog-to-
* Digital Converter (ADC) given the resolution (number of
* bits) and the voltage reference of the ADC.
* @param counts
* Value of the ADC measurement (in unitless counts).
* @param res
* (optional) Resolution (in bits) of the ADC. If not
* provided, the default is used (HF_ADC_DEFAULT_BITS).
* @param Vref
* (optional) Voltage reference of the ADC. If not
* provided, the default is used (HF_ADC_DEFAULT_VREF).
* @return Input voltage to the ADC.
*/
inline float adcIn(unsigned counts, unsigned res = adcDefaultBits, float Vref = adcDefaultVref) {
return float(counts) * Vref / float(1 << res);
}
};
#endif

141
TeensyDSP/Nextion.cpp Normal file
View File

@@ -0,0 +1,141 @@
#include "Nextion.h"
char L_nowdisp = -1; //Sended nowdisp
char L_vfoActive; //vfoActive
unsigned long L_vfoCurr; //vfoA
byte L_vfoCurr_mode; //vfoA_mode
unsigned long L_vfoA; //vfoA
byte L_vfoA_mode; //vfoA_mode
unsigned long L_vfoB; //vfoB
byte L_vfoB_mode; //vfoB_mode
char L_ritOn;
unsigned long L_ritTxFrequency; //ritTxFrequency
char L_inTx;
byte L_isDialLock; //byte isDialLock
byte L_Split; //isTxType
byte L_TXStop; //isTxType
byte L_tuneStepIndex; //byte tuneStepIndex
byte L_scaledSMeter; //scaledSMeter
unsigned long L_sideTone; //sideTone
byte L_cwKeyType; //L_cwKeyType 0: straight, 1 : iambica, 2: iambicb
unsigned int L_cwSpeed; //cwSpeed
byte L_cwDelayTime; //cwDelayTime
byte L_delayBeforeCWStartTime; //byte delayBeforeCWStartTime
byte L_attLevel;
byte L_isIFShift; //1 = ifShift, 2 extend
int L_ifShiftValue;
byte L_sdrModeOn;
byte scaledSMeter = 0;
float calcVSWR = 0.0;
float L_calcVSWR = 0.0;
byte scaledVSWR = 0;
byte L_scaledVSWR = 0;
int fwdPower = 0;
int L_fwdPower = 0;
int revPower = 0;
int L_revPower = 0;
//Control must have prefix 'v' or 's'
char softSTRHeader[11] = {'p', 'm', '.', 's', '0', '.', 't', 'x', 't', '=', '\"'};
char softINTHeader[10] = {'p', 'm', '.', 'v', '0', '.', 'v', 'a', 'l', '='};
char softTemp[20];
/*!
@brief Send a string or numeric variable to the Nextion LCD.
@param varType
The type of the variable being sent to the Nextion LCD.
@param varIndex
The index (ID) of the variable being sent to the Nextion LCD.
*/
void sendHeader(char varType, char varIndex)
{
if (varType == SWS_HEADER_STR_TYPE)
{
softSTRHeader[4] = varIndex;
for (unsigned i = 0; i < sizeof(softSTRHeader)/sizeof(softSTRHeader[0]); i++)
Serial1.write(softSTRHeader[i]);
}
else
{
softINTHeader[4] = varIndex;
for (unsigned i = 0; i < sizeof(softINTHeader)/sizeof(softINTHeader[0]); i++)
Serial1.write(softINTHeader[i]);
}
}
/*!
@brief Send an unsigned long variable to the Nextion LCD.
@param varIndex
The index (ID) of the variable being sent to the Nextion LCD.
@param sendValue
The value of the variable being sent to the Nextion LCD.
*/
void sendCommandUL(char varIndex, unsigned long sendValue)
{
sendHeader(SWS_HEADER_INT_TYPE, varIndex);
memset(softTemp, 0, 20);
ultoa(sendValue, softTemp, DEC);
Serial1.print(softTemp);
Serial1.write(0xff);
Serial1.write(0xff);
Serial1.write(0xff);
}
/*!
@brief Send a (signed) long variable to the Nextion LCD.
@param varIndex
The index (ID) of the variable being sent to the Nextion LCD.
@param sendValue
The value of the variable being sent to the Nextion LCD.
*/
void sendCommandL(char varIndex, long sendValue)
{
sendHeader(SWS_HEADER_INT_TYPE, varIndex);
memset(softTemp, 0, 20);
ltoa(sendValue, softTemp, DEC);
Serial1.print(softTemp);
Serial1.write(0xff);
Serial1.write(0xff);
Serial1.write(0xff);
}
/*!
@brief Send a string variable to the Nextion LCD.
@param varIndex
The index (ID) of the variable being sent to the Nextion LCD.
@param sendValue
The value of the variable being sent to the Nextion LCD.
*/
void sendCommandStr(char varIndex, const char* sendValue)
{
sendHeader(SWS_HEADER_STR_TYPE, varIndex);
Serial1.print(sendValue);
Serial1.write('\"');
Serial1.write(0xFF);
Serial1.write(0xFF);
Serial1.write(0xFF);
}
unsigned char softBuff1Num[14] = {'p', 'm', '.', 'c', '0', '.', 'v', 'a', 'l', '=', 0, 0xFF, 0xFF, 0xFF};
/*!
@brief Send a single digit variable to the Nextion LCD.
@param varIndex
The index (ID) of the variable being sent to the Nextion LCD.
Values 0~9 are: Mode, nowDisp, ActiveVFO, IsDialLock, IsTxtType, IsSplitType.
@param sendValue
The value of the variable being sent to the Nextion LCD.
*/
void sendCommand1Num(char varIndex, char sendValue)
{
softBuff1Num[4] = varIndex;
softBuff1Num[10] = sendValue + 0x30; // convert to character digit
for (unsigned i = 0; i < sizeof(softBuff1Num)/sizeof(softBuff1Num[0]); i++)
Serial1.write(softBuff1Num[i]);
}

126
TeensyDSP/Nextion.h Normal file
View File

@@ -0,0 +1,126 @@
#ifndef __Nextion_h__
#define __Nextion_h__
#include <Arduino.h>
#include "Debug.h"
#define SWS_HEADER_CHAR_TYPE 'c' //1Byte Protocol Prefix
#define SWS_HEADER_INT_TYPE 'v' //Numeric Protocol Prefex
#define SWS_HEADER_STR_TYPE 's' //for TEXT Line compatiable Character LCD Control
//===================================================================
//Begin of Nextion LCD Protocol
//
// v0~v9, va~vz : Numeric (Transceiver -> Nextion LCD)
// s0~s9 : String (Text) (Transceiver -> Nextion LCD)
// vlSendxxx, vloxxx: Reserve for Nextion (Nextion LCD -> Transceiver)
//
//===================================================================
#define CMD_NOW_DISP '0' //c0
extern char L_nowdisp; //Sended nowdisp
#define CMD_VFO_TYPE 'v' //cv
extern char L_vfoActive; //vfoActive
#define CMD_CURR_FREQ 'c' //vc
extern unsigned long L_vfoCurr; //vfoA
#define CMD_CURR_MODE 'c' //cc
extern byte L_vfoCurr_mode; //vfoA_mode
#define CMD_VFOA_FREQ 'a' //va
extern unsigned long L_vfoA; //vfoA
#define CMD_VFOA_MODE 'a' //ca
extern byte L_vfoA_mode; //vfoA_mode
#define CMD_VFOB_FREQ 'b' //vb
extern unsigned long L_vfoB; //vfoB
#define CMD_VFOB_MODE 'b' //cb
extern byte L_vfoB_mode; //vfoB_mode
#define CMD_IS_RIT 'r' //cr
extern char L_ritOn;
#define CMD_RIT_FREQ 'r' //vr
extern unsigned long L_ritTxFrequency; //ritTxFrequency
#define CMD_IS_TX 't' //ct
extern char L_inTx;
#define CMD_IS_DIALLOCK 'l' //cl
extern byte L_isDialLock; //byte isDialLock
#define CMD_IS_SPLIT 's' //cs
extern byte L_Split; //isTxType
#define CMD_IS_TXSTOP 'x' //cx
extern byte L_TXStop; //isTxType
#define CMD_TUNEINDEX 'n' //cn
extern byte L_tuneStepIndex; //byte tuneStepIndex
#define CMD_SMETER 'p' //cs
extern byte L_scaledSMeter; //scaledSMeter
#define CMD_SIDE_TONE 't' //vt
extern unsigned long L_sideTone; //sideTone
#define CMD_KEY_TYPE 'k' //ck
extern byte L_cwKeyType; //L_cwKeyType 0: straight, 1 : iambica, 2: iambicb
#define CMD_CW_SPEED 's' //vs
extern unsigned int L_cwSpeed; //cwSpeed
#define CMD_CW_DELAY 'y' //vy
extern byte L_cwDelayTime; //cwDelayTime
#define CMD_CW_STARTDELAY 'e' //ve
extern byte L_delayBeforeCWStartTime; //byte delayBeforeCWStartTime
#define CMD_ATT_LEVEL 'f' //vf
extern byte L_attLevel;
extern byte L_isIFShift; //1 = ifShift, 2 extend
#define CMD_IS_IFSHIFT 'i' //ci
extern int L_ifShiftValue;
#define CMD_IFSHIFT_VALUE 'i' //vi
extern byte L_sdrModeOn;
#define CMD_SDR_MODE 'j' //cj
#define CMD_UBITX_INFO 'm' //cm Complete Send uBITX Information
//Once Send Data, When boot
//arTuneStep, When boot, once send
//long arTuneStep[5];
#define CMD_AR_TUNE1 '1' //v1
#define CMD_AR_TUNE2 '2' //v2
#define CMD_AR_TUNE3 '3' //v3
#define CMD_AR_TUNE4 '4' //v4
#define CMD_AR_TUNE5 '5' //v5
//int idleStep = 0;
extern byte scaledSMeter;
extern float calcVSWR;
extern float L_calcVSWR;
extern byte scaledVSWR;
extern byte L_scaledVSWR;
extern int fwdPower;
extern int L_fwdPower;
extern int revPower;
extern int L_revPower;
void sendHeader(char varType, char varIndex);
void sendCommandUL(char varIndex, unsigned long sendValue);
void sendCommandL(char varIndex, long sendValue);
void sendCommandStr(char varIndex, const char* sendValue);
void sendCommand1Num(char varIndex, char sendValue);
//=======================================================
//END OF Nextion Protocol
//=======================================================
#endif

5
TeensyDSP/Sensors.cpp Normal file
View File

@@ -0,0 +1,5 @@
#include "Sensors.h"
UBitxSensors Sensors;
ADC adc;

342
TeensyDSP/Sensors.h Normal file
View File

@@ -0,0 +1,342 @@
#ifndef __Sensor_h__
#define __Sensor_h__
#include <ADC.h>
#include "Debug.h"
#include "HamFuncs.h"
/**********************************************************************/
#ifndef UBITX_SENSORS_S_METER_PIN
#define UBITX_SENSORS_S_METER_PIN 27
#endif
#ifndef UBITX_SENSORS_FWD_PWR_PIN
#define UBITX_SENSORS_FWD_PWR_PIN 20
#endif
#ifndef UBITX_SENSORS_REV_PWR_PIN
#define UBITX_SENSORS_REV_PWR_PIN 28
#endif
#ifndef UBITX_SENSORS_SUPPLY_PIN
#define UBITX_SENSORS_SUPPLY_PIN 21
#endif
#ifndef UBITX_SENSORS_AVG_SAMPLES
#define UBITX_SENSORS_AVG_SAMPLES 16
#endif
#ifndef UBITX_SENSORS_S_METER_R1
#define UBITX_SENSORS_S_METER_R1 22000.0
#endif
#ifndef UBITX_SENSORS_S_METER_R2
#define UBITX_SENSORS_S_METER_R2 33000.0
#endif
#ifndef UBITX_SENSORS_FWD_PWR_R1
#define UBITX_SENSORS_FWD_PWR_R1 22000.0
#endif
#ifndef UBITX_SENSORS_FWD_PWR_R2
#define UBITX_SENSORS_FWD_PWR_R2 33000.0
#endif
#ifndef UBITX_SENSORS_REV_PWR_R1
#define UBITX_SENSORS_REV_PWR_R1 22000.0
#endif
#ifndef UBITX_SENSORS_REV_PWR_R2
#define UBITX_SENSORS_REV_PWR_R2 33000.0
#endif
#ifndef UBITX_SENSORS_SUPPLY_R1
#define UBITX_SENSORS_SUPPLY_R1 56000.0
#endif
#ifndef UBITX_SENSORS_SUPPLY_R2
#define UBITX_SENSORS_SUPPLY_R2 10000.0
#endif
#ifndef UBITX_SENSORS_S_METER_LVL0
#define UBITX_SENSORS_S_METER_LVL0 2
#endif
#ifndef UBITX_SENSORS_S_METER_LVL1
#define UBITX_SENSORS_S_METER_LVL1 4
#endif
#ifndef UBITX_SENSORS_S_METER_LVL2
#define UBITX_SENSORS_S_METER_LVL2 8
#endif
#ifndef UBITX_SENSORS_S_METER_LVL3
#define UBITX_SENSORS_S_METER_LVL3 16
#endif
#ifndef UBITX_SENSORS_S_METER_LVL4
#define UBITX_SENSORS_S_METER_LVL4 32
#endif
#ifndef UBITX_SENSORS_S_METER_LVL5
#define UBITX_SENSORS_S_METER_LVL5 64
#endif
#ifndef UBITX_SENSORS_S_METER_LVL6
#define UBITX_SENSORS_S_METER_LVL6 128
#endif
#ifndef UBITX_SENSORS_S_METER_LVL7
#define UBITX_SENSORS_S_METER_LVL7 256
#endif
#ifndef UBITX_SENSORS_S_METER_LVL8
#define UBITX_SENSORS_S_METER_LVL8 512
#endif
/**********************************************************************/
const int uBitxSensorsSMeterPin = UBITX_SENSORS_S_METER_PIN;
const int uBitxSensorsFwdPwrPin = UBITX_SENSORS_FWD_PWR_PIN;
const int uBitxSensorsRevPwrPin = UBITX_SENSORS_REV_PWR_PIN;
const int uBitxSensorsSupplyPin = UBITX_SENSORS_SUPPLY_PIN;
const int uBitxSensorsAvgSamples = UBITX_SENSORS_AVG_SAMPLES;
const float uBitxSensorsSMeterR1 = UBITX_SENSORS_S_METER_R1;
const float uBitxSensorsSMeterR2 = UBITX_SENSORS_S_METER_R2;
const float uBitxSensorsFwdPwrR1 = UBITX_SENSORS_FWD_PWR_R1;
const float uBitxSensorsFwdPwrR2 = UBITX_SENSORS_FWD_PWR_R2;
const float uBitxSensorsRevPwrR1 = UBITX_SENSORS_REV_PWR_R1;
const float uBitxSensorsRevPwrR2 = UBITX_SENSORS_REV_PWR_R2;
const float uBitxSensorsSupplyR1 = UBITX_SENSORS_SUPPLY_R1;
const float uBitxSensorsSupplyR2 = UBITX_SENSORS_SUPPLY_R2;
const int uBitxSensorsSMeterValues[] = {
UBITX_SENSORS_S_METER_LVL0,
UBITX_SENSORS_S_METER_LVL1,
UBITX_SENSORS_S_METER_LVL2,
UBITX_SENSORS_S_METER_LVL3,
UBITX_SENSORS_S_METER_LVL4,
UBITX_SENSORS_S_METER_LVL5,
UBITX_SENSORS_S_METER_LVL6,
UBITX_SENSORS_S_METER_LVL7,
UBITX_SENSORS_S_METER_LVL8
};
const int uBitxSensorsSMeterLevels = sizeof(uBitxSensorsSMeterValues) /
sizeof(uBitxSensorsSMeterValues[0]);
extern ADC adc;
/**********************************************************************/
/*!
* @brief Class that maintains a "trailing average" of the last X
* samples provided. It is a template that can be instantiated
* with both the (numeric) data type that is being stored and
* averaged, as well as the number of samples to maintain the
* trailing average across.
*/
template <typename T, int N>
class TrailingAverage {
public:
/*!
* @brief Create a new TrailingAverage object. Data type averaged,
* and number of elements to average, are determined when the
* template is instantiated.
*/
TrailingAverage():
average(T(0)),
current(0),
divisor(T(N))
{
for (int i = 0; i < N; i++) {
data[i] = T(0);
}
}
/*!
* @brief Add a new element to the average. The current last (Nth)
* element is removed, and the new element is added.
* @param val
* The new element/value to incorporate into the average.
*/
inline void add(T val) {
int last = (current - 1) % N;
average -= data[last];
current = (current + 1) % N;
average += data[current] / divisor;
}
/*!
* @brief Read the current value of the average.
* @return The current average.
*/
inline T read() {
return average;
}
private:
T data[N];
T average;
int current;
T divisor;
};
/**********************************************************************/
/*!
* @brief Class that handles the various sensors in the uBitx:
* S-Meter, forward/reverse power and SWR, and supply voltage.
*/
class UBitxSensors {
public:
/*!
* @brief Create a new UBitxSensors object. It uses the default
* S-Meter, Forward Power, Reverse Power, and Supply Voltage
* ADC pins.
*/
UBitxSensors():
sMeterPin(uBitxSensorsSMeterPin),
fwdPwrPin(uBitxSensorsFwdPwrPin),
revPwrPin(uBitxSensorsRevPwrPin),
supplyPin(uBitxSensorsSupplyPin)
{
pinMode(sMeterPin, INPUT); // analog
pinMode(fwdPwrPin, INPUT); // analog
pinMode(revPwrPin, INPUT); // analog
pinMode(supplyPin, INPUT); // analog
}
/*!
* @brief Update the value of the S-Meter by reading the associated
* ADC pin.
*/
inline void updateSMeter() {
int value = adc.analogRead(sMeterPin);
sMeter.add(value);
}
/*!
* @brief Update the value of the Forward and Reverse Power
* measurements by reading the associated ADC pin.
*/
void updatePower() {
ADC::Sync_result value = adc.analogSyncRead(fwdPwrPin, revPwrPin);
float fwdV = HF::adcIn(value.result_adc0);
float revV = HF::adcIn(value.result_adc1);
fwdV = HF::divIn(fwdV, uBitxSensorsFwdPwrR1, uBitxSensorsFwdPwrR2);
fwdV = HF::bridgeFwd(fwdV);
revV = HF::divIn(revV, uBitxSensorsRevPwrR1, uBitxSensorsRevPwrR2);
revV = HF::bridgeFwd(revV);
fwdPwr.add(HF::P(fwdV));
revPwr.add(HF::P(revV));
vswr.add(HF::VSWR(fwdV, revV));
}
/*!
* @brief Update the value of the Supply Voltage measurement by
* reading the associated ADC pin.
*/
inline void updateSupply() {
float value = HF::adcIn(adc.analogRead(supplyPin));
value = HF::divIn(value, uBitxSensorsSupplyR1, uBitxSensorsSupplyR2);
supply.add(value);
}
/*!
* @brief Return the unscaled value of the S-Meter reading.
* @return Unscaled S-Meter reading.
*/
inline int sMeterUnscaled() {
return sMeter.read();
}
/*!
* @brief Return the scaled value of the S-Meter reading. This
* is the value that is used to directly control the S-Meter
* display on the Nextion LCD.
* @return Scaled S-Meter reading.
*/
int sMeterScaled() {
float sig = sMeter.read();
// small number of elements; just doing a linear search
for (int i = uBitxSensorsSMeterLevels; i > 0; i--) {
if (sig > uBitxSensorsSMeterValues[i - 1]) {
return i;
}
}
return 0;
}
/*!
* @brief Return the current Forward Power measurement.
* @return Forward Power measurement.
*/
inline float Pfwd() {
return fwdPwr.read();
}
/*!
* @brief Return the current Reverse Power measurement.
* @return Reverse Power measurement.
*/
inline float Prev() {
return revPwr.read();
}
/*!
* @brief Return the current Voltage Standing Wave Ration (VSWR).
* @return Current VSWR calculation.
*/
inline float VSWR() {
return vswr.read();
}
/*!
* @brief Return the current Voltage Standing Wave Ration (VSWR),
* scaled for the Nextion display protocol.
* @return Current VSWR calculation (scaled).
*/
float scaledVSWR() {
int val = int(vswr.read());
if (val < 0) {
return 0;
} else if (val > uBitxSensorsSMeterLevels) {
return uBitxSensorsSMeterLevels;
} else {
return val;
}
}
/*!
* @brief Return the current Supply Voltage measurement.
* @return Current Supply Voltage.
*/
inline float supplyVoltage() {
return supply.read();
}
private:
// Pins
int sMeterPin;
int fwdPwrPin;
int revPwrPin;
int supplyPin;
// Buffers for averages
TrailingAverage<int, uBitxSensorsAvgSamples> sMeter;
TrailingAverage<float, uBitxSensorsAvgSamples> fwdPwr;
TrailingAverage<float, uBitxSensorsAvgSamples> revPwr;
TrailingAverage<float, uBitxSensorsAvgSamples> vswr;
TrailingAverage<float, uBitxSensorsAvgSamples> supply;
};
extern UBitxSensors Sensors;
#endif

45
TeensyDSP/TR.cpp Normal file
View File

@@ -0,0 +1,45 @@
//======================================================================
// TR.cpp
//======================================================================
#include <Arduino.h>
#include "TR.h"
UBitxTR TR(DSP);
void UBitxTR::update(bool cw) {
updatePTT();
updateVOX();
updateKey();
if (isTX) {
// If we are currently transmitting, then ANY T/R release (key
// release) will result in exitting transmit... except for VOX
// and CAT which can only function as a release if it was enabled.
if (pttReleased() || keyReleased() ||
(voxEnabled && voxDeactivated()) ||
(catEnabled && catDeactivated())) {
// first, stop transmitting; then, setup RX audio
DBGCMD( setRX() );
DBGCMD( dsp.rx() );
}
} else {
if ((pttEnabled && pttPressed()) || (voxEnabled && voxActivated())) {
// first, setup TX audio; then, start transmitting (from Mic)
DBGCMD( dsp.txMicIn() );
DBGCMD( setTX() );
} else if (keyEnabled && keyPressed()) {
// first, setup TX audio; then, start transmitting (from Line In)
DBGCMD( dsp.txLineIn() );
DBGCMD( setTX() );
} else if (catEnabled && catActivated()) {
// first, setup TX audio; then, start transmitting (USB)
DBGCMD( dsp.txUSBIn() );
DBGCMD( setTX() );
}
}
}
//======================================================================
// EOF
//======================================================================

169
TeensyDSP/TR.h Normal file
View File

@@ -0,0 +1,169 @@
//======================================================================
// TR.h
//======================================================================
#ifndef __TR_h__
#define __TR_h__
#include <Bounce2.h>
#include "Debug.h"
#include "DSP.h"
#define UBITX_TR_OUT_PIN 2
#define UBITX_TR_PTT_PIN 3
#define UBITX_TR_VOX_PIN 4
#define UBITX_TR_KEY_PIN 5
const int uBitxTROutPin = UBITX_TR_OUT_PIN;
const int uBitxTRPttPin = UBITX_TR_PTT_PIN;
const int uBitxTRVoxPin = UBITX_TR_VOX_PIN;
const int uBitxTRKeyPin = UBITX_TR_KEY_PIN;
class UBitxTR {
public:
UBitxTR(UBitxDSP& d, int out = uBitxTROutPin, int p = uBitxTRPttPin, int v = uBitxTRVoxPin, int k = uBitxTRKeyPin):
dsp(d), outPin(out), pttPin(p), voxPin(v), keyPin(k) {}
void begin() {
pinMode(outPin, OUTPUT);
pinMode(voxPin, INPUT_PULLUP);
pinMode(keyPin, INPUT_PULLUP);
ptt.attach(pttPin, INPUT_PULLUP);
ptt.interval(5);
// default configuration: PTT, key, and CAT enabled; VOX disabled
DBGCMD( enablePTT() );
DBGCMD( disableVOX() );
DBGCMD( enableKey() );
DBGCMD( enableCAT() );
}
inline void enablePTT() { pttEnabled = true; }
inline void enableVOX() { voxEnabled = true; }
inline void enableKey() { keyEnabled = true; }
inline void enableCAT() { catEnabled = true; }
inline void disablePTT() { pttEnabled = false; }
inline void disableVOX() { voxEnabled = false; }
inline void disableKey() { keyEnabled = false; }
inline void disableCAT() { catEnabled = false; }
inline void catTX() {
L_catActive = catActive;
catActive = true;
}
inline void catRX() {
L_catActive = catActive;
catActive = false;
}
//======================================================================
inline bool transmitting() { return isTX; }
inline bool receiving() { return !isTX; }
/*!
* @brief Check if any of the PTT's have been pressed or released
* since the last update. Only one thing is allowed to occur
* based on an order of precedence. The highest priority is
* to stop transmitting.
*
* @param cw
* True if CW mode is currently active; false otherwise.
* Different/faster logic is used in CW mode.
*/
void update(bool cw = false);
void end() {
}
private:
inline void setTX() {
digitalWrite(outPin, LOW);
isTX = true;
}
inline void setRX() {
isTX = false;
digitalWrite(outPin, HIGH);
}
inline void updatePTT() {
ptt.update();
}
inline bool pttPressed() {
return ptt.fell();
}
inline bool pttReleased() {
return ptt.rose();
}
inline void updateVOX() {
L_voxActive = voxActive;
voxActive = (digitalRead(voxPin) == LOW);
}
inline bool voxActivated() {
return (L_voxActive != voxActive) && L_voxActive;
}
inline bool voxDeactivated() {
return (L_voxActive != voxActive) && voxActive;
}
inline void updateKey() {
L_keyDown = keyDown;
keyDown = (digitalRead(keyPin) == LOW);
}
inline bool keyPressed() {
return (L_keyDown != keyDown) && L_keyDown;
}
inline bool keyReleased() {
return (L_keyDown != keyDown) && keyDown;
}
inline bool catActivated() {
return (L_catActive != catActive) && L_catActive;
}
inline bool catDeactivated() {
return (L_catActive != catActive) && catActive;
}
UBitxDSP& dsp;
Bounce ptt;
int outPin;
int pttPin;
int voxPin;
int keyPin;
bool isTX = false;
bool pttEnabled = false;
bool voxEnabled = false;
bool keyEnabled = false;
bool catEnabled = false;
bool voxActive = false;
bool L_voxActive = false;
bool keyDown = false;
bool L_keyDown = false;
bool catActive = false;
bool L_catActive = false;
};
extern UBitxTR TR;
#endif
//======================================================================
// EOF
//======================================================================

65
TeensyDSP/TeensyDSP.h Normal file
View File

@@ -0,0 +1,65 @@
/*
Configuration file for Nextion LCD and Control MCU
The parameter can be set according to the CPU used.
KD8CEC, Ian Lee
-----------------------------------------------------------------------
**********************************************************************/
#include <Arduino.h>
#include "Debug.h"
#include "DSP.h"
#include "Nextion.h"
#include "Sensors.h"
#include "TR.h"
//================================================================
//COMMUNICATION SECTION
//================================================================
//================================================================
// FFT and Decode Morse
//================================================================
#define FFTSIZE 64
#define SAMPLE_FREQUENCY 6000
#define SAMPLESIZE (FFTSIZE * 2)
#define DECODE_MORSE_SAMPLESIZE 48
extern uint8_t cwDecodeHz;
extern int magnitudelimit_low;
//================================================================
// EEPROM Section
//================================================================
#define MAX_FORWARD_BUFF_LENGTH 128
#define EEPROM_DSPTYPE 100
#define EEPROM_SMETER_UART 111
#define EEPROM_SMETER_TIME 112
#define EEPROM_CW_FREQ 120
//#define EEPROM_CW_MAG_LIMIT 121
#define EEPROM_CW_MAG_LOW 122
#define EEPROM_CW_NBTIME 126
#define EEPROM_RTTYDECODEHZ 130
//================================================================
// DEFINE for I2C Command
//================================================================
//S-Meter Address
#define I2CMETER_ADDR 0x58 //changed from 0x6A
//VALUE TYPE============================================
//Signal
#define I2CMETER_CALCS 0x59 //Calculated Signal Meter
#define I2CMETER_UNCALCS 0x58 //Uncalculated Signal Meter
//Power
#define I2CMETER_CALCP 0x57 //Calculated Power Meter
#define I2CMETER_UNCALCP 0x56 //UnCalculated Power Meter
//SWR
#define I2CMETER_CALCR 0x55 //Calculated SWR Meter
#define I2CMETER_UNCALCR 0x54 //Uncalculated SWR Meter

670
TeensyDSP/TeensyDSP.ino Normal file
View File

@@ -0,0 +1,670 @@
/*
FFT, CW Decode for uBITX
KD8CEC, Ian Lee
Version : 0.8
-----------------------------------------------------------------------
License : See fftfunctions.cpp for FFT and CW Decode.
**********************************************************************/
#include <ADC.h>
#include <i2c_t3.h> // using i2c_t3 library for multiple I2C busses
#include <EEPROM.h>
#include "TeensyDSP.h"
//const uint8_t responseHeader[11]={'p', 'm', '.', 's', 'p', '.', 't', 'x', 't', '=', '"'}; //for Spectrum from DSP
//const uint8_t responseFooter[4]={'"', 0xFF, 0xFF, 0xFF};
//const char hexCodes[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', };
unsigned long SAMPLE_INTERVAL = 0;
int i2cCommand = 0;
//void calculateCoeff(uint8_t freqIndex);
uint8_t cwDecodeHz = 9;
int magnitudelimit_low = 30;
char forwardBuff[MAX_FORWARD_BUFF_LENGTH + 1];
static int nowBuffIndex = 0;
static char etxCount = 0;
static char nowSendingProtocol = 0;
uint8_t SMeterToUartSend = 0; //0 : Send, 1: Idle
uint8_t SMeterToUartIdleCount = 0;
#define SMeterToUartInterval 4
char DSPType = 1; //0 : Not Use, 1 : FFT, 2 : Morse Decoder, 3 : RTTY Decoder
char FFTToUartIdleCount = 0;
#define FFTToUartInterval 2
elapsedMillis sinceForward = 0;
uint8_t responseCommand = 0; //
bool isTX = false;
/**********************************************************************/
void responseConfig()
{
if (responseCommand == 2)
{
unsigned long returnValue = 0;
if (DSPType == 0)
{
returnValue = 94; //None
}
else if (DSPType == 1)
{
returnValue = 95; //Spectrum (FFT) mode
}
else if (DSPType == 2)
{
returnValue = 100 + cwDecodeHz;
}
returnValue = returnValue << 8;
returnValue = returnValue | (SMeterToUartSend & 0xFF);
returnValue = returnValue << 8;
uint8_t tmpValue = 0;
if (magnitudelimit_low > 255)
tmpValue = 255;
else if (magnitudelimit_low < 1)
tmpValue = 0;
else
tmpValue = magnitudelimit_low;
returnValue = returnValue | (tmpValue & 0xFF);
sendCommandUL('v', returnValue); //Return data
sendCommandUL('g', 0x6A); //Return data
}
responseCommand = 0;
}
//Result : if found .val=, 1 else 0
/*!
@brief Parse commands...
*/
char commandParser(int lastIndex)
{
//Analysing Forward data
//59 58 68 4A 1C 5F 6A E5 FF FF 73
//Find Loopback protocol
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
//70 6D 2E 76 76 2E 76 61 6C 3D 33 38 34 38 39 35 33 36 32 38 FF FF FF
//pm.vv.val=3848953628\xFF\xFF\xFF
//1234567890XXX
//
int startIndex = 0;
//Loop back command has 13 ~ 23
if (lastIndex < 13)
{
return 0;
}
//Protocol MAX Length : 22
if (lastIndex >= 22)
{
startIndex = lastIndex - 22;
}
else
{
startIndex = 0;
}
for (int i = lastIndex - 3; i >= startIndex + 7; i--)
{
//Find =
if (forwardBuff[i - 3] == 'v' && forwardBuff[i - 2] == 'a' && forwardBuff[i - 1] == 'l' && forwardBuff[i] == '=') //0x3D
{
uint8_t command1 = forwardBuff[i - 6]; //v
uint8_t command2 = forwardBuff[i - 5]; //v
// i-4 //.
forwardBuff[lastIndex - 2] = 0;
long commandVal = atol(&forwardBuff[i + 1]);
uint8_t *readBuff = (uint8_t *)&commandVal;
//Loop Back
if (command1 == 'v' && command2 == 'v')
{
int calcChecksum = readBuff[0] + readBuff[1] + readBuff[2];
calcChecksum = calcChecksum % 256;
//Correct Checksum and Receiver is DSP Moudle protocol v1.0
if (calcChecksum == readBuff[3] && readBuff[2] == 0x6A)
{
//Serial1.print("Correct Checksum Command : ");
//Serial1.println(readBuff[1]);
uint8_t cmd1 = readBuff[1];
if (cmd1 == 94)
{
DSPType = 0;
EEPROM.put(EEPROM_DSPTYPE, DSPType);
}
else if (cmd1 == 95)
{
//Serial1.println("Spectrum Mode");
DSPType = 1;
EEPROM.put(EEPROM_DSPTYPE, DSPType);
}
else if (cmd1 >= 100 && cmd1 <= 145)
{
cwDecodeHz = cmd1 - 100;
//calculateCoeff(cwDecodeHz);
DSPType = 2;
EEPROM.put(EEPROM_DSPTYPE, DSPType);
EEPROM.put(EEPROM_CW_FREQ, cwDecodeHz);
}
else if (cmd1 > 1 && cmd1 <= 5) //2~5 : Request Configuration
{
responseCommand = cmd1;
}
else if (cmd1 == 50 || cmd1 == 51) //Set Configuration
{
SMeterToUartSend = (cmd1 == 51);
EEPROM.put(EEPROM_SMETER_UART, SMeterToUartSend);
}
else if (cmd1 >= 146 && cmd1 <= 156 )
{
//Save Mode
magnitudelimit_low = (cmd1 - 146) * 10;
EEPROM.put(EEPROM_CW_MAG_LOW, magnitudelimit_low);
} //end of if
} //end of check Checksum
} //end of check Protocol (vv)
else if (command1 == 'c' && command2 == 't') //TX, RX
{
if (commandVal == 0) //RX
{
isTX = false;
SMeterToUartIdleCount = 0;
}
else if (commandVal == 1) //TX
{
isTX = true;
SMeterToUartIdleCount = 0;
}
}
return 1;
} //end of check Protocol (.val)
} //end of for
//Not found Protocol (.val=
return 0;
}
//#define PROTOCOL_TIMEOUT = 100
/*!
@brief Forwards serial data from the RX line to the TX line.
*/
void forwardData(void)
{
char recvChar;
if (Serial1.available() > 0)
{
Serial1.flush();
// Check RX buffer for available data.
while (Serial1.available() > 0)
{
recvChar = char(Serial1.read());
forwardBuff[nowBuffIndex] = recvChar;
if (recvChar == 0xFF) // found ETX
{
etxCount++; // Nextion protocol, ETX: 0xFF, 0xFF, 0xFF
if (etxCount >= 3)
{
// Finished Protocol
if (commandParser(nowBuffIndex) == 1)
{
nowSendingProtocol = 0; // finished 1 set command
etxCount = 0;
nowBuffIndex = 0;
}
}
}
else
{
nowSendingProtocol = 1; // sending data
etxCount = 0;
}
Serial1.write(recvChar);
sinceForward = 0;
nowBuffIndex++;
if (nowBuffIndex > MAX_FORWARD_BUFF_LENGTH - 2)
{
nowBuffIndex = 0;
}
}
Serial1.flush();
}
else
{
// check timeout
}
}
/**********************************************************************/
void sendMeterData(uint8_t isSend)
{
scaledSMeter = Sensors.sMeterScaled();
/*
1 : with noise (not use 0 ~ S3)
2 : -93 ~ -89
3 : -88 ~ -81
4 : -80 ~ -78
5 : -77 ~ -72
6 : -71 ~ -69
*/
if (isSend == 1)
{
if (L_scaledSMeter != scaledSMeter)
{
L_scaledSMeter = scaledSMeter;
sendCommand1Num(CMD_SMETER, L_scaledSMeter);
}
}
}
/**********************************************************************/
//void sendFFTData(void)
//{
// int readValue = 0;
// for (int i = 0; i < 11; i++)
// Serial1.write(responseHeader[i]);
//
// for(int i = 1; i < 64; i++)
// {
// readValue = (int)(FFTReal[i]);
// if (readValue < 0)
// {
// readValue = 0;
// }
// else if (readValue>255)
// {
// readValue=255;
// }
// Serial1.write(hexCodes[readValue >> 4]);
// Serial1.write(hexCodes[readValue & 0xf]);
// }
//
// for (int i = 0; i < 4; i++)
// Serial1.write(responseFooter[i]);
//}
void setup()
{
// load configuration
EEPROM.get(EEPROM_DSPTYPE, DSPType);
if (DSPType > 5)
{
DSPType = 1;
}
// signal meter
EEPROM.get(EEPROM_SMETER_UART, SMeterToUartSend);
if (SMeterToUartSend > 2)
{
SMeterToUartSend = 1;
}
// something with CW decoding...
EEPROM.get(EEPROM_CW_FREQ, cwDecodeHz);
if (cwDecodeHz > 40 || cwDecodeHz < 1)
{
cwDecodeHz = 9;
}
// EEPROM_CW_MAG_LOW
EEPROM.get(EEPROM_CW_MAG_LOW, magnitudelimit_low);
if (magnitudelimit_low > 1000 || magnitudelimit_low < 1)
{
magnitudelimit_low = 50;
}
// put your setup code here, to run once:
// slave Wire1 configuration for communication with the Raduino
Wire1.begin(I2CMETER_ADDR);
Wire1.onReceive(i2cReceiveEvent);
Wire1.onRequest(i2cRequestEvent);
// Serial1 configuration for communication with Raduino (RX) and Nextion (TX)
Serial1.begin(9600, SERIAL_8N1);
Serial1.flush();
SAMPLE_INTERVAL = round(1000000 * (1.0 / SAMPLE_FREQUENCY));
//calculateCoeff(cwDecodeHz); //Set 750Hz //9 * 50 + 300 = 750Hz
//Serial1.println("Start...");
DBGCMD( DSP.begin() );
DBGCMD( TR.begin() );
}
/*!
@brief Receive a command via I2C. The most recent command will be received, which will
indicate which data the DSP should be preparing to return.
@param numBytes
Number of bytes received--not used in this procedure.
*/
void i2cReceiveEvent(size_t numBytes)
{
int readCommand = 0;
while (Wire1.available() > 0) // for Last command
{
readCommand = Wire1.read();
// KC4UPR: Note that this looks to be only reading the last command, i.e.
// if multiple commands have been queued up, only the last will get executed.
}
if (0x50 <= readCommand && readCommand <= 0x59)
{
i2cCommand = readCommand;
}
}
/*!
@brief Respond to a request from the I2C Master (Raduino). Returns the appropriate data
based on whatever command was previously issued.
*/
void i2cRequestEvent(void)
{
//int maxValue = 0;
//int minValue = 30000;
//int readValue = 0;
//unsigned long curr = 0;
switch (i2cCommand) {
case I2CMETER_CALCS:
// Returns an already-calculated S-meter value.
Wire1.write(scaledSMeter);
break;
case I2CMETER_UNCALCS:
// Returns a raw signal strength value.
Wire1.write(Sensors.sMeterUnscaled() >> 2); // divided by 4... do we want this?
break;
case I2CMETER_CALCP:
// Returns a raw forward power value.
Wire1.write(fwdPower);
break;
case I2CMETER_CALCR:
// Returns a raw reverse power value.
Wire1.write(revPower);
break;
default:
break;
}
}
//extern void Decode_Morse(float magnitude);
//extern double coeff;
#define LAST_TIME_INTERVAL 159
// for boot delay, a lot of data to transfer
// Delay 2.5 Sec
byte isBooted = 0;
//======================================================================
// ADC PROCESSES
//======================================================================
elapsedMillis sinceFrameMillis = 0;
elapsedMillis sinceADCMillis = 0;
#define FRAME_RATE 40
#define FRAME_INTERVAL_MS (1000/FRAME_RATE)
const int frameIntervalMillis = FRAME_INTERVAL_MS;
#define ADC_SAMPLE_RATE 120
#define ADC_INTERVAL_MS (1000/ADC_SAMPLE_RATE)
const int adcIntervalMillis = ADC_INTERVAL_MS;
//======================================================================
// MAIN LOOP
//======================================================================
#ifdef DEBUG
int frameCounter = 0;
#endif
void loop()
{
//char isProcess = 0; // 0: init, 1: complete ADC sampling, 2: complete FFT
//isProcess = 0;
forwardData();
if (isBooted < 100)
{
//Delay 20msec
for (int i = 0; i < 20; i++)
{
forwardData();
delay(1);
}
isBooted++;
return;
}
if (sinceFrameMillis > frameIntervalMillis) {
// Do stuff that we do once per frame--I/O.
// TODO: debug output (frame skipping / utilization).
sinceFrameMillis = 0;
#ifdef DEBUG
// For debugging, output some debug info every 1.0" (40 frames @ 40 Hz).
frameCounter++;
if (frameCounter % 40 == 0) {
Serial.print("DBG: Frame: ");
Serial.print(frameCounter);
if (isTX) {
Serial.print(", Loop State: TX");
} else {
Serial.print(", Loop State: RX");
}
if (TR.transmitting()) {
Serial.println(", TR State: TX");
} else {
Serial.println(", TR State: RX");
}
Serial.print("DBG: S-Meter Raw: ");
Serial.print(Sensors.sMeterUnscaled());
Serial.print(", S-Meter Scaled: ");
Serial.println(scaledSMeter);
Serial.print("DBG: VSWR Calc: ");
Serial.print(calcVSWR, 2);
Serial.print(", VSWR Scaled: ");
Serial.print(scaledVSWR);
Serial.print(", FWD PWR: ");
Serial.print(fwdPower, 2);
Serial.print(", REV PWR: ");
Serial.println(revPower, 2);
}
#endif
TR.update();
if (isTX) {
calcVSWR = Sensors.VSWR();
scaledVSWR = byte(Sensors.scaledVSWR());
fwdPower = Sensors.Pfwd();
revPower = Sensors.Prev();
// Send SWR meter information.
if (L_scaledVSWR != scaledVSWR) {
L_scaledVSWR = scaledVSWR;
sendCommand1Num(CMD_SMETER, scaledVSWR);
}
// Send forward power.
if (L_fwdPower != fwdPower) {
L_fwdPower = fwdPower;
sendCommandL('m', fwdPower * 100); // watts x 100?
sendCommand1Num('m', 2);
}
// Send reverse power.
//if (L_revPower != revPower) {
// L_revPower = revPower;
// sendCommandL('m', revPower * 100); // watts x 100?
// sendCommand1Num('m', 2);
//}
// Does there need to be some kind of 250-500ms delay after this???
// Delay 250msec ~ 500msec for Nextion LCD Processing (using m protocol)
//for (int i = 0; i < 10; i++) {
// forwardData();
// if (!isTX) { //if TX -> RX break
// break;
// }
// delay(25);
//} //end of delay time
// Send SWR.
if (L_calcVSWR != calcVSWR) {
L_calcVSWR = calcVSWR;
sendCommandL('m', int(calcVSWR * 100.0)); // SWR x 100?
sendCommand1Num('m', 3);
}
} else { // RX
// Send Signal Meter to UART
if (SMeterToUartSend == 1 && nowSendingProtocol == 0) //SMeter To Uart Send
{
//nowSendingProtocol -> not finished data forward, (not found 0xff, 0xff, 0xff yet)
sendMeterData(1);
} else {
sendMeterData(0); //only calculate Signal Level
}
}
// Forward any data that came in while we were updating stuff.
forwardData();
}
if (sinceADCMillis > adcIntervalMillis) {
// Do stuff that we do once per ADC interval--ADC colllection.
// TODO: debug output (frame skipping / utilization).
sinceADCMillis = 0;
if (isTX) {
Sensors.updatePower();
} else { // RX
Sensors.updateSMeter();
Sensors.updateSupply();
}
// Forward any data that came in while we were reading sensors.
//forwardData();
}
// Check Response Command
if (responseCommand > 0 && sinceForward > LAST_TIME_INTERVAL)
{
responseConfig();
}
// //===========================================
// //TRANSCEIVER STATUS : RX
// //===========================================
// //===================================================================================
// // DSP Routine
// //===================================================================================
// if (DSPType == 1 && sinceForward > LAST_TIME_INTERVAL) // spectrum: FFT => send To UART
// {
// FFTToUartIdleCount = 0;
//
// if (isProcess == 1)
// {
// FFT(FFTReal, FFTImag, SAMPLESIZE, 7);
// isProcess = 2;
// }
//
// forwardData();
//
// if (isProcess == 2)
// {
// for (uint16_t k = 0; k < SAMPLESIZE; k++)
// {
// FFTReal[k] = sqrt(FFTReal[k] * FFTReal[k] + FFTImag[k] * FFTImag[k]);
// }
//
// isProcess = 3;
// }
//
// forwardData();
//
// if (isProcess == 3)
// {
// if (nowSendingProtocol == 0) //Idle Status
// {
// sendFFTData();
// }
// }
// }
// else if (DSPType == 2) //Decode Morse
// {
// //Implement Goertzel_algorithm
// //https://en.wikipedia.org/wiki/Goertzel_algorithm
//
// /*
// ω = 2 * π * Kterm / Nterms;
// cr = cos(ω);
// ci = sin(ω);
// coeff = 2 * cr;
//
// sprev = 0;
// sprev2 = 0;
// for each index n in range 0 to Nterms-1
// s = x[n] + coeff * sprev - sprev2;
// sprev2 = sprev;
// sprev = s;
// end
//
// power = sprev2 * sprev2 + sprev * sprev - coeff * sprev * sprev2;
// */
// double Q1 = 0;
// double Q2 = 0;
//
// for (unsigned index = 0; index < DECODE_MORSE_SAMPLESIZE; index++)
// {
// float Q0;
// Q0 = coeff * Q1 - Q2 + FFTReal[index];
// Q2 = Q1;
// Q1 = Q0;
// }
// double magnitudeSquared = (Q1*Q1)+(Q2*Q2)-Q1*Q2*coeff; // we do only need the real part //
// double magnitude = sqrt(magnitudeSquared);
//
// Decode_Morse(magnitude);
// } //end of if
}
//======================================================================
// EOF
//======================================================================

240
raduino-tmp/README.md Normal file
View File

@@ -0,0 +1,240 @@
<<<<<<< HEAD
Stand-in README.md while I merge several repos into this project.
=======
#NOTICE
----------------------------------------------------------------------------
- Now Release Version 1.20 on my blog (http://www.hamskey.com)
- You can download and compiled hex file and uBITX Manager application on release section (https://github.com/phdlee/ubitx/releases)
- For more information, see my blog (http://www.hamskey.com)
http://www.hamskey.com
Ian KD8CEC
kd8cec@gmail.com
#uBITX
uBITX firmware, written for the Raduino/Arduino control of uBITX transceivers
This project is based on https://github.com/afarhan/ubitx and all copyright is inherited.
The copyright information of the original is below.
KD8CEC
----------------------------------------------------------------------------
Prepared or finished tasks for the next version
- Add TTS module
- Direct control for Student
----------------------------------------------------------------------------
## REVISION RECORD
1.20
- Support uBITX V5
- Change to SDR Frequency (Remove just RTL-SDR's error Frequency (2390Hz))
1.12
- Support Custom LPF Control
- Other Minor Bugs
1.1
- Support Nextion LCD, TJC LCD
- Read & Backup uBITX, ADC Monitoring, ATT, IF-Shift and more on Nextion LCD (TJC LCD)
- Factory Reset (Both Character LCD and Nextion LCD are applicable)
- Support Signal Meter using ADC (A7 Port)
- Supoort I2C Signal Meter
- Spectrum
- Band Scan
- Memory Control on Nextion LCD (TJC LCD)
- Speed Change CW-Option on Nextion LCD
- Fixed Band Change Bug (Both Character LCD and Nextion LCD are applicable)
- uBITX Manager removed the Encode and Decode buttons. The procedure has become a bit easier.
- I2C Device Scan on uBITX Manager ( Both Character LCD and Nextion LCD are applicable)
- Si5351 I2C Address can be changed
- Recovery using QR-Code Data from Server
- Nextion LCD and TJC LCD can display Spectrum and CW Decode (using Stand alone S-Meter)
- Other Minor Bugs
1.09 (Beta)
- include 1.094 beta, 1.095 beta, 1.097 beta
1.08
- Receive performance is improved compared to the original firmware or version 1.061
- ATT function has been added to reduce RF gain (Shift 45Mhz IF)
- Added the ability to connect SDR. (Low cost RTL-SDR available)
- Added a protocol to ADC Monitoring in CAT communications
- Various LCD support, 16x02 Parallel LCD - It is the LCD equipped with uBITX, 16x02 I2C LCD, 20x04 Parallel LCD, 20x04 I2C LCD, 16x02 I2C Dual LCD
- Added Extended Switch Support
- Support S Meter
- Added S-Meter setting assistant to uBITX Manager
- Add recovery mode (such as Factory Reset)
- There have been many other improvements and fixes. More information is available on the blog. (http://www.hamskey.com)
1.07 (Beta)
- include 1.071 beta, 1.073 beta, 1.075 beta
- Features implemented in the beta version have been applied to Version 1.08 above.
1.061
- Added WSPR
You only need uBITX to use WSPR. No external devices are required.
Added Si5351 module for WSPR
- Update uBITX Manager to Version 1.0
- Reduce program size
for WSPR
for other Module
- Fixed IF Shift Bug
Disable IF Shift on TX
IF shift available in USB mode
Fixed cat routine in IF Shift setup
- Bugs fixed
cw start delay option
Auto key Bug
(found bug : LZ1LDO)
Message selection when Auto Key is used in RIT mode
(found bug : gerald)
- Improve CW Keying (start TX)
1.05
- include 1.05W, 1.051, 1.051W
- for WSPR Beta Test Version
1.04
- Optimized from Version1.03
- Reduce program size (97% -> 95%)
1.03
- Change eBFO Calibration Step (50 to 5)
- Change CW Frequency Display type
1.02
- Applied CW Start Delay to New CW Key logic (This is my mistake when applying the new CW Key Logic.Since uBITX operations are not significantly affected, this does not create a separate Release, It will be reflected in the next release.) - complete
- Modified CW Key Logic for Auto Key, (available AutoKey function by any cw keytype) - complete
- reduce cpu use usage (working)
- reduce (working)
1.01
- Fixed Cat problem with (IAMBIC A or B Selected)
1.0
- rename 0.30 to 1.0
0.35
- vfo to channel bug fixed (not saved mode -> fixed, channel has frequency and mode)
- add Channel tag (ch.1 ~ 10) by uBITX Manager
- add VFO to Channel, Channel To VFO
0.34
- TX Status check in auto Keysend logic
- optimize codes
- change default tune step size, and fixed bug
- change IF shift step (1Hz -> 50Hz)
0.33
- Added CWL, CWU Mode, (dont complete test yet)
- fixed VFO changed bug.
- Added Additional BFO for CWL, CWL
- Added IF Shift
- Change confirmation key PTT -> function key (not critical menus)
- Change CW Key Select type, (toggle -> select by dial)
0.32
- Added function Scroll Frequencty on upper line
- Added Example code for Draw meter and remarked (you can see and use this code in source codes)
- Added Split function, just toggle VFOs when TX/RX
0.31
- Fixed CW ADC Range error
- Display Message on Upper Line (anothor VFO Frequency, Tune Step, Selected Key Type)
0.30
- implemented the function to monitor the value of all analog inputs. This allows you to monitor the status of the CW keys connected to your uBITX.
- possible to set the ADC range for CW Keying. If no setting is made, it will have the same range as the original code. If you set the CW Keying ADC Values using uBITX Manager 0.3, you can reduce the key error.
- Added the function to select Straight Key, IAMBICA, IAMBICB key from the menu.
- default Band select is Ham Band mode, if you want common type, long press function key at band select menu, uBITX Manager can be used to modify frequencies to suit your country.
0.29
- Remove the use of initialization values in BFO settings - using crruent value, if factory reset
- Select Tune Step, default 0, 20, 50, 100, 200, Use the uBITX Manager to set the steps value you want. You can select Step by pressing and holding the Function Key (1sec ~ 2sec).
- Modify Dial Lock Function, Press the Function key for more than 3 seconds to toggle dial lock.
- created a new frequency tune method. remove original source codes, Threshold has been applied to reduce malfunction. checked the continuity of the user operating to make natural tune possible.
- stabilize and remove many warning messages - by Pullrequest and merge
- Changed cw keying method. removed the original code and applied Ron's code and Improved compatibility with original hardware and CAT commnication. It can be used without modification of hardware.
0.28
- Fixed CAT problem with hamlib on Linux
- restore Protocol autorecovery logic
0.27
(First alpha test version, This will be renamed to the major version 1.0)
- Dual VFO Dial Lock (vfoA Dial lock)
- Support Ham band on uBITX
default Hamband is regeion1 but customize by uBITX Manager Software
- Advanced ham band options (Tx control) for use in all countries. You can adjust it yourself.
- Convenience of band movement
0.26
- only Beta tester released & source code share
- find a bug on none initial eeprom uBITX - Fixed (Check -> initialized & compatible original source code)
- change the version number 0.26 -> 0.27
- Prevent overflow bugs
- bug with linux based Hamlib (raspberry pi), It was perfect for the 0.224 version, but there was a problem for the 0.25 version.
On Windows, ham deluxe, wsjt-x, jt65-hf, and fldigi were successfully run. Problem with Raspberry pi.
0.25
- Beta Version Released
http://www.hamskey.com/2018/01/release-beta-version-of-cat-support.html
- Added CAT Protocol for uBITX
- Modified the default usb carrier value used when the setting is wrong.
- Fixed a routine to repair when the CAT protocol was interrupted.
0.24
- Program optimization
reduce usage ram rate (string with M() optins)
- Optimized CAT protocol for wsjt-x, fldigi
0.23
- added delay_background() , replace almost delay() to delay_background for prevent timeout
- cat library compatible with FT-817 Command
switch VFOA / VFOB,
Read Write CW Speed
Read Write CW Delay Time
Read Write CW Pitch (with sidetone)
All of these can be controlled by Hamradio deluxe.
- modified cat libray function for protocol for CAT communication is not broken in CW or TX mode
- Ability to change CW Delay
- Added Dial Lock function
- Add functions CW Start dely (TX -> CW interval)
- Automatic storage of VFO frequency
It was implemented by storing it only once when the frequency stays 10 seconds or more after the change.
(protect eeprom life)
0.22
- fixed screen Update Problem
- Frequency Display Problem - Problems occur below 1Mhz
- added function Enhanced CAT communication
- replace ubitx_cat.ino to cat_libs.ino
- Save mode when switching to VFOA / VFOB
0.21
- fixed the cw side tone configuration.
- Fix the error that the frequency is over.
- fixed frequency display (alignment, point)
0.20
- original uBITX software (Ashhar Farhan)
## Original README.md
uBITX firmware, written for the Raduino/Arduino control of uBITX transceigers
Copyright (C) 2017, Ashhar Farhan
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
>>>>>>> raduino/master

View File

@@ -0,0 +1,30 @@
This file will guide you to change the source code file.
For Windows-based Arduino IDE users, the directory name and the Main source file name must be the same.
You do not need to learn github to download .hex files or source code that I release.
However, if you want to see what I'm doing right now, you should use the github homepage.
You do not need to learn git to suggest source code. If you give me an e-mail, I will correct it at any time.
If you have not joined the BITX Group, join group. There will be discussions on various topics every day.
I am getting a lot of hints from the group.
Ian KD8CEC
kd8cec@gmail.com
==================================================================
Files modified in Version1.08 Beta
1.Delted Files.
2.Added Files
3.Modified Files
- ubitx_20.ino
- ubitx_ui.ino
- cat_libs.ino
- ubitx.h
- ubitx_eemap.h
- ubitx_lcd_1602.ino
- ubitx_lcd_1602Dual.ino
- ubitx_lcd_2004.ino
- ubitx_wspr.ino

View File

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

674
teensydsp-tmp/LICENSE Normal file
View File

@@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

14
teensydsp-tmp/README.md Normal file
View File

@@ -0,0 +1,14 @@
# dspmeterv1
Please also refer to the site below.
https://github.com/soligen2010/dspmeterv1
-------------------------------------------
Standalone Signal Analyzer (I2C Type Signal-Meter) for uBITX - Arduino Nano Version
I do not claim any license for my code.
You may use it in any way. I just hope this will be used for amateur radio.
The other person's source code (CW Morse code) follows the original author's license.
Ian KD8CEC

View File

@@ -1,940 +0,0 @@
/**
* This source file is under General Public License version 3.
*
* This verision uses a built-in Si5351 library
* Most source code are meant to be understood by the compilers and the computers.
* Code that has to be hackable needs to be well understood and properly documented.
* Donald Knuth coined the term Literate Programming to indicate code that is written be
* easily read and understood.
*
* The Raduino is a small board that includes the Arduin Nano, a 16x2 LCD display and
* an Si5351a frequency synthesizer. This board is manufactured by Paradigm Ecomm Pvt Ltd
*
* To learn more about Arduino you may visit www.arduino.cc.
*
* The Arduino works by starts executing the code in a function called setup() and then it
* repeatedly keeps calling loop() forever. All the initialization code is kept in setup()
* and code to continuously sense the tuning knob, the function button, transmit/receive,
* etc is all in the loop() function. If you wish to study the code top down, then scroll
* to the bottom of this file and read your way up.
*
* Below are the libraries to be included for building the Raduino
* The EEPROM library is used to store settings like the frequency memory, caliberation data,
* callsign etc .
*
* The main chip which generates upto three oscillators of various frequencies in the
* Raduino is the Si5351a. To learn more about Si5351a you can download the datasheet
* from www.silabs.com although, strictly speaking it is not a requirment to understand this code.
* Instead, you can look up the Si5351 library written by xxx, yyy. You can download and
* install it from www.url.com to complile this file.
* The Wire.h library is used to talk to the Si5351 and we also declare an instance of
* Si5351 object to control the clocks.
*/
#include <Wire.h>
#include <EEPROM.h>
/**
The main chip which generates upto three oscillators of various frequencies in the
Raduino is the Si5351a. To learn more about Si5351a you can download the datasheet
from www.silabs.com although, strictly speaking it is not a requirment to understand this code.
We no longer use the standard SI5351 library because of its huge overhead due to many unused
features consuming a lot of program space. Instead of depending on an external library we now use
Jerry Gaffke's, KE7ER, lightweight standalone mimimalist "si5351bx" routines (see further down the
code). Here are some defines and declarations used by Jerry's routines:
*/
/**
* We need to carefully pick assignment of pin for various purposes.
* There are two sets of completely programmable pins on the Raduino.
* First, on the top of the board, in line with the LCD connector is an 8-pin connector
* that is largely meant for analog inputs and front-panel control. It has a regulated 5v output,
* ground and six pins. Each of these six pins can be individually programmed
* either as an analog input, a digital input or a digital output.
* The pins are assigned as follows (left to right, display facing you):
* Pin 1 (Violet), A7, SPARE
* Pin 2 (Blue), A6, KEYER (DATA)
* Pin 3 (Green), +5v
* Pin 4 (Yellow), Gnd
* Pin 5 (Orange), A3, PTT
* Pin 6 (Red), A2, F BUTTON
* Pin 7 (Brown), A1, ENC B
* Pin 8 (Black), A0, ENC A
*Note: A5, A4 are wired to the Si5351 as I2C interface
* *
* Though, this can be assigned anyway, for this application of the Arduino, we will make the following
* assignment
* A2 will connect to the PTT line, which is the usually a part of the mic connector
* A3 is connected to a push button that can momentarily ground this line. This will be used for RIT/Bandswitching, etc.
* A6 is to implement a keyer, it is reserved and not yet implemented
* A7 is connected to a center pin of good quality 100K or 10K linear potentiometer with the two other ends connected to
* ground and +5v lines available on the connector. This implments the tuning mechanism
*/
#define ENC_A (A0)
#define ENC_B (A1)
#define FBUTTON (A2)
#define PTT (A3)
#define ANALOG_KEYER (A6)
#define ANALOG_SPARE (A7)
/**
* The Raduino board is the size of a standard 16x2 LCD panel. It has three connectors:
*
* First, is an 8 pin connector that provides +5v, GND and six analog input pins that can also be
* configured to be used as digital input or output pins. These are referred to as A0,A1,A2,
* A3,A6 and A7 pins. The A4 and A5 pins are missing from this connector as they are used to
* talk to the Si5351 over I2C protocol.
*
* Second is a 16 pin LCD connector. This connector is meant specifically for the standard 16x2
* LCD display in 4 bit mode. The 4 bit mode requires 4 data lines and two control lines to work:
* Lines used are : RESET, ENABLE, D4, D5, D6, D7
* We include the library and declare the configuration of the LCD panel too
*/
#include <LiquidCrystal.h>
LiquidCrystal lcd(8,9,10,11,12,13);
#define VERSION_NUM 0x01 //for KD8CEC'S firmware and for memory management software
/**
* The Arduino, unlike C/C++ on a regular computer with gigabytes of RAM, has very little memory.
* We have to be very careful with variables that are declared inside the functions as they are
* created in a memory region called the stack. The stack has just a few bytes of space on the Arduino
* if you declare large strings inside functions, they can easily exceed the capacity of the stack
* and mess up your programs.
* We circumvent this by declaring a few global buffers as kitchen counters where we can
* slice and dice our strings. These strings are mostly used to control the display or handle
* the input and output from the USB port. We must keep a count of the bytes used while reading
* the serial port as we can easily run out of buffer space. This is done in the serial_in_count variable.
*/
char c[30], b[30];
char printBuff[2][17]; //mirrors what is showing on the two lines of the display
int count = 0; //to generally count ticks, loops, etc
/**
* 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.
* This assignment is as follows :
* Pin 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
* GND +5V CLK0 GND GND CLK1 GND GND CLK2 GND D2 D3 D4 D5 D6 D7
* These too are flexible with what you may do with them, for the Raduino, we use them to :
* - TX_RX line : Switches between Transmit and Receive after sensing the PTT or the morse keyer
* - CW_KEY line : turns on the carrier for CW
*/
#define TX_RX (7)
#define CW_TONE (6)
#define TX_LPF_A (5)
#define TX_LPF_B (4)
#define TX_LPF_C (3)
#define CW_KEY (2)
/**
* These are the indices where these user changable settinngs are stored in the EEPROM
*/
#define MASTER_CAL 0
#define LSB_CAL 4
#define USB_CAL 8
#define SIDE_TONE 12
//these are ids of the vfos as well as their offset into the eeprom storage, don't change these 'magic' values
#define VFO_A 16
#define VFO_B 20
#define CW_SIDETONE 24
#define CW_SPEED 28
//AT328 has 1KBytes EEPROM
#define VFO_A_MODE 256
#define VFO_B_MODE 257
#define CW_DELAY 258
#define CW_START 259
#define HAM_BAND_COUNT 260 //
#define TX_TUNE_TYPE 261 //
#define HAM_BAND_RANGE 262 //FROM (2BYTE) TO (2BYTE) * 10 = 40byte
#define HAM_BAND_FREQS 302 //40, 1 BAND = 4Byte most bit is mode
//Check Firmware type and version
#define FIRMWAR_ID_ADDR 776 //776 : 0x59, 777 :0x58, 778 : 0x68 : Id Number, if not found id, erase eeprom(32~1023) for prevent system error.
#define VERSION_ADDRESS 779 //check Firmware version
//USER INFORMATION
#define USER_CALLSIGN_KEY 780 //0x59
#define USER_CALLSIGN_LEN 781 //1BYTE (OPTION + LENGTH) + CALLSIGN (MAXIMUM 18)
#define USER_CALLSIGN_DAT 782 //CALL SIGN DATA //direct EEPROM to LCD basic offset
//AUTO KEY STRUCTURE
//AUTO KEY USE 800 ~ 1023
#define CW_AUTO_MAGIC_KEY 800 //0x73
#define CW_AUTO_COUNT 801 //0 ~ 255
#define CW_AUTO_DATA 803 //[INDEX, INDEX, INDEX,DATA,DATA, DATA (Positon offset is CW_AUTO_DATA
#define CW_DATA_OFSTADJ CW_AUTO_DATA - USER_CALLSIGN_DAT //offset adjust for ditect eeprom to lcd (basic offset is USER_CALLSIGN_DAT
#define CW_STATION_LEN 1023 //value range : 4 ~ 30
/**
* The uBITX is an upconnversion transceiver. The first IF is at 45 MHz.
* The first IF frequency is not exactly at 45 Mhz but about 5 khz lower,
* this shift is due to the loading on the 45 Mhz crystal filter by the matching
* L-network used on it's either sides.
* The first oscillator works between 48 Mhz and 75 MHz. The signal is subtracted
* from the first oscillator to arriive at 45 Mhz IF. Thus, it is inverted : LSB becomes USB
* and USB becomes LSB.
* The second IF of 12 Mhz has a ladder crystal filter. If a second oscillator is used at
* 57 Mhz, the signal is subtracted FROM the oscillator, inverting a second time, and arrives
* at the 12 Mhz ladder filter thus doouble inversion, keeps the sidebands as they originally were.
* If the second oscillator is at 33 Mhz, the oscilaltor is subtracated from the signal,
* thus keeping the signal's sidebands inverted. The USB will become LSB.
* We use this technique to switch sidebands. This is to avoid placing the lsbCarrier close to
* 12 MHz where its fifth harmonic beats with the arduino's 16 Mhz oscillator's fourth harmonic
*/
// the second oscillator should ideally be at 57 MHz, however, the crystal filter's center frequency
// is shifted down a little due to the loading from the impedance matching L-networks on either sides
#define SECOND_OSC_USB (56995000l)
#define SECOND_OSC_LSB (32995000l)
//these are the two default USB and LSB frequencies. The best frequencies depend upon your individual taste and filter shape
#define INIT_USB_FREQ (11996500l)
// limits the tuning and working range of the ubitx between 3 MHz and 30 MHz
#define LOWEST_FREQ (3000000l)
#define HIGHEST_FREQ (30000000l)
//When the frequency is moved by the dial, the maximum value by KD8CEC
#define LOWEST_FREQ_DIAL (3000l)
#define HIGHEST_FREQ_DIAL (60000000l)
//we directly generate the CW by programmin the Si5351 to the cw tx frequency, hence, both are different modes
//these are the parameter passed to startTx
#define TX_SSB 0
#define TX_CW 1
char ritOn = 0;
char vfoActive = VFO_A;
int8_t meter_reading = 0; // a -1 on meter makes it invisible
unsigned long vfoA=7150000L, vfoB=14200000L, sideTone=800, usbCarrier;
unsigned long vfoA_eeprom, vfoB_eeprom; //for protect eeprom life
unsigned long frequency, ritRxFrequency, ritTxFrequency; //frequency is the current frequency on the dial
int cwSpeed = 100; //this is actuall the dot period in milliseconds
extern int32_t calibration;
//for store the mode in eeprom
byte vfoA_mode=0, vfoB_mode = 0; //0: default, 1:not use, 2:LSB, 3:USB, 4:CW, 5:AM, 6:FM
byte vfoA_mode_eeprom, vfoB_mode_eeprom; //for protect eeprom life
//KD8CEC
//for AutoSave and protect eeprom life
byte saveIntervalSec = 10; //second
unsigned long saveCheckTime = 0;
unsigned long saveCheckFreq = 0;
bool isSplitOn = false;
byte cwDelayTime = 60;
byte delayBeforeCWStartTime = 50;
//sideTonePitch + sideToneSub = sideTone
byte sideTonePitch=0;
byte sideToneSub = 0;
//DialLock
byte isDialLock = 0; //000000[0]vfoB [0]vfoA 0Bit : A, 1Bit : B
byte isTxType = 0; //000000[0 - isSplit] [0 - isTXStop]
//Variables for auto cw mode
byte isCWAutoMode = 0; //0 : none, 1 : CW_AutoMode_Menu_Selection, 2 : CW_AutoMode Sending
byte cwAutoTextCount = 0; //cwAutoText Count
byte beforeCWTextIndex = 255; //when auto cw start, always beforeCWTextIndex = 255, (for first time check)
byte cwAutoDialType = 0; //0 : CW Text Change, 1 : Frequency Tune
#define AUTO_CW_RESERVE_MAX 3
byte autoCWSendReserv[AUTO_CW_RESERVE_MAX]; //Reserve CW Auto Send
byte autoCWSendReservCount = 0; //Reserve CW Text Cound
byte sendingCWTextIndex = 0; //cw auto seding Text Index
byte userCallsignLength = 0; //7 : display callsign at system startup, 6~0 : callsign length (range : 1~18)
/**
* Raduino needs to keep track of current state of the transceiver. These are a few variables that do it
*/
boolean txCAT = false; //turned on if the transmitting due to a CAT command
char inTx = 0; //it is set to 1 if in transmit mode (whatever the reason : cw, ptt or cat)
char splitOn = 0; //working split, uses VFO B as the transmit frequency, (NOT IMPLEMENTED YET)
char keyDown = 0; //in cw mode, denotes the carrier is being transmitted
char isUSB = 0; //upper sideband was selected, this is reset to the default for the
//frequency when it crosses the frequency border of 10 MHz
byte menuOn = 0; //set to 1 when the menu is being displayed, if a menu item sets it to zero, the menu is exited
unsigned long cwTimeout = 0; //milliseconds to go before the cw transmit line is released and the radio goes back to rx mode
unsigned long dbgCount = 0; //not used now
unsigned char txFilter = 0; //which of the four transmit filters are in use
boolean modeCalibrate = false;//this mode of menus shows extended menus to calibrate the oscillators and choose the proper
//beat frequency
/**
* Below are the basic functions that control the uBitx. Understanding the functions before
* you start hacking around
*/
//Ham Band
#define MAX_LIMIT_RANGE 10 //because limited eeprom size
byte useHamBandCount = 0; //0 use full range frequency
byte tuneTXType = 0; //0 : use full range, 1 : just Change Dial speed, 2 : just ham band change, but can general band by tune, 3 : only ham band (just support 0, 2 (0.26 version))
//100 : use full range but not TX on general band, 101 : just change dial speed but.. 2 : jut... but.. 3 : only ham band (just support 100, 102 (0.26 version))
unsigned int hamBandRange[MAX_LIMIT_RANGE][2]; // = //Khz because reduce use memory
//-1 : not found, 0 ~ 9 : Hamband index
char getIndexHambanBbyFreq(unsigned long f)
{
f = f / 1000;
for (byte i = 0; i < useHamBandCount; i++)
if (hamBandRange[i][0] <= f && f < hamBandRange[i][1])
return i;
return -1;
}
//when Band change step = just hamband
//moveDirection : 1 = next, -1 : prior
void setNextHamBandFreq(unsigned long f, char moveDirection)
{
unsigned long resultFreq = 0;
byte loadMode = 0;
char findedIndex = getIndexHambanBbyFreq(f);
if (findedIndex == -1) { //out of hamband
f = f / 1000;
for (byte i = 0; i < useHamBandCount -1; i++) {
if (hamBandRange[i][1] <= f && f < hamBandRange[i + 1][0]) {
findedIndex = i + moveDirection;
//return (unsigned long)(hamBandRange[i + 1][0]) * 1000;
}
} //end of for
}
else if (((moveDirection == 1) && (findedIndex < useHamBandCount -1)) || //Next
((moveDirection == -1) && (findedIndex > 0)) ) { //Prior
findedIndex += moveDirection;
}
else
findedIndex = -1;
if (findedIndex == -1)
findedIndex = (moveDirection == 1 ? 0 : useHamBandCount -1);
EEPROM.get(HAM_BAND_FREQS + 4 * findedIndex, resultFreq);
loadMode = (byte)(resultFreq >> 30);
resultFreq = resultFreq & 0x3FFFFFFF;
if ((resultFreq / 1000) < hamBandRange[findedIndex][0] || (resultFreq / 1000) > hamBandRange[findedIndex][1])
resultFreq = (unsigned long)(hamBandRange[findedIndex][0]) * 1000;
setFrequency(resultFreq);
byteWithFreqToMode(loadMode);
}
void saveBandFreqByIndex(unsigned long f, unsigned long mode, char bandIndex) {
if (bandIndex >= 0)
EEPROM.put(HAM_BAND_FREQS + 4 * bandIndex, (f & 0x3FFFFFFF) | (mode << 30) );
}
/*
KD8CEC
When using the basic delay of the Arduino, the program freezes.
When the delay is used, the program will generate an error because it is not communicating,
so Create a new delay function that can do background processing.
*/
unsigned long delayBeforeTime = 0;
byte delay_background(unsigned delayTime, byte fromType){ //fromType : 4 autoCWKey -> Check Paddle
delayBeforeTime = millis();
while (millis() - delayBeforeTime <= delayTime) {
if (fromType == 4)
{
//CHECK PADDLE
if (getPaddle() != 0) //Interrupt : Stop cw Auto mode by Paddle -> Change Auto to Manual
return 1;
//Check PTT while auto Sending
autoSendPTTCheck();
Check_Cat(3);
}
else
{
//Background Work
Check_Cat(fromType);
}
}
return 0;
}
/**
* Select the properly tx harmonic filters
* The four harmonic filters use only three relays
* the four LPFs cover 30-21 Mhz, 18 - 14 Mhz, 7-10 MHz and 3.5 to 5 Mhz
* Briefly, it works like this,
* - When KT1 is OFF, the 'off' position routes the PA output through the 30 MHz LPF
* - When KT1 is ON, it routes the PA output to KT2. Which is why you will see that
* the KT1 is on for the three other cases.
* - When the KT1 is ON and KT2 is off, the off position of KT2 routes the PA output
* to 18 MHz LPF (That also works for 14 Mhz)
* - When KT1 is On, KT2 is On, it routes the PA output to KT3
* - KT3, when switched on selects the 7-10 Mhz filter
* - KT3 when switched off selects the 3.5-5 Mhz filter
* See the circuit to understand this
*/
void setTXFilters(unsigned long freq){
if (freq > 21000000L){ // the default filter is with 35 MHz cut-off
digitalWrite(TX_LPF_A, 0);
digitalWrite(TX_LPF_B, 0);
digitalWrite(TX_LPF_C, 0);
}
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
digitalWrite(TX_LPF_A, 1);
digitalWrite(TX_LPF_B, 0);
digitalWrite(TX_LPF_C, 0);
}
else if (freq > 7000000L){
digitalWrite(TX_LPF_A, 1);
digitalWrite(TX_LPF_B, 1);
digitalWrite(TX_LPF_C, 0);
}
else {
digitalWrite(TX_LPF_A, 1);
digitalWrite(TX_LPF_B, 1);
digitalWrite(TX_LPF_C, 1);
}
}
/**
* This is the most frequently called function that configures the
* radio to a particular frequeny, sideband and sets up the transmit filters
*
* The transmit filter relays are powered up only during the tx so they dont
* draw any current during rx.
*
* The carrier oscillator of the detector/modulator is permanently fixed at
* uppper sideband. The sideband selection is done by placing the second oscillator
* either 12 Mhz below or above the 45 Mhz signal thereby inverting the sidebands
* through mixing of the second local oscillator.
*/
void setFrequency(unsigned long f){
uint64_t osc_f;
//1 digits discarded
f = (f / 50) * 50;
setTXFilters(f);
if (isUSB){
si5351bx_setfreq(2, SECOND_OSC_USB - usbCarrier + f);
si5351bx_setfreq(1, SECOND_OSC_USB);
}
else{
si5351bx_setfreq(2, SECOND_OSC_LSB + usbCarrier + f);
si5351bx_setfreq(1, SECOND_OSC_LSB);
}
frequency = f;
}
/**
* startTx is called by the PTT, cw keyer and CAT protocol to
* put the uBitx in tx mode. It takes care of rit settings, sideband settings
* Note: In cw mode, doesnt key the radio, only puts it in tx mode
*/
void startTx(byte txMode, byte isDisplayUpdate){
unsigned long tx_freq = 0;
//Check Hamband only TX //Not found Hamband index by now frequency
if (tuneTXType >= 100 && getIndexHambanBbyFreq(ritOn ? ritTxFrequency : frequency) == -1) {
//no message
return;
}
if ((isTxType & 0x01) != 0x01)
digitalWrite(TX_RX, 1);
inTx = 1;
if (ritOn){
//save the current as the rx frequency
ritRxFrequency = frequency;
setFrequency(ritTxFrequency);
}
if (txMode == TX_CW){
//turn off the second local oscillator and the bfo
si5351bx_setfreq(0, 0);
si5351bx_setfreq(1, 0);
//shif the first oscillator to the tx frequency directly
//the key up and key down will toggle the carrier unbalancing
//the exact cw frequency is the tuned frequency + sidetone
if (isUSB)
si5351bx_setfreq(2, frequency + sideTone);
else
si5351bx_setfreq(2, frequency - sideTone);
}
//reduce latency time when begin of CW mode
if (isDisplayUpdate == 1)
updateDisplay();
}
void stopTx(){
inTx = 0;
digitalWrite(TX_RX, 0); //turn off the tx
si5351bx_setfreq(0, usbCarrier); //set back the carrier oscillator anyway, cw tx switches it off
if (ritOn)
setFrequency(ritRxFrequency);
else
setFrequency(frequency);
updateDisplay();
}
/**
* ritEnable is called with a frequency parameter that determines
* what the tx frequency will be
*/
void ritEnable(unsigned long f){
ritOn = 1;
//save the non-rit frequency back into the VFO memory
//as RIT is a temporary shift, this is not saved to EEPROM
ritTxFrequency = f;
}
// this is called by the RIT menu routine
void ritDisable(){
if (ritOn){
ritOn = 0;
setFrequency(ritTxFrequency);
updateDisplay();
}
}
/**
* Basic User Interface Routines. These check the front panel for any activity
*/
/**
* The PTT is checked only if we are not already in a cw transmit session
* If the PTT is pressed, we shift to the ritbase if the rit was on
* flip the T/R line to T and update the display to denote transmission
*/
void checkPTT(){
//we don't check for ptt when transmitting cw
if (cwTimeout > 0)
return;
if (digitalRead(PTT) == 0 && inTx == 0){
startTx(TX_SSB, 1);
delay(50); //debounce the PTT
}
if (digitalRead(PTT) == 1 && inTx == 1)
stopTx();
}
void checkButton(){
int i, t1, t2, knob, new_knob;
//only if the button is pressed
if (!btnDown())
return;
delay(50);
if (!btnDown()) //debounce
return;
doMenu();
//wait for the button to go up again
while(btnDown()) {
delay(10);
Check_Cat(0);
}
delay(50);//debounce
}
/**
* The tuning jumps by 50 Hz on each step when you tune slowly
* As you spin the encoder faster, the jump size also increases
* This way, you can quickly move to another band by just spinning the
* tuning knob
*/
void doTuning(){
int s = 0;
unsigned long prev_freq;
int incdecValue = 0;
if ((vfoActive == VFO_A && ((isDialLock & 0x01) == 0x01)) ||
(vfoActive == VFO_B && ((isDialLock & 0x02) == 0x02)))
return;
if (isCWAutoMode == 0 || cwAutoDialType == 1)
s = enc_read();
if (s){
prev_freq = frequency;
if (s > 10)
incdecValue = 200000l;
if (s > 7)
incdecValue = 10000l;
else if (s > 4)
incdecValue = 1000l;
else if (s > 2)
incdecValue = 500;
else if (s > 0)
incdecValue = 50l;
else if (s > -2)
incdecValue = -50l;
else if (s > -4)
incdecValue = -500l;
else if (s > -7)
incdecValue = -1000l;
else if (s > -9)
incdecValue = -10000l;
else
incdecValue = -200000l;
if (incdecValue > 0 && frequency + incdecValue > HIGHEST_FREQ_DIAL)
frequency = HIGHEST_FREQ_DIAL;
else if (incdecValue < 0 && frequency < -incdecValue + LOWEST_FREQ_DIAL) //for compute and compare based integer type.
frequency = LOWEST_FREQ_DIAL;
else
frequency += incdecValue;
if (prev_freq < 10000000l && frequency > 10000000l)
isUSB = true;
if (prev_freq > 10000000l && frequency < 10000000l)
isUSB = false;
setFrequency(frequency);
updateDisplay();
}
}
/**
* RIT only steps back and forth by 100 hz at a time
*/
void doRIT(){
unsigned long newFreq;
int knob = enc_read();
unsigned long old_freq = frequency;
if (knob < 0)
frequency -= 100l;
else if (knob > 0)
frequency += 100;
if (old_freq != frequency){
setFrequency(frequency);
updateDisplay();
}
}
/**
save Frequency and mode to eeprom
*/
void storeFrequencyAndMode(byte saveType)
{
//freqType : 0 Both (vfoA and vfoB), 1 : vfoA, 2 : vfoB
if (saveType == 0 || saveType == 1) //vfoA
{
if (vfoA != vfoA_eeprom) {
EEPROM.put(VFO_A, vfoA);
vfoA_eeprom = vfoA;
}
if (vfoA_mode != vfoA_mode_eeprom) {
EEPROM.put(VFO_A_MODE, vfoA_mode);
vfoA_mode_eeprom = vfoA_mode;
}
}
if (saveType == 0 || saveType == 2) //vfoB
{
if (vfoB != vfoB_eeprom) {
EEPROM.put(VFO_B, vfoB);
vfoB_eeprom = vfoB;
}
if (vfoB_mode != vfoB_mode_eeprom) {
EEPROM.put(VFO_B_MODE, vfoB_mode);
vfoB_mode_eeprom = vfoB_mode;
}
}
}
/**
* The settings are read from EEPROM. The first time around, the values may not be
* present or out of range, in this case, some intelligent defaults are copied into the
* variables.
*/
void initSettings(){
//read the settings from the eeprom and restore them
//if the readings are off, then set defaults
//for original source Section ===========================
EEPROM.get(MASTER_CAL, calibration);
EEPROM.get(USB_CAL, usbCarrier);
EEPROM.get(VFO_A, vfoA);
EEPROM.get(VFO_B, vfoB);
EEPROM.get(CW_SIDETONE, sideTone);
EEPROM.get(CW_SPEED, cwSpeed);
//for custom source Section =============================
//ID & Version Check from EEProm
//if found different firmware, erase eeprom (32
#define FIRMWAR_ID_ADDR 776 //776 : 0x59, 777 :0x58, 778 : 0x68 : Id Number, if not found id, erase eeprom(32~1023) for prevent system error.
if (EEPROM.read(FIRMWAR_ID_ADDR) != 0x59 ||
EEPROM.read(FIRMWAR_ID_ADDR + 1) != 0x58 ||
EEPROM.read(FIRMWAR_ID_ADDR + 2) != 0x68 ) {
printLineF(1, F("Init EEProm..."));
//initial all eeprom
for (unsigned int i = 32; i < 1024; i++) //protect Master_cal, usb_cal
EEPROM.write(i, 0);
//Write Firmware ID
EEPROM.write(FIRMWAR_ID_ADDR, 0x59);
EEPROM.write(FIRMWAR_ID_ADDR + 1, 0x58);
EEPROM.write(FIRMWAR_ID_ADDR + 2, 0x68);
}
//Version Write for Memory Management Software
if (EEPROM.read(VERSION_ADDRESS) != VERSION_NUM)
EEPROM.write(VERSION_ADDRESS, VERSION_NUM);
//for Save VFO_A_MODE to eeprom
//0: default, 1:not use, 2:LSB, 3:USB, 4:CW, 5:AM, 6:FM
EEPROM.get(VFO_A_MODE, vfoA_mode);
EEPROM.get(VFO_B_MODE, vfoB_mode);
//CW DelayTime
EEPROM.get(CW_DELAY, cwDelayTime);
//CW interval between TX and CW Start
EEPROM.get(CW_START, delayBeforeCWStartTime);
//User callsign information
if (EEPROM.read(USER_CALLSIGN_KEY) == 0x59)
userCallsignLength = EEPROM.read(USER_CALLSIGN_LEN); //MAXIMUM 18 LENGTH
//Ham Band Count
EEPROM.get(HAM_BAND_COUNT, useHamBandCount);
EEPROM.get(TX_TUNE_TYPE, tuneTXType);
if ((3 < tuneTXType && tuneTXType < 100) || 103 < tuneTXType || useHamBandCount < 1)
tuneTXType = 0;
//Read band Information
for (byte i = 0; i < useHamBandCount; i++) {
unsigned int tmpReadValue = 0;
EEPROM.get(HAM_BAND_RANGE + 4 * i, tmpReadValue);
hamBandRange[i][0] = tmpReadValue;
EEPROM.get(HAM_BAND_RANGE + 4 * i + 2, tmpReadValue);
hamBandRange[i][1] = tmpReadValue;
}
if (cwDelayTime < 1 || cwDelayTime > 250)
cwDelayTime = 60;
if (vfoA_mode < 2)
vfoA_mode = 2;
if (vfoB_mode < 2)
vfoB_mode = 3;
if (usbCarrier > 12010000l || usbCarrier < 11990000l)
usbCarrier = 11995000l;
if (vfoA > 35000000l || 3500000l > vfoA) {
vfoA = 7150000l;
vfoA_mode = 2;
}
if (vfoB > 35000000l || 3500000l > vfoB) {
vfoB = 14150000l;
vfoB_mode = 3;
}
//for protect eeprom life
vfoA_eeprom = vfoA;
vfoB_eeprom = vfoB;
vfoA_mode_eeprom = vfoA_mode;
vfoB_mode_eeprom = vfoB_mode;
if (sideTone < 100 || 2000 < sideTone)
sideTone = 800;
if (cwSpeed < 10 || 1000 < cwSpeed)
cwSpeed = 100;
if (sideTone < 300 || sideTone > 1000) {
sideTonePitch = 0;
sideToneSub = 0;;
}
else{
sideTonePitch = (sideTone - 300) / 50;
sideToneSub = sideTone % 50;
}
}
void initPorts(){
analogReference(DEFAULT);
//??
pinMode(ENC_A, INPUT_PULLUP);
pinMode(ENC_B, INPUT_PULLUP);
pinMode(FBUTTON, INPUT_PULLUP);
//configure the function button to use the external pull-up
// pinMode(FBUTTON, INPUT);
// digitalWrite(FBUTTON, HIGH);
pinMode(PTT, INPUT_PULLUP);
pinMode(ANALOG_KEYER, INPUT_PULLUP);
pinMode(CW_TONE, OUTPUT);
digitalWrite(CW_TONE, 0);
pinMode(TX_RX,OUTPUT);
digitalWrite(TX_RX, 0);
pinMode(TX_LPF_A, OUTPUT);
pinMode(TX_LPF_B, OUTPUT);
pinMode(TX_LPF_C, OUTPUT);
digitalWrite(TX_LPF_A, 0);
digitalWrite(TX_LPF_B, 0);
digitalWrite(TX_LPF_C, 0);
pinMode(CW_KEY, OUTPUT);
digitalWrite(CW_KEY, 0);
}
void setup()
{
/*
//Init EEProm for Fault EEProm TEST and Factory Reset
//please remove remark for others.
//for (int i = 0; i < 1024; i++)
for (int i = 16; i < 1024; i++) //protect Master_cal, usb_cal
EEPROM.write(i, 0xFF);
lcd.begin(16, 2);
printLineF(1, F("Complete Erase"));
sleep(1000);
//while(1);
//end section of test
*/
//Serial.begin(9600);
lcd.begin(16, 2);
printLineF(1, F("CECBT v0.27"));
Init_Cat(38400, SERIAL_8N1);
initMeter(); //not used in this build
initSettings();
if (userCallsignLength > 0 && ((userCallsignLength & 0x80) == 0x80)) {
userCallsignLength = userCallsignLength & 0x7F;
printLineFromEEPRom(0, 0, 0, userCallsignLength -1); //eeprom to lcd use offset (USER_CALLSIGN_DAT)
delay(500);
}
else {
printLineF(0, F("uBITX v0.20"));
delay(500);
printLine2("");
}
initPorts();
initOscillators();
frequency = vfoA;
saveCheckFreq = frequency; //for auto save frequency
byteToMode(vfoA_mode);
setFrequency(vfoA);
updateDisplay();
if (btnDown())
factory_alignment();
}
/**
* The loop checks for keydown, ptt, function button and tuning.
*/
//for debug
int dbgCnt = 0;
byte flasher = 0;
void checkAutoSaveFreqMode()
{
//when tx or ritOn, disable auto save
if (inTx || ritOn)
return;
//detect change frequency
if (saveCheckFreq != frequency)
{
saveCheckTime = millis();
saveCheckFreq = frequency;
}
else if (saveCheckTime != 0)
{
//check time for Frequency auto save
if (millis() - saveCheckTime > saveIntervalSec * 1000)
{
if (vfoActive == VFO_A)
{
vfoA = frequency;
vfoA_mode = modeToByte();
storeFrequencyAndMode(1);
}
else
{
vfoB = frequency;
vfoB_mode = modeToByte();
storeFrequencyAndMode(2);
}
}
}
}
void loop(){
if (isCWAutoMode == 0){ //when CW AutoKey Mode, disable this process
if (!txCAT)
checkPTT();
checkButton();
}
else
controlAutoCW();
cwKeyer();
//tune only when not tranmsitting
if (!inTx){
if (ritOn)
doRIT();
else
doTuning();
}
//we check CAT after the encoder as it might put the radio into TX
Check_Cat(inTx? 1 : 0);
checkAutoSaveFreqMode();
}

View File

@@ -1,186 +0,0 @@
/**
* CW Keyer
*
* The CW keyer handles either a straight key or an iambic / paddle key.
* They all use just one analog input line. This is how it works.
* The analog line has the internal pull-up resistor enabled.
* When a straight key is connected, it shorts the pull-up resistor, analog input is 0 volts
* When a paddle is connected, the dot and the dash are connected to the analog pin through
* a 10K and a 2.2K resistors. These produce a 4v and a 2v input to the analog pins.
* So, the readings are as follows :
* 0v - straight key
* 1-2.5 v - paddle dot
* 2.5 to 4.5 v - paddle dash
* 2.0 to 0.5 v - dot and dash pressed
*
* The keyer is written to transparently handle all these cases
*
* Generating CW
* The CW is cleanly generated by unbalancing the front-end mixer
* and putting the local oscillator directly at the CW transmit frequency.
* The sidetone, generated by the Arduino is injected into the volume control
*/
// in milliseconds, this is the parameter that determines how long the tx will hold between cw key downs
//#define CW_TIMEOUT (600l) //Change to CW Delaytime for value save to eeprom
#define PADDLE_DOT 1
#define PADDLE_DASH 2
#define PADDLE_BOTH 3
#define PADDLE_STRAIGHT 4
//we store the last padde's character
//to alternatively send dots and dashes
//when both are simultaneously pressed
char lastPaddle = 0;
//reads the analog keyer pin and reports the paddle
byte getPaddle(){
int paddle = analogRead(ANALOG_KEYER);
if (paddle > 800) // above 4v is up
return 0;
if (paddle > 600) // 4-3v is dot
return PADDLE_DASH;
else if (paddle > 300) //1-2v is dash
return PADDLE_DOT;
else if (paddle > 50)
return PADDLE_BOTH; //both are between 1 and 2v
else
return PADDLE_STRAIGHT; //less than 1v is the straight key
}
/**
* Starts transmitting the carrier with the sidetone
* It assumes that we have called cwTxStart and not called cwTxStop
* each time it is called, the cwTimeOut is pushed further into the future
*/
void cwKeydown(){
keyDown = 1; //tracks the CW_KEY
tone(CW_TONE, (int)sideTone);
digitalWrite(CW_KEY, 1);
//Modified by KD8CEC, for CW Delay Time save to eeprom
//cwTimeout = millis() + CW_TIMEOUT;
cwTimeout = millis() + cwDelayTime * 10;
}
/**
* Stops the cw carrier transmission along with the sidetone
* Pushes the cwTimeout further into the future
*/
void cwKeyUp(){
keyDown = 0; //tracks the CW_KEY
noTone(CW_TONE);
digitalWrite(CW_KEY, 0);
//Modified by KD8CEC, for CW Delay Time save to eeprom
//cwTimeout = millis() + CW_TIMEOUT;
cwTimeout = millis() + cwDelayTime * 10;
}
/**
* The keyer handles the straight key as well as the iambic key
* This module keeps looping until the user stops sending cw
* if the cwTimeout is set to 0, then it means, we have to exit the keyer loop
* Each time the key is hit the cwTimeout is pushed to a time in the future by cwKeyDown()
*/
void cwKeyer(){
byte paddle;
lastPaddle = 0;
while(1){
paddle = getPaddle();
// do nothing if the paddle has not been touched, unless
// we are in the cw mode and we have timed out
if (!paddle){
//modifed by KD8CEC for auto CW Send
if (isCWAutoMode > 1) //if while auto cw sending, dont stop tx by paddle position
return;
if (0 < cwTimeout && cwTimeout < millis()){
cwTimeout = 0;
keyDown = 0;
stopTx();
}
if (!cwTimeout)
return;
//if a paddle was used (not a straight key) we should extend the space to be a full dash
//by adding two more dots long space (one has already been added at the end of the dot or dash)
/*
if (cwTimeout > 0 && lastPaddle != PADDLE_STRAIGHT)
delay_background(cwSpeed * 2, 3);
//delay(cwSpeed * 2);
// got back to the begining of the loop, if no further activity happens on the paddle or the straight key
// we will time out, and return out of this routine
delay(5);
*/
continue;
}
//if while auto cw send, stop auto cw
//but isAutoCWHold for Manual Keying with cwAutoSend
if (isCWAutoMode > 1 && isAutoCWHold == 0)
isCWAutoMode = 1; //read status
//Remoark Debug code / Serial Use by CAT Protocol
//Serial.print("paddle:");Serial.println(paddle);
// if we are here, it is only because the key or the paddle is pressed
if (!inTx){
keyDown = 0;
//Modified by KD8CEC, for CW Delay Time save to eeprom
//cwTimeout = millis() + CW_TIMEOUT;
cwTimeout = millis() + cwDelayTime * 10;
startTx(TX_CW, 0); //disable updateDisplay Command for reduce latency time
updateDisplay();
//DelayTime Option
delay_background(delayBeforeCWStartTime * 2, 2);
}
// star the transmission)
// we store the transmitted character in the lastPaddle
cwKeydown();
if (paddle == PADDLE_DOT){
//delay(cwSpeed);
delay_background(cwSpeed, 3);
lastPaddle = PADDLE_DOT;
}
else if (paddle == PADDLE_DASH){
//delay(cwSpeed * 3);
delay_background(cwSpeed * 3, 3);
lastPaddle = PADDLE_DASH;
}
else if (paddle == PADDLE_BOTH){ //both paddles down
//depending upon what was sent last, send the other
if (lastPaddle == PADDLE_DOT) {
//delay(cwSpeed * 3);
delay_background(cwSpeed * 3, 3);
lastPaddle = PADDLE_DASH;
}else{
//delay(cwSpeed);
delay_background(cwSpeed, 3);
lastPaddle = PADDLE_DOT;
}
}
else if (paddle == PADDLE_STRAIGHT){
while (getPaddle() == PADDLE_STRAIGHT) {
delay(1);
Check_Cat(2);
}
lastPaddle = PADDLE_STRAIGHT;
}
cwKeyUp();
//introduce a dot long gap between characters if the keyer was used
if (lastPaddle != PADDLE_STRAIGHT)
delay(cwSpeed);
}
}

View File

@@ -1,842 +0,0 @@
/** Menus
* The Radio menus are accessed by tapping on the function button.
* - The main loop() constantly looks for a button press and calls doMenu() when it detects
* a function button press.
* - As the encoder is rotated, at every 10th pulse, the next or the previous menu
* item is displayed. Each menu item is controlled by it's own function.
* - Eache menu function may be called to display itself
* - Each of these menu routines is called with a button parameter.
* - The btn flag denotes if the menu itme was clicked on or not.
* - If the menu item is clicked on, then it is selected,
* - If the menu item is NOT clicked on, then the menu's prompt is to be displayed
*/
#define printLineF1(x) (printLineF(1, x))
#define printLineF2(x) (printLineF(0, x))
int menuBand(int btn){
int knob = 0;
int stepChangeCount = 0;
byte btnPressCount = 0;
if (!btn){
printLineF2(F("Band Select?"));
return;
}
printLineF2(F("Press to confirm"));
//wait for the button menu select button to be lifted)
while (btnDown()) {
delay(50);
Check_Cat(0); //To prevent disconnections
if (btnPressCount++ > 20) {
btnPressCount = 0;
if (tuneTXType > 0) { //Just toggle 0 <-> 2, if tuneTXType is 100, 100 -> 0 -> 2
tuneTXType = 0;
printLineF2(F("Full range mode"));
}
else {
tuneTXType = 2;
//if empty band Information, auto insert default region 1 frequency range
//This part is made temporary for people who have difficulty setting up, so can remove it when you run out of memory.
if (useHamBandCount < 1) {
useHamBandCount = 10;
hamBandRange[0][0] = 1810; hamBandRange[0][1] = 2000;
hamBandRange[1][0] = 3500; hamBandRange[1][1] = 3800;
hamBandRange[2][0] = 5351; hamBandRange[2][1] = 5367;
hamBandRange[3][0] = 7000; hamBandRange[3][1] = 7200;
hamBandRange[4][0] = 10100; hamBandRange[4][1] = 10150;
hamBandRange[5][0] = 14000; hamBandRange[5][1] = 14350;
hamBandRange[6][0] = 18068; hamBandRange[6][1] = 18168;
hamBandRange[7][0] = 21000; hamBandRange[7][1] = 21450;
hamBandRange[8][0] = 24890; hamBandRange[8][1] = 24990;
hamBandRange[9][0] = 28000; hamBandRange[9][1] = 29700;
}
printLineF2(F("Ham band mode"));
}
delay_background(1000, 0);
printLine2ClearAndUpdate();
printLineF2(F("Press to confirm"));
}
}
char currentBandIndex = -1;
//Save Band Information
if (tuneTXType == 2 || tuneTXType == 3 || tuneTXType == 102 || tuneTXType == 103) { //only ham band move
//Get Now Band Index
currentBandIndex = getIndexHambanBbyFreq(frequency);
if (currentBandIndex >= 0) {
//Save Frequency to Band Frequncy Record
saveBandFreqByIndex(frequency, modeToByte(), currentBandIndex);
}
}
delay(50);
ritDisable();
while(!btnDown()){
knob = enc_read();
if (knob != 0){
/*
if (band > 3 && knob < 0)
band--;
if (band < 30 && knob > 0)
band++;
if (band > 10)
isUSB = true;
else
isUSB = false;
setFrequency(((unsigned long)band * 1000000l) + offset); */
if (tuneTXType == 2 || tuneTXType == 3 || tuneTXType == 102 || tuneTXType == 103) { //only ham band move
if (knob < 0) {
if (stepChangeCount-- < -3) {
setNextHamBandFreq(frequency, -1); //Prior Band
stepChangeCount = 0;
}
}
else if (knob > 0) {
if (stepChangeCount++ > 3) {
setNextHamBandFreq(frequency, 1); //Next Band
stepChangeCount = 0;
}
}
}
else { //original source
if (knob < 0 && frequency > 3000000l)
setFrequency(frequency - 200000l);
if (knob > 0 && frequency < 30000000l)
setFrequency(frequency + 200000l);
if (frequency > 10000000l)
isUSB = true;
else
isUSB = false;
}
updateDisplay();
}
delay(20);
Check_Cat(0); //To prevent disconnections
}
while(btnDown()) {
delay(50);
Check_Cat(0); //To prevent disconnections
}
delay(50);
printLine2ClearAndUpdate();
menuOn = 0;
}
//0: default, 1:not use, 2:LSB, 3:USB, 4:CW, 5:AM, 6:FM
byte modeToByte(){
if (isUSB)
return 3;
else
return 2;
}
void byteToMode(byte modeValue){
if (modeValue == 3)
isUSB = 1;
else
isUSB = 0;
}
void byteWithFreqToMode(byte modeValue){
if (modeValue == 3)
isUSB = 1;
else if (modeValue == 0) //Not Set
isUSB = (frequency > 10000000l) ? true : false;
else
isUSB = 0;
}
void menuVfoToggle(int btn)
{
if (!btn){
if (vfoActive == VFO_A)
printLineF2(F("Select VFO B?"));
else
printLineF2(F("Select VFO A?"));
}
else {
if (vfoActive == VFO_B){
vfoB = frequency;
vfoB_mode = modeToByte();
storeFrequencyAndMode(2); //vfoB -> eeprom
vfoActive = VFO_A;
frequency = vfoA;
saveCheckFreq = frequency;
byteToMode(vfoA_mode);
printLineF2(F("Selected VFO A"));
}
else {
vfoA = frequency;
vfoA_mode = modeToByte();
storeFrequencyAndMode(1); //vfoA -> eeprom
vfoActive = VFO_B;
frequency = vfoB;
saveCheckFreq = frequency;
byteToMode(vfoB_mode);
printLineF2(F("Selected VFO B"));
}
ritDisable();
//updateDisplay();
delay_background(500, 0);
printLine2ClearAndUpdate();
//exit the menu
menuOn = 0;
}
}
void menuRitToggle(int btn){
if (!btn){
if (ritOn == 1)
printLineF2(F("RIT:On, Off?"));
else
printLineF2(F("RIT:Off, On?"));
}
else {
if (ritOn == 0){
printLineF2(F("RIT is ON"));
//enable RIT so the current frequency is used at transmit
ritEnable(frequency);
}
else{
printLineF2(F("RIT is OFF"));
ritDisable();
}
menuOn = 0;
delay_background(500, 0);
printLine2ClearAndUpdate();
}
}
void menuSidebandToggle(int btn){
if (!btn){
if (isUSB == true)
printLineF2(F("Select LSB?"));
else
printLineF2(F("Select USB?"));
}
else {
if (isUSB == true){
isUSB = false;
printLineF2(F("LSB Selected"));
}
else {
isUSB = true;
printLineF2(F("USB Selected"));
}
setFrequency(frequency);
delay_background(500, 0);
printLine2ClearAndUpdate();
menuOn = 0;
}
}
void menuTxOnOff(int btn, byte optionType){
if (!btn){
if ((isTxType & optionType) == 0)
printLineF2(F("TX OFF?"));
else
printLineF2(F("TX ON?"));
}
else {
if ((isTxType & optionType) == 0){
isTxType |= optionType;
printLineF2(F("TX OFF!"));
}
else {
isTxType &= ~(optionType);
printLineF2(F("TX ON!"));
}
delay_background(500, 0);
printLine2ClearAndUpdate();
menuOn = 0;
}
}
/**
* The calibration routines are not normally shown in the menu as they are rarely used
* They can be enabled by choosing this menu option
*/
void menuSetup(int btn){
if (!btn){
if (!modeCalibrate)
printLineF2(F("Setup On?"));
else
printLineF2(F("Setup Off?"));
}else {
if (!modeCalibrate){
modeCalibrate = true;
printLineF2(F("Setup:On"));
}
else {
modeCalibrate = false;
printLineF2(F("Setup:Off"));
}
delay_background(2000, 0);
printLine2Clear();
menuOn = 0;
}
}
void menuExit(int btn){
if (!btn){
printLineF2(F("Exit Menu?"));
}
else{
printLine2ClearAndUpdate();
menuOn = 0;
}
}
int menuCWSpeed(int btn){
int knob = 0;
int wpm;
wpm = 1200/cwSpeed;
if (!btn){
strcpy(b, "CW:");
itoa(wpm,c, 10);
strcat(b, c);
strcat(b, "WPM Change?");
printLine2(b);
return;
}
printLineF1(F("Press PTT to set"));
strcpy(b, "WPM:");
itoa(wpm,c, 10);
strcat(b, c);
printLine2(b);
delay_background(300, 0);
while(!btnDown() && digitalRead(PTT) == HIGH){
knob = enc_read();
if (knob != 0){
if (wpm > 3 && knob < 0)
wpm--;
if (wpm < 50 && knob > 0)
wpm++;
strcpy(b, "WPM:");
itoa(wpm,c, 10);
strcat(b, c);
printLine2(b);
}
//abort if this button is down
if (btnDown())
//re-enable the clock1 and clock 2
break;
Check_Cat(0); //To prevent disconnections
}
//save the setting
if (digitalRead(PTT) == LOW){
printLineF2(F("CW Speed set!"));
cwSpeed = 1200/wpm;
EEPROM.put(CW_SPEED, cwSpeed);
delay_background(2000, 0);
}
printLine2ClearAndUpdate();
menuOn = 0;
}
int menuCWAutoKey(int btn){
if (!btn){
printLineF2(F("CW AutoKey Mode?"));
return;
}
//Check CW_AUTO_MAGIC_KEY and CW Text Count
EEPROM.get(CW_AUTO_COUNT, cwAutoTextCount);
if (EEPROM.read(CW_AUTO_MAGIC_KEY) != 0x73 || cwAutoTextCount < 1)
{
printLineF2(F("Empty CW data"));
delay_background(2000, 0);
return;
}
printLineF1(F("Press PTT to Send"));
delay_background(500, 0);
updateDisplay();
beforeCWTextIndex = 255; //255 value is for start check
isCWAutoMode = 1;
menuOn = 0;
}
int menuSetupCwDelay(int btn){
int knob = 0;
int tmpCWDelay = cwDelayTime * 10;
if (!btn){
strcpy(b, "CW TX->RX Delay");
printLine2(b);
return;
}
printLineF1(F("Press PTT to set"));
strcpy(b, "DELAY:");
itoa(tmpCWDelay,c, 10);
strcat(b, c);
printLine2(b);
delay_background(300, 0);
while(!btnDown() && digitalRead(PTT) == HIGH){
knob = enc_read();
if (knob != 0){
if (tmpCWDelay > 3 && knob < 0)
tmpCWDelay -= 10;
if (tmpCWDelay < 2500 && knob > 0)
tmpCWDelay += 10;
strcpy(b, "DELAY:");
itoa(tmpCWDelay,c, 10);
strcat(b, c);
printLine2(b);
}
//abort if this button is down
if (btnDown())
break;
Check_Cat(0); //To prevent disconnections
}
//save the setting
if (digitalRead(PTT) == LOW){
printLineF2(F("CW Delay set!"));
cwDelayTime = tmpCWDelay / 10;
EEPROM.put(CW_DELAY, cwDelayTime);
delay_background(2000, 0);
}
printLine2ClearAndUpdate();
menuOn = 0;
}
int menuSetupTXCWInterval(int btn){
int knob = 0;
int tmpTXCWInterval = delayBeforeCWStartTime * 2;
if (!btn){
strcpy(b, "CW Start Delay");
printLine2(b);
return;
}
printLineF1(F("Press PTT to set"));
strcpy(b, "Start Delay:");
itoa(tmpTXCWInterval,c, 10);
strcat(b, c);
printLine2(b);
delay_background(300, 0);
while(!btnDown() && digitalRead(PTT) == HIGH){
knob = enc_read();
if (knob != 0){
if (tmpTXCWInterval > 0 && knob < 0)
tmpTXCWInterval -= 2;
if (tmpTXCWInterval < 500 && knob > 0)
tmpTXCWInterval += 2;
strcpy(b, "Start Delay:");
itoa(tmpTXCWInterval,c, 10);
strcat(b, c);
printLine2(b);
}
//abort if this button is down
if (btnDown())
break;
Check_Cat(0); //To prevent disconnections
}
//save the setting
if (digitalRead(PTT) == LOW){
printLineF2(F("CW Start set!"));
delayBeforeCWStartTime = tmpTXCWInterval / 2;
EEPROM.put(CW_START, delayBeforeCWStartTime);
delay_background(2000, 0);
}
printLine2ClearAndUpdate();
menuOn = 0;
}
/**
* Take a deep breath, math(ematics) ahead
* The 25 mhz oscillator is multiplied by 35 to run the vco at 875 mhz
* This is divided by a number to generate different frequencies.
* If we divide it by 875, we will get 1 mhz signal
* So, if the vco is shifted up by 875 hz, the generated frequency of 1 mhz is shifted by 1 hz (875/875)
* At 12 Mhz, the carrier will needed to be shifted down by 12 hz for every 875 hz of shift up of the vco
*
*/
//this is used by the si5351 routines in the ubitx_5351 file
extern int32_t calibration;
extern uint32_t si5351bx_vcoa;
int factoryCalibration(int btn){
int knob = 0;
int32_t prev_calibration;
//keep clear of any previous button press
while (btnDown())
delay(100);
delay(100);
if (!btn){
printLineF2(F("Set Calibration?"));
return 0;
}
prev_calibration = calibration;
calibration = 0;
isUSB = true;
//turn off the second local oscillator and the bfo
si5351_set_calibration(calibration);
startTx(TX_CW, 1);
si5351bx_setfreq(2, 10000000l);
strcpy(b, "#1 10 MHz cal:");
ltoa(calibration/8750, c, 10);
strcat(b, c);
printLine2(b);
while (!btnDown())
{
if (digitalRead(PTT) == LOW && !keyDown)
cwKeydown();
if (digitalRead(PTT) == HIGH && keyDown)
cwKeyUp();
knob = enc_read();
if (knob > 0)
calibration += 875;
else if (knob < 0)
calibration -= 875;
else
continue; //don't update the frequency or the display
si5351_set_calibration(calibration);
si5351bx_setfreq(2, 10000000l);
strcpy(b, "#1 10 MHz cal:");
ltoa(calibration/8750, c, 10);
strcat(b, c);
printLine2(b);
}
cwTimeout = 0;
keyDown = 0;
stopTx();
printLineF2(F("Calibration set!"));
EEPROM.put(MASTER_CAL, calibration);
initOscillators();
setFrequency(frequency);
updateDisplay();
while(btnDown())
delay(50);
delay(100);
}
int menuSetupCalibration(int btn){
int knob = 0;
int32_t prev_calibration;
if (!btn){
printLineF2(F("Set Calibration?"));
return 0;
}
printLineF1(F("Set to Zero-beat,"));
printLineF2(F("press PTT to save"));
delay_background(1000, 0);
prev_calibration = calibration;
calibration = 0;
si5351_set_calibration(calibration);
setFrequency(frequency);
strcpy(b, "cal:");
ltoa(calibration/8750, c, 10);
strcat(b, c);
printLine2(b);
while (digitalRead(PTT) == HIGH && !btnDown())
{
knob = enc_read();
if (knob > 0){
calibration += 8750;
usbCarrier += 120;
}
else if (knob < 0){
calibration -= 8750;
usbCarrier -= 120;
}
else
continue; //don't update the frequency or the display
si5351_set_calibration(calibration);
si5351bx_setfreq(0, usbCarrier);
setFrequency(frequency);
strcpy(b, "cal:");
ltoa(calibration/8750, c, 10);
strcat(b, c);
printLine2(b);
}
//save the setting
if (digitalRead(PTT) == LOW){
printLineF1(F("Calibration set!"));
printLineF2(F("Set Carrier now"));
EEPROM.put(MASTER_CAL, calibration);
delay_background(2000, 0);
}
else
calibration = prev_calibration;
initOscillators();
//si5351_set_calibration(calibration);
setFrequency(frequency);
printLine2ClearAndUpdate();
menuOn = 0;
}
void printCarrierFreq(unsigned long freq){
memset(c, 0, sizeof(c));
memset(b, 0, sizeof(b));
ultoa(freq, b, DEC);
strncat(c, b, 2);
strcat(c, ".");
strncat(c, &b[2], 3);
strcat(c, ".");
strncat(c, &b[5], 1);
printLine2(c);
}
void menuSetupCarrier(int btn){
int knob = 0;
unsigned long prevCarrier;
if (!btn){
printLineF2(F("Set the BFO"));
return;
}
prevCarrier = usbCarrier;
printLineF1(F("Tune to best Signal"));
printLineF1(F("PTT to confirm. "));
delay_background(1000, 0);
usbCarrier = 11995000l;
si5351bx_setfreq(0, usbCarrier);
printCarrierFreq(usbCarrier);
//disable all clock 1 and clock 2
while (digitalRead(PTT) == HIGH && !btnDown())
{
knob = enc_read();
if (knob > 0)
usbCarrier -= 50;
else if (knob < 0)
usbCarrier += 50;
else
continue; //don't update the frequency or the display
si5351bx_setfreq(0, usbCarrier);
printCarrierFreq(usbCarrier);
Check_Cat(0); //To prevent disconnections
delay(100);
}
//save the setting
if (digitalRead(PTT) == LOW){
printLineF2(F("Carrier set!"));
EEPROM.put(USB_CAL, usbCarrier);
delay_background(1000, 0);
}
else
usbCarrier = prevCarrier;
si5351bx_setfreq(0, usbCarrier);
setFrequency(frequency);
printLine2ClearAndUpdate();
menuOn = 0;
}
void menuSetupCwTone(int btn){
int knob = 0;
int prev_sideTone;
if (!btn){
printLineF2(F("Change CW Tone"));
return;
}
prev_sideTone = sideTone;
printLineF1(F("Tune CW tone"));
printLineF2(F("PTT to confirm."));
delay_background(1000, 0);
tone(CW_TONE, sideTone);
//disable all clock 1 and clock 2
while (digitalRead(PTT) == HIGH && !btnDown())
{
knob = enc_read();
if (knob > 0 && sideTone < 2000)
sideTone += 10;
else if (knob < 0 && sideTone > 100 )
sideTone -= 10;
else
continue; //don't update the frequency or the display
tone(CW_TONE, sideTone);
itoa(sideTone, b, 10);
printLine2(b);
delay(100);
Check_Cat(0); //To prevent disconnections
}
noTone(CW_TONE);
//save the setting
if (digitalRead(PTT) == LOW){
printLineF2(F("Sidetone set!"));
EEPROM.put(CW_SIDETONE, usbCarrier);
delay_background(2000, 0);
}
else
sideTone = prev_sideTone;
printLine2ClearAndUpdate();
menuOn = 0;
}
void setDialLock(byte tmpLock, byte fromMode) {
if (tmpLock == 1)
isDialLock |= (vfoActive == VFO_A ? 0x01 : 0x02);
else
isDialLock &= ~(vfoActive == VFO_A ? 0x01 : 0x02);
if (fromMode == 2 || fromMode == 3) return;
if (tmpLock == 1)
printLineF2(F("Dial Lock ON"));
else
printLineF2(F("Dial Lock OFF"));
delay_background(1000, 0);
printLine2ClearAndUpdate();
}
int btnDownTimeCount;
void doMenu(){
int select=0, i,btnState;
//for DialLock On/Off function
btnDownTimeCount = 0;
//wait for the button to be raised up
while(btnDown()){
delay(50);
Check_Cat(0); //To prevent disconnections
//btnDownTimeCount++;
//check long time Down Button -> 3 Second
if (btnDownTimeCount++ > (2000 / 50)) {
if (vfoActive == VFO_A)
setDialLock((isDialLock & 0x01) == 0x01 ? 0 : 1, 0); //Reverse Dial lock
else
setDialLock((isDialLock & 0x02) == 0x02 ? 0 : 1, 0); //Reverse Dial lock
return;
}
}
delay(50); //debounce
menuOn = 2;
while (menuOn){
i = enc_read();
btnState = btnDown();
if (i > 0){
if (modeCalibrate && select + i < 150)
select += i;
if (!modeCalibrate && select + i < 80)
select += i;
}
if (i < 0 && select - i >= 0)
select += i; //caught ya, i is already -ve here, so you add it
if (select < 10)
menuBand(btnState);
else if (select < 20)
menuRitToggle(btnState);
else if (select < 30)
menuVfoToggle(btnState);
else if (select < 40)
menuSidebandToggle(btnState);
else if (select < 50)
menuCWSpeed(btnState);
else if (select < 60)
menuCWAutoKey(btnState);
else if (select < 70)
menuSetup(btnState);
else if (select < 80 && !modeCalibrate)
menuExit(btnState);
else if (select < 90 && modeCalibrate)
menuSetupCalibration(btnState); //crystal
else if (select < 100 && modeCalibrate)
menuSetupCarrier(btnState); //lsb
else if (select < 110 && modeCalibrate)
menuSetupCwTone(btnState);
else if (select < 120 && modeCalibrate)
menuSetupCwDelay(btnState);
else if (select < 130 && modeCalibrate)
menuSetupTXCWInterval(btnState);
else if (select < 140 && modeCalibrate)
menuTxOnOff(btnState, 0x01); //TX OFF / ON
else if (select < 150 && modeCalibrate)
menuExit(btnState);
Check_Cat(0); //To prevent disconnections
}
//debounce the button
while(btnDown()){
delay(50);
Check_Cat(0); //To prevent disconnections
}
delay(50);
}

View File

@@ -1,346 +0,0 @@
/**
* The user interface of the ubitx consists of the encoder, the push-button on top of it
* and the 16x2 LCD display.
* The upper line of the display is constantly used to display frequency and status
* of the radio. Occasionally, it is used to provide a two-line information that is
* quickly cleared up.
*/
//#define printLineF1(x) (printLineF(1, x))
//#define printLineF2(x) (printLineF(0, x))
//returns true if the button is pressed
int btnDown(){
if (digitalRead(FBUTTON) == HIGH)
return 0;
else
return 1;
}
/**
* Meter (not used in this build for anything)
* the meter is drawn using special characters. Each character is composed of 5 x 8 matrix.
* The s_meter array holds the definition of the these characters.
* each line of the array is is one character such that 5 bits of every byte
* makes up one line of pixels of the that character (only 5 bits are used)
* The current reading of the meter is assembled in the string called meter
*/
//char meter[17];
const PROGMEM uint8_t s_meter_bitmap[] = {
B00000,B00000,B00000,B00000,B00000,B00100,B00100,B11011,
B10000,B10000,B10000,B10000,B10100,B10100,B10100,B11011,
B01000,B01000,B01000,B01000,B01100,B01100,B01100,B11011,
B00100,B00100,B00100,B00100,B00100,B00100,B00100,B11011,
B00010,B00010,B00010,B00010,B00110,B00110,B00110,B11011,
B00001,B00001,B00001,B00001,B00101,B00101,B00101,B11011
};
PGM_P ps_meter_bitmap = reinterpret_cast<PGM_P>(s_meter_bitmap);
const PROGMEM uint8_t lock_bitmap[8] = {
0b01110,
0b10001,
0b10001,
0b11111,
0b11011,
0b11011,
0b11111,
0b00000};
PGM_P plock_bitmap = reinterpret_cast<PGM_P>(lock_bitmap);
// initializes the custom characters
// we start from char 1 as char 0 terminates the string!
void initMeter(){
uint8_t tmpbytes[8];
byte i;
for (i = 0; i < 8; i++)
tmpbytes[i] = pgm_read_byte(plock_bitmap + i);
lcd.createChar(0, tmpbytes);
for (i = 0; i < 8; i++)
tmpbytes[i] = pgm_read_byte(ps_meter_bitmap + i);
lcd.createChar(1, tmpbytes);
for (i = 0; i < 8; i++)
tmpbytes[i] = pgm_read_byte(ps_meter_bitmap + i + 8);
lcd.createChar(2, tmpbytes);
for (i = 0; i < 8; i++)
tmpbytes[i] = pgm_read_byte(ps_meter_bitmap + i + 16);
lcd.createChar(3, tmpbytes);
for (i = 0; i < 8; i++)
tmpbytes[i] = pgm_read_byte(ps_meter_bitmap + i + 24);
lcd.createChar(4, tmpbytes);
for (i = 0; i < 8; i++)
tmpbytes[i] = pgm_read_byte(ps_meter_bitmap + i + 28);
lcd.createChar(5, tmpbytes);
for (i = 0; i < 8; i++)
tmpbytes[i] = pgm_read_byte(ps_meter_bitmap + i + 32);
lcd.createChar(6, tmpbytes);
}
/**
* The meter is drawn with special characters.
* character 1 is used to simple draw the blocks of the scale of the meter
* characters 2 to 6 are used to draw the needle in positions 1 to within the block
* This displays a meter from 0 to 100, -1 displays nothing
*/
/*
void drawMeter(int8_t needle){
int16_t best, i, s;
if (needle < 0)
return;
s = (needle * 4)/10;
for (i = 0; i < 8; i++){
if (s >= 5)
meter[i] = 1;
else if (s >= 0)
meter[i] = 2 + s;
else
meter[i] = 1;
s = s - 5;
}
if (needle >= 40)
meter[i-1] = 6;
meter[i] = 0;
}
*/
// The generic routine to display one line on the LCD
void printLine(char linenmbr, char *c) {
if (strcmp(c, printBuff[linenmbr])) { // only refresh the display when there was a change
lcd.setCursor(0, linenmbr); // place the cursor at the beginning of the selected line
lcd.print(c);
strcpy(printBuff[linenmbr], c);
for (byte i = strlen(c); i < 16; i++) { // add white spaces until the end of the 16 characters line is reached
lcd.print(' ');
}
}
}
void printLineF(char linenmbr, const __FlashStringHelper *c)
{
int i;
char tmpBuff[17];
PGM_P p = reinterpret_cast<PGM_P>(c);
for (i = 0; i < 17; i++){
unsigned char fChar = pgm_read_byte(p++);
tmpBuff[i] = fChar;
if (fChar == 0)
break;
}
printLine(linenmbr, tmpBuff);
}
#define LCD_MAX_COLUMN 16
void printLineFromEEPRom(char linenmbr, char lcdColumn, byte eepromStartIndex, byte eepromEndIndex) {
lcd.setCursor(lcdColumn, linenmbr);
for (byte i = eepromStartIndex; i <= eepromEndIndex; i++)
{
if (++lcdColumn <= LCD_MAX_COLUMN)
lcd.write(EEPROM.read(USER_CALLSIGN_DAT + i));
else
break;
}
for (byte i = lcdColumn; i < 16; i++) //Right Padding by Space
lcd.write(' ');
}
// short cut to print to the first line
void printLine1(char *c){
printLine(1,c);
}
// short cut to print to the first line
void printLine2(char *c){
printLine(0,c);
}
// short cut to print to the first line
void printLine1Clear(){
printLine(1,"");
}
// short cut to print to the first line
void printLine2Clear(){
printLine(0, "");
}
void printLine2ClearAndUpdate(){
printLine(0, "");
updateDisplay();
}
//012...89ABC...Z
char byteToChar(byte srcByte){
if (srcByte < 10)
return 0x30 + srcByte;
else
return 'A' + srcByte - 10;
}
// this builds up the top line of the display with frequency and mode
void updateDisplay() {
// tks Jack Purdum W8TEE
// replaced fsprint commmands by str commands for code size reduction
// replace code for Frequency numbering error (alignment, point...) by KD8CEC
int i;
unsigned long tmpFreq = frequency; //
memset(c, 0, sizeof(c));
if (inTx){
if (isCWAutoMode == 2) {
for (i = 0; i < 4; i++)
c[3-i] = (i < autoCWSendReservCount ? byteToChar(autoCWSendReserv[i]) : ' ');
//display Sending Index
c[4] = byteToChar(sendingCWTextIndex);
c[5] = '=';
}
else {
if (cwTimeout > 0)
strcpy(c, " CW:");
else
strcpy(c, " TX:");
}
}
else {
if (ritOn)
strcpy(c, "RIT ");
else {
if (isUSB)
strcpy(c, "USB ");
else
strcpy(c, "LSB ");
}
if (vfoActive == VFO_A) // VFO A is active
strcat(c, "A:");
else
strcat(c, "B:");
}
//display frequency
for (int i = 15; i >= 6; i--) {
if (tmpFreq > 0) {
if (i == 12 || i == 8) c[i] = '.';
else {
c[i] = tmpFreq % 10 + 0x30;
tmpFreq /= 10;
}
}
else
c[i] = ' ';
}
//remarked by KD8CEC
//already RX/TX status display, and over index (16 x 2 LCD)
//if (inTx)
// strcat(c, " TX");
printLine(1, c);
if ((vfoActive == VFO_A && ((isDialLock & 0x01) == 0x01)) ||
(vfoActive == VFO_B && ((isDialLock & 0x02) == 0x02))) {
lcd.setCursor(5,1);
lcd.write((uint8_t)0);
}
else if (isCWAutoMode == 2){
lcd.setCursor(5,1);
lcd.write(0x7E);
}
else
{
lcd.setCursor(5,1);
lcd.write(":");
}
/*
//now, the second line
memset(c, 0, sizeof(c));
memset(b, 0, sizeof(b));
if (inTx)
strcat(c, "TX ");
else if (ritOn)
strcpy(c, "RIT");
strcpy(c, " \xff");
drawMeter(meter_reading);
strcat(c, meter);
strcat(c, "\xff");
printLine2(c);*/
}
int enc_prev_state = 3;
/**
* The A7 And A6 are purely analog lines on the Arduino Nano
* These need to be pulled up externally using two 10 K resistors
*
* There are excellent pages on the Internet about how these encoders work
* and how they should be used. We have elected to use the simplest way
* to use these encoders without the complexity of interrupts etc to
* keep it understandable.
*
* The enc_state returns a two-bit number such that each bit reflects the current
* value of each of the two phases of the encoder
*
* The enc_read returns the number of net pulses counted over 50 msecs.
* If the puluses are -ve, they were anti-clockwise, if they are +ve, the
* were in the clockwise directions. Higher the pulses, greater the speed
* at which the enccoder was spun
*/
byte enc_state (void) {
return (analogRead(ENC_A) > 500 ? 1 : 0) + (analogRead(ENC_B) > 500 ? 2: 0);
}
int enc_read(void) {
int result = 0;
byte newState;
int enc_speed = 0;
long stop_by = millis() + 50;
while (millis() < stop_by) { // check if the previous state was stable
newState = enc_state(); // Get current state
if (newState != enc_prev_state)
delay (1);
if (enc_state() != newState || newState == enc_prev_state)
continue;
//these transitions point to the encoder being rotated anti-clockwise
if ((enc_prev_state == 0 && newState == 2) ||
(enc_prev_state == 2 && newState == 3) ||
(enc_prev_state == 3 && newState == 1) ||
(enc_prev_state == 1 && newState == 0)){
result--;
}
//these transitions point o the enccoder being rotated clockwise
if ((enc_prev_state == 0 && newState == 1) ||
(enc_prev_state == 1 && newState == 3) ||
(enc_prev_state == 3 && newState == 2) ||
(enc_prev_state == 2 && newState == 0)){
result++;
}
enc_prev_state = newState; // Record state for next pulse interpretation
enc_speed++;
delay(1);
}
return(result);
}