├── schematic.jpg
├── 0.87_Keyer_Manual.pdf
├── README.md
├── main.eep
├── yack.h
├── userman.dox
├── main.hex
├── main.c
├── Makefile
└── yack.c
/schematic.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donfroula/ATTiny85_CW_Keyer/HEAD/schematic.jpg
--------------------------------------------------------------------------------
/0.87_Keyer_Manual.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/donfroula/ATTiny85_CW_Keyer/HEAD/0.87_Keyer_Manual.pdf
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ATTiny85_CW_Keyer
2 | A full-featured CW keyer for amateur radio use. The keyer is built around a cheap and tiny ATTINY85 microcontroller. The circuit boasts 4-100 character memories, beacon mode, multiple timing options, and a CW trainer for improving your Morse code speed.
3 |
--------------------------------------------------------------------------------
/main.eep:
--------------------------------------------------------------------------------
1 | :10000000A5344D000F00000000006D65737361673B
2 | :10001000652031000000000000000000000000002A
3 | :1000200000000000000000000000000000000000D0
4 | :1000300000000000000000000000000000000000C0
5 | :1000400000000000000000000000000000000000B0
6 | :1000500000000000000000000000000000000000A0
7 | :1000600000000000000000000000000000006D65BE
8 | :10007000737361676520320000000000000000001B
9 | :100080000000000000000000000000000000000070
10 | :100090000000000000000000000000000000000060
11 | :1000A0000000000000000000000000000000000050
12 | :1000B0000000000000000000000000000000000040
13 | :1000C0000000000000000000000000000000000030
14 | :1000D00000006D65737361676520330000000000E8
15 | :1000E0000000000000000000000000000000000010
16 | :1000F0000000000000000000000000000000000000
17 | :1001000000000000000000000000000000000000EF
18 | :1001100000000000000000000000000000000000DF
19 | :1001200000000000000000000000000000000000CF
20 | :100130000000000000006D65737361676520340086
21 | :1001400000000000000000000000000000000000AF
22 | :10015000000000000000000000000000000000009F
23 | :10016000000000000000000000000000000000008F
24 | :10017000000000000000000000000000000000007F
25 | :10018000000000000000000000000000000000006F
26 | :0A0190000000000000000000000065
27 | :00000001FF
28 |
--------------------------------------------------------------------------------
/yack.h:
--------------------------------------------------------------------------------
1 | /* ********************************************************************
2 | Program : yack.h
3 | Author : Jan Lategahn DK3LJ modified by Jack Welch AI4SV, Don Froula WD9DMP
4 | Purpose : definition of keyer hardware
5 | Created : 15.10.2010
6 | Update : 23.12.2016
7 | Version : 0.86
8 |
9 | Changelog
10 | ---------
11 | Version Date Change
12 | ----------------------------------------------------------------------
13 | 0.86 23.12.2016 Changed sidetone back to 800 Hz and mode default to iambicB
14 |
15 | Todo
16 | ----
17 |
18 |
19 | *********************************************************************/
20 |
21 | // User configurable settings
22 |
23 | // The following settings define the hardware connections to the keyer chip
24 |
25 | // Definition of where the keyer itself is connected
26 | #define KEYDDR DDRB
27 | #define KEYPORT PORTB
28 | #define KEYINP PINB
29 | #define DITPIN 3
30 | #define DAHPIN 4
31 |
32 | // Definition of where the transceiver keyer line is connected
33 | #define OUTDDR DDRB
34 | #define OUTPORT PORTB
35 | #define OUTPIN 0
36 |
37 | // Definition of where the sidetone output is connected (beware,
38 | // this is chip dependent and can not just be changed at will)
39 | #define STDDR DDRB
40 | #define STPORT PORTB
41 | #define STPIN 1
42 |
43 | // Definition of where the control button is connected
44 | #define BTNDDR DDRB
45 | #define BTNPORT PORTB
46 | #define BTNINP PINB
47 | #define BTNPIN 2
48 |
49 |
50 | // The following defines the meaning of status bits in the yackflags and volflags
51 | // global variables
52 |
53 | // Definition of the yackflags variable. These settings get stored in EEPROM when changed.
54 | #define NOTUSED1 0b00000001 // Available
55 | #define CONFLOCK 0b00000010 // Configuration locked down
56 | #define MODE 0b00001100 // 2 bits to define keyer mode (see next section)
57 | #define SIDETONE 0b00010000 // Set if the chip must produce a sidetone
58 | #define TXKEY 0b00100000 // Set if the chip keys the transmitter
59 | #define TXINV 0b01000000 // Set if TX key line is active low
60 | #define PDLSWAP 0b10000000 // Set if DIT and DAH are swapped
61 |
62 | #define IAMBICA 0b00000000 // IAMBIC A mode
63 | #define IAMBICB 0b00000100 // IAMBIC B mode (default)
64 | #define ULTIMATIC 0b00001000 // Ultimatic Mode
65 | #define DAHPRIO 0b00001100 // Always give DAH priority
66 |
67 | #define FLAGDEFAULT IAMBICB | TXKEY | SIDETONE
68 |
69 | // Definition of volflags variable. These flags do not get stored in EEPROM.
70 | #define DITLATCH 0b00000001 // Set if DIT contact was closed
71 | #define DAHLATCH 0b00000010 // Set if DAH contact was closed
72 | #define SQUEEZED 0b00000011 // DIT and DAH = squeezed
73 | #define DIRTYFLAG 0b00000100 // Set if cfg data was changed and needs storing
74 | #define CKLATCH 0b00001000 // Set if the command key was pressed at some point
75 | #define VSCOPY 0b00110000 // Copies of Sidetone and TX flags from yackflags
76 |
77 |
78 | // The following defines timing constants. In the default version the keyer is set to operate in
79 | // 10ms heartbeat intervals. If a higher resolution is required, this can be changed to a faster
80 | // beat
81 |
82 | // YACK heartbeat frequency (in ms)
83 | #define YACKBEAT 5
84 | #define YACKSECS(n) (n*(1000/YACKBEAT)) // Beats in n seconds (off by 2x for 5ms heartbeat)
85 | #define YACKMS(n) (n/YACKBEAT) // Beats in n milliseconds
86 |
87 | // Power save mode
88 | #define POWERSAVE // Comment this line if no power save mode required
89 | #define PSTIME 30 // 30 seconds until automatic powerdown
90 | #define PWRWAKE ((1<.
20 |
21 |
22 | @section intro Introduction
23 |
24 | YACK is a universal CW keyer library and application for the AVR architecture that is designed to be
25 | reusable. It consists of a set of functions to read, play, record and decode CW input from a paddle
26 | keyer (single or double lever). The library can be used to easily create keyers, CW decoders and trainers, beacons,
27 | door openers, alarm clocks and many more applications at very moderate cost. It can also be mixed with other
28 | applications in the same chip.
29 |
30 | Components of the application can be left out or included on as needed, reducing the memory footprint. The library
31 | can be found in the file yack.c
32 |
33 | To demonstrate the library, a standard keyer application has been written which can be found in main.c
34 |
35 | This document describes the operation of the keyer from a user perspective
36 |
37 | Version: 0.87
38 |
39 | @section hw Hardware
40 |
41 | As is, the library is configured to run on a ATTINY85 cpu, as shipped, with its internal oscillator at 8MHz,
42 | and prescaled to 1MHz.
43 |
44 | The ATTINY85 comes with 8KB of Flash memory and 512 Byte each for RAM and EEPROM. It can be ported to other AVR chips
45 | if these have sufficient features to support the intended application. As the library was written in C, processors without
46 | internal stack will not work with this application unless significantly rewritten.
47 |
48 | Hardware connections are defined in yack.h
49 |
50 | - Pin 1 : PB5 - RESET (Can be used for additional button)
51 | - Pin 2 : PB3 - DIT (towards GND, buffer with 10nF cap)
52 | - Pin 3 : PB4 - DAH (towards GND, buffer with 10nF cap)
53 | - Pin 4 : GND
54 | - Pin 5 : PB0 - TX key line (polarity configurable)
55 | - Pin 6 : PB1 - Sidetone (Connect a piezo disc)
56 | - Pin 7 : PB2 - Command button (towards GND)
57 | - Pin 8 : VCC (5V)
58 |
59 | @section usage Usage
60 |
61 | After reset in default mode, the keyer operates as regular IAMBIC keyer in IAMBIC B at 15 WPM
62 | (words per minute = 60 CPM), with 800 Hz side tone. By default, the transmitter keying signal is
63 | positive.
64 |
65 | @subsection speed Speed Change
66 |
67 | Speed can be changed by pressing and holding the command key while operating the DIT and DAH paddles.
68 | DIT reduces speed while DAH increases speed. The keyer plays an alternating sequence of dit and dah while
69 | changing speed without keying the transmitter.
70 |
71 | @subsection cmode Command mode
72 |
73 | Pressing the command button without changing speed will switch the keyer into command mode. This will be
74 | confirmed with the '?' character. Another press of the same button takes the keyer back into regular
75 | keyer mode and will be confirmed by the 'SK' prosign.
76 |
77 | During command mode the transceiver is never keyed and sidetone is always activated. Further
78 | functions can be accessed by keying one-letter commands as listed below.
79 |
80 | @subsubsection Version V - Version
81 |
82 | The keyer responds with the current keyer software version number
83 |
84 | @subsubsection pitch P - Pitch
85 |
86 | Allows modifying the sidetone pitch to a higher or lower level. A sequence of dits will be played
87 | and the pitch can be modified with the dit and dah paddles. If no paddle is touched for 5 seconds,
88 | the acknowledgment signal 'R' is sounded and the mode terminates, leaving the user in command mode.
89 |
90 | @subsubsection reset R - Reset
91 |
92 | All settings are returned to their default values except for the stored messages in the message buffers.
93 | Restored settings include speed and pitch, Paddle Swap, TX level inversion, sidetone and TX keyer settings.
94 |
95 | @subsubsection tune U - Tune mode
96 |
97 | The transceiver is keyed for a duration of 20 seconds for tuning purposes. Tuning mode is aborted once either
98 | DIT or DAH paddles are touched or the control key is pressed.
99 |
100 | @subsubsection ia A - IAMBIC A
101 |
102 | Keyer sets IAMBIC A as permanent keying mode. An 'R' is sounded to acknowledge the request.
103 |
104 | @subsubsection ib B - IAMBIC B
105 |
106 | Keyer sets IAMBIC B as permanent keying mode. An 'R' is sounded to acknowledge the request.
107 |
108 | @subsubsection ultimatic L - Ultimatic
109 |
110 | Sets the keyer into ULTIMATIC mode. In Ultimatic mode always the last paddle to be touched is repeated indefinitely
111 | when paddles are squeezed
112 |
113 | @subsubsection dahprio D - DAH priority mode. In squeezed state a sequence of DAHs is sent.
114 |
115 | Some of the first generation keyers exhibited this behaviour so the chip can simulate that
116 |
117 | @subsubsection swap X - Paddle swapping
118 |
119 | DIT and DAH paddles are swapped. An 'R' is sounded to acknowledge the request.
120 |
121 | @subsubsection side S - Sidetone toggle
122 |
123 | The built-in sidetone generator setting is toggled (ON -> OFF or OFF -> ON). NOTE: This setting is only of relevance
124 | for regular keying mode. Sidetone is always on in command mode. An 'R' is sounded to acknowledge the request.
125 |
126 | @subsubsection txtog K - TX Keying toggle
127 |
128 | Toggles the setting of the TX keyer output. In default state the keyer switches the output line when it is in keyer mode.
129 | Toggling this setting enables or disables that function. NOTE: Keying is always off in Command mode. An 'R' is sounded to
130 | acknowledge the request.
131 |
132 | @subsubsection farnsworth Z - Set Farnsworth pause
133 |
134 | Allows setting of an extended inter-character pause in all sending modes, which makes fast keying easier to understand.
135 | Note that this of course only influences RECEPTION, not TRANSMISSION. If you desire farnsworth mode in transmission, please
136 | manually pause during characters.
137 |
138 | @subsubsection lvtog F (Flip) - TX level inverter toggle
139 |
140 | This function toggles wether the "active" level on the keyer output is VCC or GND. The default is VCC. This setting
141 | is dependent on the attached keying circuit. An 'R' is sounded to acknowledge the request.
142 |
143 | @subsubsection query W - Query current WPM speed
144 |
145 | Keyer responds with current keying speed in WPM.
146 |
147 | @subsubsection msgrec 1, 2, 3, 4 - Record internal messages 1, 2, 3 or 4
148 |
149 | The keyer immediately responds with "1" or "2" or "3" or "4" after which a message up to 100 characters can be keyed at current WPM speed.
150 | After 5 seconds of inactivity the message is played back once and then stored in EEPROM. Choosing "1" or "2" or "3" or "4" but not keying
151 | a new message deletes the chosen message buffer content. A command key press during the recording function returns the keyer to
152 | command mode, leaving the memory unchanged.
153 |
154 | @subsubsection msgplay E, I, T and M - Play back internal messages 1 or 2 or 3 or 4.
155 |
156 | A press of the command key immediately returns the keyer to command mode so another memory may be played. A second command key press
157 | returns keyer to normal mode for a QSO. The stored messages 1, 2, 3, or 4 are played back with keying enabled (if configured).
158 |
159 | @subsubsection beacon N - Automatic Beacon
160 |
161 | The keyer responds with 'N' after which a number between 0 and 9999 can be keyed. After a 5 second timeout the keyer
162 | responds by repeating the number and 'R'. Once the keyer returns to keyer mode, the content of message buffer 4 is
163 | repeated in intervals of n seconds. The setting is preserved in EEPROM so the chip can be used as a fox hunt keyer.
164 |
165 | Returning to command mode and entering an interval of 0 (or none at all) stops beacon mode.
166 |
167 | @subsubsection lock 0 - Lock configuration
168 |
169 | The 0 command locks or unlocks the main configuration items but not speed, pitch and playback functions.
170 |
171 | @subsubsection trainer C - Callsign trainer
172 |
173 | The keyer plays a generated callsign (sidetone only) and the user must repeat it. If it was repeated correctly, 'R' is
174 | played and the next callsign is given. If a mistake was sensed, the error prosign (8 dits) is sounded and
175 | the current callsign is repeated again for the user to try once more. If nothing is keyed for 10 seconds, the keyer returns
176 | to command mode.
177 |
178 |
179 | */
--------------------------------------------------------------------------------
/main.hex:
--------------------------------------------------------------------------------
1 | :1000000069C083C0BDC281C080C07FC07EC07DC0CA
2 | :100010007CC07BC07AC079C078C077C076C01FC270
3 | :1000200023C227C22BC233C232C231C230C22FC256
4 | :100030002EC22DC22CC22BC22AC229C228C2FCC188
5 | :10004000FDC125C200C223C208C221C220C21FC2F4
6 | :100050001EC2FFC1F6C11BC217C219C218C217C205
7 | :10006000E9C1F5C114C213C212C211C2EEC10FC25E
8 | :10007000F2C1520056302E3837002300373300FCCF
9 | :100080007C3C1C0C0484C4E4F46088A8904028D014
10 | :10009000082078B048E0A0F068D85010C030187040
11 | :1000A00098B8C8325694E8CEE2AA4A137AB4B68613
12 | :1000B0006A36528C16548B44AC14583F2E2F212C88
13 | :1000C0003A3B7E245E28292D405F7C3D232B2A2548
14 | :1000D000263C3E0011241FBECFE5D2E0DEBFCDBFDF
15 | :1000E00010E0A0E6B0E0E0EEFFE002C005900D9267
16 | :1000F000A436B107D9F710E0A4E6B0E001C01D9224
17 | :10010000AA37B107E1F72AD269C77ACF482F2091E1
18 | :10011000620030916300C901817090709095819563
19 | :100120009F4F8070947B36952795822793279093D5
20 | :10013000630080936200892F01C0841B8417E8F755
21 | :1001400090E00895EF92FF921F93CF93DF937C018D
22 | :10015000EC0110E0123031F48AE0D8DF805DF70165
23 | :10016000828304C08AE1D2DF8F5B88831F5F219680
24 | :10017000153081F7DF91CF911F91FF90EF90089597
25 | :100180001F93CF93DF93182F8091600090916100AF
26 | :10019000885E9D4F49F481E061E040E050E07FD40B
27 | :1001A0009093610080936000113009F047C0109275
28 | :1001B00061001092600088EE93E090936500809358
29 | :1001C00064008EE4E5D4C8EED3E01AC080E051D3D9
30 | :1001D000182F23D2812F80538A3090F480916000B1
31 | :1001E000909161006AE070E089D6C097810F911DFF
32 | :1001F0009093610080936000D0936500C093640089
33 | :1002000080916400909165000197909365008093C0
34 | :100210006400892BD9F6409160005091610087E21B
35 | :100220004031580748F482E061E039D480916000A1
36 | :10023000909161009AD535C0B5D233C0123089F59E
37 | :100240008091600090916100892B59F180E0A2D1EA
38 | :100250008091640090916500009731F00197909330
39 | :100260006500809364001DC088EC90E09093650069
40 | :100270008093640080916000909161000197909359
41 | :10028000610080936000892B61F481E061E040E0CF
42 | :1002900050E005D4909361008093600082E064E0B8
43 | :1002A000BED4DF91CF911F910895AF92BF92CF92AC
44 | :1002B000DF92EF92FF920F931F93DF93CF9300D0C3
45 | :1002C00000D00F92CDB7DEB76E010894C11CD11CCF
46 | :1002D00066E0A62EB12CAC0EBD1EC60133DFFF2496
47 | :1002E000FF2081F48EE02AD28601F801808150D46B
48 | :1002F00038D281E018D4882371F50F5F1F4F0A159B
49 | :100300001B0599F700ED17E080E0B3D2E82E85D108
50 | :1003100001501040EE2041F401151105E1F080E09C
51 | :1003200002D4882389F302C0012BA9F081E0FBD31A
52 | :10033000882389F4F601EF0DF11D80818E1529F4D3
53 | :10034000F394F4E0FF1560F603C02CD2FF24CACF6B
54 | :1003500082E51ED4C2CF0F900F900F900F900F9098
55 | :10036000CF91DF911F910F91FF90EF90DF90CF9091
56 | :10037000BF90AF9008951F9310E081E0D4D38823FD
57 | :10038000B9F481E0FDD181E0D9D182E0F9D183E0F7
58 | :10039000D5D1E7D1B39902C082E007C0B49B04C0B5
59 | :1003A0001F5F1A3051F704C081E061E008D2E4CF4A
60 | :1003B0001F910895CF93DF93CAE0D0E085E4E8D39E
61 | :1003C00081E0B1D3882379F4B39B02C0219704C0A4
62 | :1003D00082E02AD1CAE0D0E0B49903C081E024D100
63 | :1003E000EBCF209759F7DF91CF9108951F93CF93CB
64 | :1003F000DF9381E090D18FE3CBD3C8EED3E09EC0F2
65 | :1004000080E037D2182F882319F0C8EED3E001C05E
66 | :10041000219703D18FEF7ADE82E044D18823B9F5AA
67 | :10042000812F90E0FC01F197EA32F10580F5E15F60
68 | :10043000FF4F09940DD579C080E001C084E026D13A
69 | :1004400074C088E0FCCF8CE0FACF80E84EC080E139
70 | :100450004CC080E24AC08FDF68C080E446C081E3C0
71 | :1004600097D381E061E00EC082E392D381E062E045
72 | :1004700009C083E38DD381E063E004C084E388D3C3
73 | :1004800081E064E0CCD351C081E07ADE4EC01D34FF
74 | :10049000E9F11E3468F4133429F1143420F41033D4
75 | :1004A00009F041C021C0153411F11934E1F524C01F
76 | :1004B000153591F0163528F4103561F0143599F59D
77 | :1004C00020C0163519F0173571F52AC084E790E081
78 | :1004D0008ED42BC06FDF29C080E01DD19CD481E079
79 | :1004E0001AD123C0E2DE21C082E0E0D01EC080E04D
80 | :1004F00012D182E061E00EC080E00DD182E062E0C6
81 | :1005000009C080E008D182E063E004C080E003D14C
82 | :1005100082E064E084D381E0FED0C8EBDBE00EC073
83 | :1005200078D023D402C0113039F4D9D289E006D171
84 | :1005300082E790E05CD402C0111134D181E0F3D2A3
85 | :10054000882319F4209709F05BCF8AE790E04FD415
86 | :1005500080E0E1D0DF91CF911F91089594D481E0A4
87 | :10056000DAD08CE790E043D480E0D5D081E0DBD2D4
88 | :1005700081113CDF52D082E003DE80E07AD1F6CFF9
89 | :100580001F920F920FB60F9211240F900FBE0F9073
90 | :100590001F901895882309F433C080916F009091C3
91 | :1005A0007000A0917100B09172000196A11DB11D63
92 | :1005B00080936F0090937000A0937100B0937200CD
93 | :1005C0000197A109B10980579741A040B04001F5BA
94 | :1005D00010926F00109270001092710010927200D1
95 | :1005E00085B7877E806185BF85B7846885BF8B7F2F
96 | :1005F00085BF85B7806285BF78948895F894089503
97 | :1006000010926F00109270001092710010927200A0
98 | :1006100008958091780090E0089508B606FEFDCF19
99 | :1006200088B7806488BF0895813031F48091740068
100 | :1006300090917500019707C0823049F48091740051
101 | :10064000909175000196909375008093740080914D
102 | :10065000740090917500889730F488E290E0909350
103 | :1006600075008093740080917400909175008C39AE
104 | :10067000910530F08BE990E09093750080937400C1
105 | :100680008091660084608093660008959091730065
106 | :10069000937F982B90937300809166008460809381
107 | :1006A00066000895909173008923089590917300D6
108 | :1006B0009827909373008091660084608093660011
109 | :1006C0000895982F8230A9F480916600282F84FF26
110 | :1006D00008C08091740089BD88BD8AB582618ABDD9
111 | :1006E00093BF25FF17C08091730086FF10C0C0988C
112 | :1006F0000895813079F48091660084FF02C01ABCAD
113 | :1007000013BE85FF07C08091730086FF02C0C09AA8
114 | :100710000895C098089590916600882329F09F7CE1
115 | :1007200090619093660008958091730080739F7C20
116 | :10073000892B8093660081E0C4DF0895282F3091D3
117 | :1007400076000AC008B606FEFDCF88B7806488BF71
118 | :1007500091509923B9F72150222311F0932FF9CF0B
119 | :100760000895CF93DF9380917900C82FD0E003C024
120 | :1007700081E0E4DF21972097D9F7DF91CF910895A9
121 | :100780001F93182F82E09DDF80E004DF113021F0FD
122 | :10079000123021F483E001C081E0D0DF81E091DFFD
123 | :1007A0001F9108951F9310E081E0EADF81E0C6DF2A
124 | :1007B0001F5F1830C9F783E0C1DF1F9108956130D2
125 | :1007C00091F4813031F480917900882339F181509E
126 | :1007D00007C0823019F5809179008F3FF9F08F5F63
127 | :1007E000809379001BC0813031F48091780082338E
128 | :1007F00058F48F5F07C0823039F4809178008630DA
129 | :1008000018F08150809378006091780080EF90E03C
130 | :1008100070E09AD3709377006093760080916600C1
131 | :1008200084608093660081E0ABDF81E087DF82E057
132 | :10083000A7DF83E083DF95DF0895909173009078C0
133 | :10084000B3990AC020916600992311F481E001C098
134 | :1008500082E0822B80936600B4990AC020916600E2
135 | :10086000992311F482E001C081E0822B809366001D
136 | :1008700008951F9320916C0030916D002115310572
137 | :1008800031F02150304030936D0020936C0088236C
138 | :1008900011F41092680080916E00813009F4CEC08E
139 | :1008A000813020F0823009F0F6C0E4C0C6DF81E07C
140 | :1008B00071DE8091730090E08C70907084309105AF
141 | :1008C00061F0853091051CF4892B39F02DC08830FA
142 | :1008D000910571F00C9741F51EC090916B009095B9
143 | :1008E0008091660089238093660010926B001CC083
144 | :1008F00090916600892F8370833049F4809167005E
145 | :10090000882379F080958923809366000DC09370C9
146 | :100910009093670009C090916600892F837083309F
147 | :1009200019F49E7F9093660080916C0090916D0009
148 | :10093000892B09F04BC040916900442309F43EC063
149 | :1009400080916A00880F816090E027E030E0241BEE
150 | :10095000310902C0880F991F2A95E2F7982F20E0ED
151 | :1009600030E0F901E158FF4FE491E91769F42A30CA
152 | :1009700010F4205D0FC0243210F4295C0BC02956FE
153 | :100980003F4FF901249106C02F5F3F4F2C333105B3
154 | :1009900041F720E01092690010926A008091760081
155 | :1009A00090917700880F991F880F991F90936D0081
156 | :1009B00080936C0081E0809368006EC08091680035
157 | :1009C000882321F01092680020E266C01091660032
158 | :1009D000412F50E0CA0183709070892B09F45BC0ED
159 | :1009E00010926800809169008F5F80936900209168
160 | :1009F0006A00220F20936A00809176009091770020
161 | :100A000010FF08C090936D0080936C0081E080938C
162 | :100A10006B000DC063E070E071D290936D00809325
163 | :100A20006C0082E080936B00216020936A0082E07A
164 | :100A300048DE1C7F1093660081E019C080E0AADDCB
165 | :100A4000809173008C70843009F4F7DE80916C0023
166 | :100A500090916D00892BF9F481E033DE809176006E
167 | :100A60009091770090936D0080936C0082E080936A
168 | :100A70006E0011C0E2DE80916C0090916D00892BB8
169 | :100A800051F410926E0080917600909177009093CF
170 | :100A90006D0080936C0020E0822F1F9108958130BB
171 | :100AA00069F4613021F486E090E079D205C06230CB
172 | :100AB00091F488E090E073D29C010FC0823059F429
173 | :100AC000613019F486E090E004C0623021F488E0DF
174 | :100AD00090E0BA0180D220E030E0C9010895809111
175 | :100AE000660082FF1FC080E090E065EA66D26091F8
176 | :100AF00074007091750082E090E06DD284E090E027
177 | :100B0000609178005AD281E090E06091730055D2F4
178 | :100B100085E090E06091790050D2809166008B7FF3
179 | :100B20008093660008950F931F93082F109166001D
180 | :100B3000B2991BC0186081E0EEDD84ED90E301976F
181 | :100B4000F1F70CC0B39904C082E060E038DE177F93
182 | :100B5000B49904C081E060E032DE177FB29BF2CF2F
183 | :100B600084ED90E30197F1F7BADF1093660001304E
184 | :100B700021F4812F877F80936600812F90E043E0EE
185 | :100B8000969587954A95E1F781701F910F91089589
186 | :100B90001F93282F80538A3010F010E805C0E22FF1
187 | :100BA000F0E0E15BFF4F1491822F81568A3128F4E7
188 | :100BB000E22FF0E0E85DFF4F1491822F81548A31DB
189 | :100BC00028F4E22FF0E0E85BFF4F149180E090E022
190 | :100BD000FC01E554FF4FE4912E1721F4FC01ED5583
191 | :100BE000FF4F149101968831910591F7203281F4DD
192 | :100BF00084E0A4DD12C080E096DF882371F417FF43
193 | :100C000002C082E001C081E0BBDD81E097DD110F11
194 | :100C1000103889F782E092DDA4DD1F910895CF920C
195 | :100C2000DF92EF92FF920F931F93DF93CF93CDB795
196 | :100C3000DEB7C456D0400FB6F894DEBF0FBECDBFAE
197 | :100C4000062F813009F04EC068EEE62E63E0F62EE6
198 | :100C500010E06E010894C11CD11C81E064DF882380
199 | :100C600009F073C081E005DE882321F40894E108CF
200 | :100C7000F10809C0F601E10FF11D80831F5F58EEF6
201 | :100C8000E52E53E0F52E143610F08CDD10E008B69A
202 | :100C900006FEFDCF88B7806488BFE114F104E9F651
203 | :100CA0001123F1F01150CE010196FC01E10FF11D6D
204 | :100CB0001082013019F46AE070E004C0023031F4AF
205 | :100CC0006EE670E044E650E06FD13FC0033019F4A7
206 | :100CD00062ED70E0F7CF0430C1F566E371E0F2CF6A
207 | :100CE00061DD33C0823089F5613029F4CE0101968F
208 | :100CF0006AE070E014C0623029F4CE0101966EE61D
209 | :100D000070E00DC0633029F4CE01019662ED70E011
210 | :100D100006C0643039F4CE01019666E371E044E622
211 | :100D200050E025D110E07E010894E11CF11C07C0C1
212 | :100D300080E0F9DE882349F4802F2ADF1F5FF70166
213 | :100D4000E10FF11D0081002399F7CC59DF4F0FB659
214 | :100D5000F894DEBF0FBECDBFCF91DF911F910F91F1
215 | :100D6000FF90EF90DF90CF900895EF92FF921F9346
216 | :100D7000DF93CF9300D000D00F92CDB7DEB79C01A8
217 | :100D800010E07E010894E11CF11C0FC0F701E10F97
218 | :100D9000F11DC9016AE070E0C3D0805D80831F5FF0
219 | :100DA000C9016AE070E0BCD09B012115310571F7E3
220 | :100DB0000BC081E0B8DE882369F41150F701E10F20
221 | :100DC000F11D8081E5DE04C07E010894E11CF11C68
222 | :100DD000112379F780E2DCDE0F900F900F900F90D7
223 | :100DE0000F90CF91DF911F91FF90EF9008951F9387
224 | :100DF000CF93DF93EC0102C0812FCADEFE01219662
225 | :100E00001491112321F081E08EDE8823A9F3DF9174
226 | :100E1000CF911F910895CF93DF9382E052DCC0EA17
227 | :100E2000DFE009C0219708B606FEFDCF88B78064D1
228 | :100E300088BF209741F0B39B06C0B49B04C081E0FB
229 | :100E400072DE882379F381E03CDCDF91CF91089555
230 | :100E50008DE490E090937500809374008FE0809310
231 | :100E6000780080E190E09093770080937600109274
232 | :100E7000790084E38093730080916600846080939E
233 | :100E800066002DDE0895B89AB99AC39AC49AC29A98
234 | :100E900080E090E07CD0853A01F582E090E07FD060
235 | :100EA000909375008093740084E090E070D0682F78
236 | :100EB0008093780080EF90E070E046D070937700E8
237 | :100EC0006093760085E090E062D08093790081E0C5
238 | :100ED00090E05DD08093730001C0BADF80E01BDC3E
239 | :100EE00085B38C6185BB8BB780628BBF8EE48DBD73
240 | :100EF00080B7876880BF81E08EBD089555270024A4
241 | :100F000080FF02C0060E571F660F771F611571051F
242 | :100F100021F096958795009799F7952F802D089544
243 | :100F2000AA1BBB1B51E107C0AA1FBB1FA617B7070F
244 | :100F300010F0A61BB70B881F991F5A95A9F780952B
245 | :100F40009095BC01CD01089597FB092E07260AD084
246 | :100F500077FD04D0E5DF06D000201AF47095619586
247 | :100F60007F4F0895F6F7909581959F4F0895DC0186
248 | :100F7000CB01FC01E199FECF06C0FFBBEEBBE09ABE
249 | :100F800031960DB20D9241505040B8F70895E19955
250 | :100F9000FECF9FBB8EBBE09A99278DB30895A8E141
251 | :100FA000B0E042E050E0E5CFDC01CB0102C02D9182
252 | :100FB00005D041505040D8F70895262FE199FECF33
253 | :100FC0001CBA9FBB8EBB2DBB0FB6F894E29AE19A78
254 | :100FD0000FBE01960895F1DF272FF0CFF894FFCFD1
255 | :040FE000E8FDE1AC9B
256 | :00000001FF
257 |
--------------------------------------------------------------------------------
/main.c:
--------------------------------------------------------------------------------
1 | /*!
2 |
3 | @file main.c
4 | @brief CW Keyer application
5 | @author Jan Lategahn DK3LJ jan@lategahn.com (C) 2010 modified by Jack Welch AI4SV; modified by Don Froula WD9DMP
6 |
7 | This file implements a sample CW keyer application by using the yack.c
8 | library. It is targeted at the ATTINY45 microcontroller but can be used
9 | for other ATMEL controllers in the same way. Note the enclosed documentation
10 | for further defails.
11 |
12 | This program is free software: you can redistribute it and/or modify
13 | it under the terms of the GNU General Public License as published by
14 | the Free Software Foundation, either version 3 of the License, or
15 | (at your option) any later version.
16 |
17 | This program is distributed in the hope that it will be useful,
18 | but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | GNU General Public License for more details.
21 |
22 | You should have received a copy of the GNU General Public License
23 | along with this program. If not, see .
24 |
25 | @version 0.87
26 |
27 | @date 15.10.2010 - Created
28 | @date 16.12.2010 - Submitted to SVN
29 | @date 03.10.2013 - Last change
30 | @date 21.12.2016 - Added additional prosigns and punctuation. Added 2 additional memories for ATTINY85. Changed some commands.
31 | Fixed pitch change not saving after timeout. (WD9DMP)
32 | @date 21.12.2016 - Added a call to save changes to EEPROM while in command mode loop if DIRTYFLAG set for better EEPROM parm save reliability. (WD9DMP)
33 | Changed "SK" response when leaving command mode to "#" which now decodes to proper SK without intercharacter space.
34 | Beacon command ("N") was in both the lockable and unlockable command list, making it unlockable. I removed it from the unlockable list, making it lockable.
35 |
36 | @date 03.01.2017 - Added short 3 DAH delay after command returns before txok ("R") is sent to prevent some command outputs running on with txok.
37 | If memory recording is interrupted by command button, keyer now returns txok ("R") and stays in command mode. Memory is unchanged.
38 | Removed playback of recorded message before saving.
39 | When in Pitch change routine, allow breaking back to command mode with key press. Changes are saved.
40 | When in Farnsworth spacing change routine, allow breaking back to command mode with key press. Changes are saved.
41 | Changed Farnsworth setting mode to play continuous DIT-DAH when not holding paddle to adjust, like Pitch command
42 | Changed Version command to return to command mode instead of normal mode if interrupted with command key
43 | Changed speed inquiry command to return to command mode instead of normal mode if interrupted with command key
44 | */
45 |
46 |
47 | #ifndef F_CPU
48 | #error F_CPU undefined!! Please define in Makefile
49 | #endif
50 |
51 | #include
52 | #include
53 | #include
54 | #include "yack.h"
55 |
56 | // Time after which callsign training is assumed complete
57 | #define TRAINTIMEOUT 10 // 10 Seconds
58 | #define PITCHREPEAT 10 // 10 e's will be played for pitch adjust
59 | #define FARNSREPEAT 10 // 10 a's will be played for Farnsworth
60 |
61 | // Some texts in Flash used by the application
62 | const char txok[] PROGMEM = "R";
63 | const char vers[] PROGMEM = "V0.87";
64 | const char prgx[] PROGMEM = "#"; // # decodes to prosign SK with no intercharacter gap
65 | const char imok[] PROGMEM = "73";
66 |
67 | void pitch(void)
68 | /*!
69 | @brief Pitch change mode
70 |
71 | This function implements pitch change mode. A series of dots is played and pitch can
72 | be adjusted using the paddle levers.
73 |
74 | Once 10 dots have been played at the same pitch, the mode terminates
75 | */
76 | {
77 | word timer=PITCHREPEAT;
78 |
79 | while (timer) // while not yet timed out
80 | {
81 | timer--;
82 | yackchar('E'); // play an 'e'
83 |
84 | if (yackctrlkey(TRUE)) {return;}
85 |
86 | if(!(KEYINP & (1<> 1) ^ (-(lfsr & 1u) & 0xB400u);
166 |
167 | random = lfsr >> 8; // Byte = upper byte of word
168 |
169 | while (random >= n) random -= n; // Cheap modulo :-)
170 |
171 | return random;
172 |
173 | }
174 |
175 |
176 |
177 |
178 |
179 | void rndcall(char* call)
180 | /*!
181 | @brief Randomize a callsign
182 |
183 | This creates a random callsign with 2 letters + 1 digit + 2 letters
184 |
185 | @param call a pointer to a buffer of sufficient size to store the callsign
186 | */
187 | {
188 | byte i;
189 |
190 | // Generate a random callsign 2 Char, 1 Digit, 2 Char
191 |
192 | for (i=0;i<5;i++)
193 | {
194 | if (i == 2)
195 | call[i]=lfsr(10) + '0';
196 | else
197 | call[i]=lfsr(26) + 'A';
198 |
199 | }
200 | }
201 |
202 |
203 |
204 |
205 | void cstrain(void)
206 | /*!
207 | @brief Callsign trainer mode
208 |
209 | This implements callsign training. The keyer plays a random callsign and the
210 | user repeats it on the paddle. If a mistake happens, the error prosign is
211 | sounded, the callsign sent again and the user attempts one more time.
212 | */
213 | {
214 | char call[5]; // A buffer to store the callsign
215 | char c; // The character returned by IAMBIC keyer
216 | byte i; // Counter
217 | byte n; // Playback counter
218 | word timer; // Timeout timer
219 |
220 | while(1) // Endless loop will exit throught RETURN statement only
221 |
222 | {
223 | rndcall(call); // Make up a callsign
224 |
225 | i=0; // i counts the number of chracters correctly guessed
226 |
227 | while(i<5)
228 | {
229 | if (!i) // If nothing guessed yet, play the callsign
230 | {
231 | yackdelay(2 * IWGLEN); // Give him some time to breathe b4 next callsign
232 | for (n=0;n<5;n++)
233 | {
234 | yackchar(call[n]);
235 | yackfarns(); // Add potential farnsworth delays
236 | if(yackctrlkey(TRUE))
237 | return; // Abort if requested..
238 | }
239 | }
240 |
241 | timer = YACKSECS(TRAINTIMEOUT);
242 |
243 | do
244 | {
245 |
246 | c=yackiambic(OFF); // Wait for a character
247 | yackbeat(); // FSM heartbeat
248 | timer--; // Countdown
249 |
250 | } while ((!c) && timer && !(yackctrlkey(FALSE))); // Stop when character or timeout
251 |
252 | if (timer == 0 || yackctrlkey(TRUE)) // If termination because of timeout
253 | return; // then return
254 |
255 | if (call[i] == c) // Was it the right character?
256 | i++; // then increment counter
257 | else
258 | {
259 | yackerror(); // Send an error prosign
260 | i=0; // And reset the counter
261 | }
262 |
263 | }
264 |
265 | yackchar ('R');
266 |
267 | }
268 | }
269 |
270 |
271 |
272 | void beacon(byte mode)
273 | /*!
274 | @brief Beacon mode
275 |
276 | This routine can read a beacon transmission interval up to
277 | 9999 seconds and store it in EEPROM (RECORD mode)
278 | In PLAY mode, when called in the YACKBEAT loop, it plays back
279 | message 2 in the programmed interval
280 |
281 | @param mode RECORD (read and store the beacon interval) or PLAY (beacon)
282 |
283 | @see main
284 |
285 | */
286 | {
287 |
288 | static word interval = 65000; // A dummy value that can not be reached
289 | static word timer;
290 | char c;
291 |
292 |
293 | if (interval == 65000) //
294 | interval = yackuser(READ, 1, 0);
295 |
296 | if (mode == RECORD)
297 | {
298 | interval = 0; // Reset previous settings
299 | timer = YACKSECS(DEFTIMEOUT);
300 |
301 | yackchar('N');
302 |
303 | while(--timer)
304 | {
305 | c=yackiambic(FALSE);
306 | yackbeat();
307 |
308 | if (c>='0' && c<='9')
309 | {
310 | interval *= 10;
311 | interval += c - '0';
312 | timer = YACKSECS(DEFTIMEOUT);
313 | }
314 | }
315 |
316 | if (interval >= 0 && interval <= 9999)
317 | {
318 | yackuser(WRITE, 1, interval); // Record interval
319 | yacknumber(interval); // Playback number
320 | }
321 | else
322 | {
323 | yackerror();
324 | }
325 |
326 | }
327 |
328 |
329 | if ((mode == PLAY) && interval)
330 | {
331 |
332 | #ifdef POWERSAVE
333 |
334 | // If we execute this, the interval counter is positive which means we are waiting
335 | // for a message playback. In this case we must not allow the CPU to enter sleep mode.
336 |
337 | yackpower(FALSE); // Inhibit sleep mode
338 |
339 | #endif
340 |
341 | if (timer) timer--; // Countdown until a second has expired
342 | else
343 | {
344 | timer = YACKSECS(1); // Reset timer
345 |
346 | if ((--interval)==0) // Interval was > 0. Did decrement bring it to 0?
347 | {
348 |
349 | interval = yackuser(READ, 1, 0); // Reset the interval timer
350 | yackmessage(PLAY,4); // And play message 4
351 |
352 |
353 | }
354 |
355 | }
356 |
357 | }
358 |
359 | }
360 |
361 |
362 |
363 |
364 | void commandmode(void)
365 | /*!
366 | @brief Command mode
367 |
368 | This routine implements command mode. Entries are read from the paddle
369 | and interpreted as commands.
370 |
371 | */
372 | {
373 |
374 | char c; // Character from Morse key
375 | word timer; // Exit timer
376 |
377 | yackinhibit(ON); // Sidetone = on, Keyer = off
378 |
379 | yackchar('?'); // Play Greeting
380 |
381 | timer = YACKSECS(DEFTIMEOUT); // Time out after 10 seconds
382 |
383 | while ((yackctrlkey(TRUE)==0) && (timer-- > 0))
384 | {
385 |
386 | c=yackiambic(OFF);
387 | if (c) timer = YACKSECS(DEFTIMEOUT); // Reset timeout if character read
388 |
389 | yackbeat();
390 |
391 | lfsr(255); // Keep seeding the LFSR so we get different callsigns
392 |
393 | if (!yackflag(CONFLOCK)) // No Configuration lock?
394 | {
395 | switch (c) // These are the lockable configuration commands
396 | {
397 |
398 | case 'R': // Reset
399 | yackreset();
400 | c = TRUE;
401 | break;
402 |
403 | case 'A': // IAMBIC A
404 | yackmode(IAMBICA);
405 | c = TRUE;
406 | break;
407 |
408 | case 'B': // IAMBIC B
409 | yackmode(IAMBICB);
410 | c = TRUE;
411 | break;
412 |
413 | case 'L': // ULTIMATIC
414 | yackmode(ULTIMATIC);
415 | c = TRUE;
416 | break;
417 |
418 | case 'D': // DAHPRIO
419 | yackmode(DAHPRIO);
420 | c = TRUE;
421 | break;
422 |
423 | case 'X': // Paddle swapping
424 | yacktoggle(PDLSWAP);
425 | c = TRUE;
426 | break;
427 |
428 | case 'S': // Sidetone toggle
429 | yacktoggle(SIDETONE);
430 | c = TRUE;
431 | break;
432 |
433 | case 'K': // TX keying toggle
434 | yacktoggle(TXKEY);
435 | c = TRUE;
436 | break;
437 |
438 | case 'Z': // Farnsworth pause
439 | setfarns();
440 | c = TRUE;
441 | break;
442 |
443 | case 'F': // TX level inverter toggle
444 | yacktoggle(TXINV);
445 | c = TRUE;
446 | break;
447 |
448 | case '1': // Record Macro 1
449 | yackchar('1');
450 | yackmessage(RECORD,1);
451 | c = TRUE;
452 | break;
453 |
454 | case '2': // Record Macro 2
455 | yackchar('2');
456 | yackmessage(RECORD,2);
457 | c = TRUE;
458 | break;
459 |
460 | case '3': // Record Macro 3
461 | yackchar('3');
462 | yackmessage(RECORD,3);
463 | c = TRUE;
464 | break;
465 |
466 | case '4': // Record Macro 4
467 | yackchar('4');
468 | yackmessage(RECORD,4);
469 | c = TRUE;
470 | break;
471 |
472 | case 'N': // Automatic Beacon
473 | beacon(RECORD);
474 | c = TRUE;
475 | break;
476 |
477 | }
478 |
479 | }
480 |
481 | switch (c) // Commands that can be used anytime
482 | {
483 |
484 | case 'V': // Version
485 | yackstring(vers);
486 | c = TRUE;
487 | break;
488 |
489 |
490 | case 'P': // Pitch
491 | pitch();
492 | c = TRUE;
493 | break;
494 |
495 | case 'U': // Tune
496 | yackinhibit(OFF);
497 | yacktune();
498 | yackinhibit(ON);
499 | c = TRUE;
500 | break;
501 |
502 | case 'C': // Callsign training
503 | cstrain();
504 | c = TRUE;
505 | break;
506 |
507 | case '0': // Lock changes
508 | yacktoggle(CONFLOCK);
509 | c = TRUE;
510 | break;
511 |
512 | case 'E': // Playback Macro 1
513 | yackinhibit(OFF);
514 | yackmessage(PLAY,1);
515 | yackinhibit(ON);
516 | timer = YACKSECS(MACTIMEOUT);
517 | c = FALSE;
518 | break;
519 |
520 | case 'I': // Playback Macro 2
521 | yackinhibit(OFF);
522 | yackmessage(PLAY,2);
523 | yackinhibit(ON);
524 | timer = YACKSECS(MACTIMEOUT);
525 | c = FALSE;
526 | break;
527 |
528 | case 'T': // Playback Macro 3
529 | yackinhibit(OFF);
530 | yackmessage(PLAY,3);
531 | yackinhibit(ON);
532 | timer = YACKSECS(MACTIMEOUT);
533 | c = FALSE;
534 | break;
535 |
536 | case 'M': // Playback Macro 4
537 | yackinhibit(OFF);
538 | yackmessage(PLAY,4);
539 | yackinhibit(ON);
540 | timer = YACKSECS(MACTIMEOUT);
541 | c = FALSE;
542 | break;
543 |
544 | case 'W': // Query WPM
545 | yacknumber(yackwpm());
546 | c = TRUE;
547 | break;
548 |
549 |
550 | }
551 |
552 | if (c == TRUE) // If c still contains a string, the command was not handled properly
553 | {
554 | yacksave(); //Save any non-volatile changes to EEPROM
555 | yackdelay(DAHLEN * 3); //Eliminate runon txok on some commands
556 | yackstring(txok);
557 | }
558 | else if (c)
559 | yackerror();
560 |
561 | }
562 |
563 |
564 | yackstring(prgx); // Sign off
565 |
566 | yackinhibit(OFF); // Back to normal mode
567 |
568 | }
569 |
570 |
571 |
572 | int main(void)
573 | /*!
574 | @brief Trivial main routine
575 |
576 | Yack library is initialized, command mode is entered on request and both
577 | beacon and keyer routines are called in 10 ms intervals.
578 |
579 | @return Not relevant
580 | */
581 | {
582 |
583 | yackinit(); // Initialize YACK hardware
584 |
585 | yackinhibit(ON); //side tone greeting to confirm the unit is alive and kicking
586 | yackstring(imok);
587 | yackinhibit(OFF);
588 |
589 | while(1) // Endless core loop of the keyer app
590 | {
591 |
592 | if (yackctrlkey(TRUE)) // If command key pressed, go to command mode
593 | commandmode();
594 |
595 | yackbeat();
596 | beacon(PLAY); // Play beacon if requested
597 | yackiambic(OFF);
598 |
599 | }
600 |
601 | return 0;
602 | }
603 |
604 |
605 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # Hey Emacs, this is a -*- makefile -*-
2 | #----------------------------------------------------------------------------
3 | #
4 | #----------------------------------------------------------------------------
5 | # On command line:
6 | #
7 | # make all = Make software.
8 | #
9 | # make clean = Clean out built project files.
10 | #
11 | # make coff = Convert ELF to AVR COFF.
12 | #
13 | # make extcoff = Convert ELF to AVR Extended COFF.
14 | #
15 | # make program = Download the hex file to the device, using avrdude.
16 | # Please customize the avrdude settings below first!
17 | #
18 | # make debug = Start either simulavr or avarice as specified for debugging,
19 | # with avr-gdb or avr-insight as the front end for debugging.
20 | #
21 | # make filename.s = Just compile filename.c into the assembler code only.
22 | #
23 | # make filename.i = Create a preprocessed source file for use in submitting
24 | # bug reports to the GCC project.
25 | #
26 | # To rebuild project do "make clean" then "make all".
27 | #----------------------------------------------------------------------------
28 |
29 |
30 | #MCU=attiny45
31 | MCU=attiny85
32 | #ADMCU=t45
33 | ADMCU=t85
34 |
35 |
36 | # Processor frequency.
37 | # This will define a symbol, F_CPU, in all source code files equal to the
38 | # processor frequency. You can then use this symbol in your source code to
39 | # calculate timings. Do NOT tack on a 'UL' at the end, this will be done
40 | # automatically to create a 32-bit value in your source code.
41 | # Typical values are:
42 | # F_CPU = 1000000
43 | # F_CPU = 1843200
44 | # F_CPU = 2000000
45 | # F_CPU = 3686400
46 | # F_CPU = 4000000
47 | # F_CPU = 7372800
48 | # F_CPU = 8000000
49 | # F_CPU = 11059200
50 | # F_CPU = 14745600
51 | # F_CPU = 16000000
52 | # F_CPU = 18432000
53 | # F_CPU = 20000000
54 | F_CPU = 1000000
55 |
56 |
57 | # Output format. (can be srec, ihex, binary)
58 | FORMAT = ihex
59 |
60 |
61 | # Target file name (without extension).
62 | TARGET = main
63 |
64 |
65 | # Object files directory
66 | # To put object files in current directory, use a dot (.), do NOT make
67 | # this an empty or blank macro!
68 | OBJDIR = .
69 |
70 |
71 | # List C source files here. (C dependencies are automatically generated.)
72 | SRC += $(TARGET).c yack.c
73 |
74 | # List C++ source files here. (C dependencies are automatically generated.)
75 | CPPSRC =
76 |
77 |
78 | # List Assembler source files here.
79 | # Make them always end in a capital .S. Files ending in a lowercase .s
80 | # will not be considered source files but generated files (assembler
81 | # output from the compiler), and will be deleted upon "make clean"!
82 | # Even though the DOS/Win* filesystem matches both .s and .S the same,
83 | # it will preserve the spelling of the filenames, and gcc itself does
84 | # care about how the name is spelled on its command-line.
85 | ASRC =
86 |
87 |
88 | # Optimization level, can be [0, 1, 2, 3, s].
89 | # 0 = turn off optimization. s = optimize for size.
90 | # (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
91 | OPT = s
92 |
93 |
94 | # Debugging format.
95 | # Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.
96 | # AVR Studio 4.10 requires dwarf-2.
97 | # AVR [Extended] COFF format requires stabs, plus an avr-objcopy run.
98 | DEBUG = stabs
99 |
100 |
101 | # List any extra directories to look for include files here.
102 | # Each directory must be seperated by a space.
103 | # Use forward slashes for directory separators.
104 | # For a directory that has spaces, enclose it in quotes.
105 | EXTRAINCDIRS =
106 |
107 |
108 | # Compiler flag to set the C Standard level.
109 | # c89 = "ANSI" C
110 | # gnu89 = c89 plus GCC extensions
111 | # c99 = ISO C99 standard (not yet fully implemented)
112 | # gnu99 = c99 plus GCC extensions
113 | CSTANDARD = -std=gnu99
114 |
115 |
116 | # Place -D or -U options here for C sources
117 | CDEFS = -DF_CPU=$(F_CPU)UL
118 |
119 |
120 | # Place -D or -U options here for C++ sources
121 | CPPDEFS = -DF_CPU=$(F_CPU)UL
122 | #CPPDEFS += -D__STDC_LIMIT_MACROS
123 | #CPPDEFS += -D__STDC_CONSTANT_MACROS
124 |
125 |
126 |
127 | #---------------- Compiler Options C ----------------
128 | # -g*: generate debugging information
129 | # -O*: optimization level
130 | # -f...: tuning, see GCC manual and avr-libc documentation
131 | # -Wall...: warning level
132 | # -Wa,...: tell GCC to pass this to the assembler.
133 | # -adhlns...: create assembler listing
134 | CFLAGS = -g$(DEBUG)
135 | CFLAGS += $(CDEFS)
136 | CFLAGS += -O$(OPT)
137 | CFLAGS += -funsigned-char
138 | CFLAGS += -funsigned-bitfields
139 | CFLAGS += -fpack-struct
140 | CFLAGS += -fshort-enums
141 | CFLAGS += -Wall
142 | CFLAGS += -Wstrict-prototypes
143 | #CFLAGS += -mshort-calls
144 | #CFLAGS += -fno-unit-at-a-time
145 | #CFLAGS += -Wundef
146 | #CFLAGS += -Wunreachable-code
147 | #CFLAGS += -Wsign-compare
148 | CFLAGS += -Wa,-adhlns=$(<:%.c=$(OBJDIR)/%.lst)
149 | CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
150 | CFLAGS += $(CSTANDARD)
151 |
152 |
153 | #---------------- Compiler Options C++ ----------------
154 | # -g*: generate debugging information
155 | # -O*: optimization level
156 | # -f...: tuning, see GCC manual and avr-libc documentation
157 | # -Wall...: warning level
158 | # -Wa,...: tell GCC to pass this to the assembler.
159 | # -adhlns...: create assembler listing
160 | CPPFLAGS = -g$(DEBUG)
161 | CPPFLAGS += $(CPPDEFS)
162 | CPPFLAGS += -O$(OPT)
163 | CPPFLAGS += -funsigned-char
164 | CPPFLAGS += -funsigned-bitfields
165 | CPPFLAGS += -fpack-struct
166 | CPPFLAGS += -fshort-enums
167 | CPPFLAGS += -fno-exceptions
168 | CPPFLAGS += -Wall
169 | CFLAGS += -Wundef
170 | #CPPFLAGS += -mshort-calls
171 | #CPPFLAGS += -fno-unit-at-a-time
172 | #CPPFLAGS += -Wstrict-prototypes
173 | #CPPFLAGS += -Wunreachable-code
174 | #CPPFLAGS += -Wsign-compare
175 | CPPFLAGS += -Wa,-adhlns=$(<:%.cpp=$(OBJDIR)/%.lst)
176 | CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
177 | #CPPFLAGS += $(CSTANDARD)
178 |
179 |
180 | #---------------- Assembler Options ----------------
181 | # -Wa,...: tell GCC to pass this to the assembler.
182 | # -ahlms: create listing
183 | # -gstabs: have the assembler create line number information; note that
184 | # for use in COFF files, additional information about filenames
185 | # and function names needs to be present in the assembler source
186 | # files -- see avr-libc docs [FIXME: not yet described there]
187 | # -listing-cont-lines: Sets the maximum number of continuation lines of hex
188 | # dump that will be displayed for a given single line of source input.
189 | ASFLAGS = -Wa,-adhlns=$(<:.S=$(OBJDIR)/%.lst),-gstabs,--listing-cont-lines=100
190 |
191 |
192 | #---------------- Library Options ----------------
193 | # Minimalistic printf version
194 | PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min
195 |
196 | # Floating point printf version (requires MATH_LIB = -lm below)
197 | PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt
198 |
199 | # If this is left blank, then it will use the Standard printf version.
200 | PRINTF_LIB =
201 | #PRINTF_LIB = $(PRINTF_LIB_MIN)
202 | #PRINTF_LIB = $(PRINTF_LIB_FLOAT)
203 |
204 |
205 | # Minimalistic scanf version
206 | SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min
207 |
208 | # Floating point + %[ scanf version (requires MATH_LIB = -lm below)
209 | SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt
210 |
211 | # If this is left blank, then it will use the Standard scanf version.
212 | SCANF_LIB =
213 | #SCANF_LIB = $(SCANF_LIB_MIN)
214 | #SCANF_LIB = $(SCANF_LIB_FLOAT)
215 |
216 |
217 | MATH_LIB = -lm
218 |
219 |
220 | # List any extra directories to look for libraries here.
221 | # Each directory must be seperated by a space.
222 | # Use forward slashes for directory separators.
223 | # For a directory that has spaces, enclose it in quotes.
224 | EXTRALIBDIRS =
225 |
226 |
227 |
228 | #---------------- External Memory Options ----------------
229 |
230 | # 64 KB of external RAM, starting after internal RAM (ATmega128!),
231 | # used for variables (.data/.bss) and heap (malloc()).
232 | #EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
233 |
234 | # 64 KB of external RAM, starting after internal RAM (ATmega128!),
235 | # only used for heap (malloc()).
236 | #EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff
237 |
238 | EXTMEMOPTS =
239 |
240 |
241 |
242 | #---------------- Linker Options ----------------
243 | # -Wl,...: tell GCC to pass this to linker.
244 | # -Map: create map file
245 | # --cref: add cross reference to map file
246 | LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
247 | LDFLAGS += $(EXTMEMOPTS)
248 | LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))
249 | LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
250 | #LDFLAGS += -T linker_script.x
251 |
252 |
253 |
254 | #---------------- Programming Options (avrdude) ----------------
255 |
256 | # Programming hardware: alf avr910 avrisp bascom bsd
257 | # dt006 pavr picoweb pony-stk200 sp12 stk200 stk500
258 | #
259 | # Type: avrdude -c ?
260 | # to get a full listing.
261 | #
262 | AVRDUDE_PROGRAMMER = avrisp
263 |
264 | AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex
265 | AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep
266 |
267 |
268 | # Uncomment the following if you want avrdude's erase cycle counter.
269 | # Note that this counter needs to be initialized first using -Yn,
270 | # see avrdude manual.
271 | #AVRDUDE_ERASE_COUNTER = -y
272 |
273 | # Uncomment the following if you do /not/ wish a verification to be
274 | # performed after programming the device.
275 | #AVRDUDE_NO_VERIFY = -V
276 |
277 | # Increase verbosity level. Please use this when submitting bug
278 | # reports about avrdude. See
279 | # to submit bug reports.
280 | #AVRDUDE_VERBOSE = -v -v
281 |
282 | AVRDUDE_FLAGS = -p $(ADMCU) -c $(AVRDUDE_PROGRAMMER)
283 | AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY)
284 | AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE)
285 | AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER)
286 | AVRDUDE_FLAGS += -P /dev/cu.usbserial-A9007MkN
287 | AVRDUDE_FLAGS += -b 19200
288 |
289 |
290 | #---------------- Debugging Options ----------------
291 |
292 | # For simulavr only - target MCU frequency.
293 | DEBUG_MFREQ = $(F_CPU)
294 |
295 | # Set the DEBUG_UI to either gdb or insight.
296 | # DEBUG_UI = gdb
297 | DEBUG_UI = insight
298 |
299 | # Set the debugging back-end to either avarice, simulavr.
300 | DEBUG_BACKEND = avarice
301 | #DEBUG_BACKEND = simulavr
302 |
303 | # GDB Init Filename.
304 | GDBINIT_FILE = __avr_gdbinit
305 |
306 | # When using avarice settings for the JTAG
307 | JTAG_DEV = /dev/com1
308 |
309 | # Debugging port used to communicate between GDB / avarice / simulavr.
310 | DEBUG_PORT = 4242
311 |
312 | # Debugging host used to communicate between GDB / avarice / simulavr, normally
313 | # just set to localhost unless doing some sort of crazy debugging when
314 | # avarice is running on a different computer.
315 | DEBUG_HOST = localhost
316 |
317 |
318 |
319 | #============================================================================
320 |
321 |
322 | # Define programs and commands.
323 | SHELL = sh
324 | CC = avr-gcc
325 | OBJCOPY = avr-objcopy
326 | OBJDUMP = avr-objdump
327 | SIZE = avr-size
328 | AR = avr-ar rcs
329 | NM = avr-nm
330 | AVRDUDE = avrdude
331 | REMOVE = rm -f
332 | REMOVEDIR = rm -rf
333 | COPY = cp
334 | WINSHELL = cmd
335 |
336 |
337 | # Define Messages
338 | # English
339 | MSG_ERRORS_NONE = Errors: none
340 | MSG_BEGIN = -------- begin --------
341 | MSG_END = -------- end --------
342 | MSG_SIZE_BEFORE = Size before:
343 | MSG_SIZE_AFTER = Size after:
344 | MSG_COFF = Converting to AVR COFF:
345 | MSG_EXTENDED_COFF = Converting to AVR Extended COFF:
346 | MSG_FLASH = Creating load file for Flash:
347 | MSG_EEPROM = Creating load file for EEPROM:
348 | MSG_EXTENDED_LISTING = Creating Extended Listing:
349 | MSG_SYMBOL_TABLE = Creating Symbol Table:
350 | MSG_LINKING = Linking:
351 | MSG_COMPILING = Compiling C:
352 | MSG_COMPILING_CPP = Compiling C++:
353 | MSG_ASSEMBLING = Assembling:
354 | MSG_CLEANING = Cleaning project:
355 | MSG_CREATING_LIBRARY = Creating library:
356 |
357 |
358 |
359 |
360 | # Define all object files.
361 | OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o)
362 |
363 | # Define all listing files.
364 | LST = $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst)
365 |
366 |
367 | # Compiler flags to generate dependency files.
368 | GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d
369 |
370 |
371 | # Combine all necessary flags and optional flags.
372 | # Add target processor to flags.
373 | ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS)
374 | ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS)
375 | ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
376 |
377 |
378 | # Default target.
379 | all: begin gccversion sizebefore build sizeafter end
380 |
381 | # Change the build target to build a HEX file or a library.
382 | build: elf hex eep lss sym extcoff
383 | #build: lib
384 |
385 |
386 | elf: $(TARGET).elf
387 | hex: $(TARGET).hex
388 | eep: $(TARGET).eep
389 | lss: $(TARGET).lss
390 | sym: $(TARGET).sym
391 | LIBNAME=lib$(TARGET).a
392 | lib: $(LIBNAME)
393 |
394 |
395 |
396 | # Eye candy.
397 | # AVR Studio 3.x does not check make's exit code but relies on
398 | # the following magic strings to be generated by the compile job.
399 | begin:
400 | @echo
401 | @echo $(MSG_BEGIN)
402 |
403 | end:
404 | @echo $(MSG_END)
405 | @echo
406 |
407 |
408 | # Display size of file.
409 | HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex
410 | ELFSIZE = $(SIZE) --format=avr $(TARGET).elf
411 |
412 | sizebefore:
413 | @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \
414 | 2>/dev/null; echo; fi
415 |
416 | sizeafter:
417 | @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \
418 | 2>/dev/null; echo; fi
419 |
420 |
421 |
422 | # Display compiler version information.
423 | gccversion :
424 | @$(CC) --version
425 |
426 |
427 |
428 | # Program the device.
429 | program: $(TARGET).hex $(TARGET).eep
430 | $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
431 |
432 |
433 | # Generate avr-gdb config/init file which does the following:
434 | # define the reset signal, load the target file, connect to target, and set
435 | # a breakpoint at main().
436 | gdb-config:
437 | @$(REMOVE) $(GDBINIT_FILE)
438 | @echo define reset >> $(GDBINIT_FILE)
439 | @echo SIGNAL SIGHUP >> $(GDBINIT_FILE)
440 | @echo end >> $(GDBINIT_FILE)
441 | @echo file $(TARGET).elf >> $(GDBINIT_FILE)
442 | @echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE)
443 | ifeq ($(DEBUG_BACKEND),simulavr)
444 | @echo load >> $(GDBINIT_FILE)
445 | endif
446 | @echo break main >> $(GDBINIT_FILE)
447 |
448 | debug: gdb-config $(TARGET).elf
449 | ifeq ($(DEBUG_BACKEND), avarice)
450 | @echo Starting AVaRICE - Press enter when "waiting to connect" message displays.
451 | @$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \
452 | $(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT)
453 | @$(WINSHELL) /c pause
454 |
455 | else
456 | @$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \
457 | $(DEBUG_MFREQ) --port $(DEBUG_PORT)
458 | endif
459 | @$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE)
460 |
461 |
462 |
463 |
464 | # Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
465 | COFFCONVERT = $(OBJCOPY) --debugging
466 | COFFCONVERT += --change-section-address .data-0x800000
467 | COFFCONVERT += --change-section-address .bss-0x800000
468 | COFFCONVERT += --change-section-address .noinit-0x800000
469 | COFFCONVERT += --change-section-address .eeprom-0x810000
470 |
471 |
472 |
473 | coff: $(TARGET).elf
474 | @echo
475 | @echo $(MSG_COFF) $(TARGET).cof
476 | $(COFFCONVERT) -O coff-avr $< $(TARGET).cof
477 |
478 |
479 | extcoff: $(TARGET).elf
480 | @echo
481 | @echo $(MSG_EXTENDED_COFF) $(TARGET).cof
482 | $(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof
483 |
484 |
485 |
486 | # Create final output files (.hex, .eep) from ELF output file.
487 | %.hex: %.elf
488 | @echo
489 | @echo $(MSG_FLASH) $@
490 | $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
491 |
492 | %.eep: %.elf
493 | @echo
494 | @echo $(MSG_EEPROM) $@
495 | -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
496 | --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0
497 |
498 | # Create extended listing file from ELF output file.
499 | %.lss: %.elf
500 | @echo
501 | @echo $(MSG_EXTENDED_LISTING) $@
502 | $(OBJDUMP) -h -S $< > $@
503 |
504 | # Create a symbol table from ELF output file.
505 | %.sym: %.elf
506 | @echo
507 | @echo $(MSG_SYMBOL_TABLE) $@
508 | $(NM) -n $< > $@
509 |
510 |
511 |
512 | # Create library from object files.
513 | .SECONDARY : $(TARGET).a
514 | .PRECIOUS : $(OBJ)
515 | %.a: $(OBJ)
516 | @echo
517 | @echo $(MSG_CREATING_LIBRARY) $@
518 | $(AR) $@ $(OBJ)
519 |
520 |
521 | # Link: create ELF output file from object files.
522 | .SECONDARY : $(TARGET).elf
523 | .PRECIOUS : $(OBJ)
524 | %.elf: $(OBJ)
525 | @echo
526 | @echo $(MSG_LINKING) $@
527 | $(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS)
528 |
529 |
530 | # Compile: create object files from C source files.
531 | $(OBJDIR)/%.o : %.c
532 | @echo
533 | @echo $(MSG_COMPILING) $<
534 | $(CC) -c $(ALL_CFLAGS) $< -o $@
535 |
536 |
537 | # Compile: create object files from C++ source files.
538 | $(OBJDIR)/%.o : %.cpp
539 | @echo
540 | @echo $(MSG_COMPILING_CPP) $<
541 | $(CC) -c $(ALL_CPPFLAGS) $< -o $@
542 |
543 |
544 | # Compile: create assembler files from C source files.
545 | %.s : %.c
546 | $(CC) -S $(ALL_CFLAGS) $< -o $@
547 |
548 |
549 | # Compile: create assembler files from C++ source files.
550 | %.s : %.cpp
551 | $(CC) -S $(ALL_CPPFLAGS) $< -o $@
552 |
553 |
554 | # Assemble: create object files from assembler source files.
555 | $(OBJDIR)/%.o : %.S
556 | @echo
557 | @echo $(MSG_ASSEMBLING) $<
558 | $(CC) -c $(ALL_ASFLAGS) $< -o $@
559 |
560 |
561 | # Create preprocessed source for use in sending a bug report.
562 | %.i : %.c
563 | $(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@
564 |
565 |
566 | # Target: clean project.
567 | clean: begin clean_list end
568 |
569 | clean_list :
570 | @echo
571 | @echo $(MSG_CLEANING)
572 | $(REMOVE) $(TARGET).hex
573 | $(REMOVE) $(TARGET).eep
574 | $(REMOVE) $(TARGET).cof
575 | $(REMOVE) $(TARGET).elf
576 | $(REMOVE) $(TARGET).map
577 | $(REMOVE) $(TARGET).sym
578 | $(REMOVE) $(TARGET).lss
579 | $(REMOVE) $(SRC:%.c=$(OBJDIR)/%.o)
580 | $(REMOVE) $(SRC:%.c=$(OBJDIR)/%.lst)
581 | $(REMOVE) $(SRC:.c=.s)
582 | $(REMOVE) $(SRC:.c=.d)
583 | $(REMOVE) $(SRC:.c=.i)
584 | $(REMOVEDIR) .dep
585 |
586 |
587 | # Create object files directory
588 | $(shell mkdir $(OBJDIR) 2>/dev/null)
589 |
590 |
591 | # Include the dependency files.
592 | -include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
593 |
594 |
595 | # Listing of phony targets.
596 | .PHONY : all begin finish end sizebefore sizeafter gccversion \
597 | build elf hex eep lss sym coff extcoff \
598 | clean clean_list program debug gdb-config
599 |
600 |
601 |
602 |
603 |
604 |
--------------------------------------------------------------------------------
/yack.c:
--------------------------------------------------------------------------------
1 | /*!
2 |
3 | @file yack.c
4 | @brief CW Keyer library
5 | @author Jan Lategahn DK3LJ jan@lategahn.com (C) 2011; modified by Jack Welch AI4SV; modified by Don Froula WD9DMP
6 |
7 | @version 0.87
8 |
9 | This program is free software: you can redistribute it and/or modify
10 | it under the terms of the GNU General Public License as published by
11 | the Free Software Foundation, either version 3 of the License, or
12 | (at your option) any later version.
13 |
14 | This program is distributed in the hope that it will be useful,
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | GNU General Public License for more details.
18 |
19 | You should have received a copy of the GNU General Public License
20 | along with this program. If not, see .
21 |
22 | @date 15.10.2010 - Created
23 | @date 03.10.2013 - Last update
24 | @date 21.12.2016 - Added additional prosigns and punctuation. Added 2 additional memories for ATTINY85. Fixed save of speed change to EEPROM. (WD9DMP)
25 | @date 03.01.2017 - If memory recording is interrupted by command button, keyer now returns txok ("R") and stays in command mode. Memory is unchanged.
26 | Memory playback halts immediately on command key instead of looping through message length without playing anything.
27 | Removed playback of recorded message before saving.
28 | Changed yackstring command to return to command mode instead of normal mode if interrupted with command key
29 |
30 | @todo Make the delay dependent on T/C 1
31 |
32 | */
33 |
34 |
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 | #include
41 | #include
42 | #include "yack.h"
43 |
44 | // Forward declaration of private functions
45 | static void key( byte mode);
46 | static char morsechar(byte buffer);
47 | static void keylatch(void);
48 |
49 | // Enumerations
50 |
51 | enum FSMSTATE {
52 | IDLE, //!< Not keyed, waiting for paddle
53 | KEYED, //!< Keyed, waiting for duration of current element
54 | IEG //!< In Inter-Element-Gap
55 | };
56 |
57 | // Module local definitions
58 |
59 | static byte yackflags; // Permanent (stored) status of module flags
60 | static byte volflags=0; // Temporary working flags (volatile)
61 | static word ctcvalue; // Pitch
62 | static word wpmcnt; // Speed
63 | static byte wpm; // Real wpm
64 | static byte farnsworth; // Additional Farnsworth pause
65 |
66 | // EEPROM Data
67 |
68 | byte magic EEMEM = MAGPAT; // Needs to contain 'A5' if mem is valid
69 | byte flagstor EEMEM = ( IAMBICB | TXKEY | SIDETONE); // Defaults
70 | word ctcstor EEMEM = DEFCTC; // Pitch = 800Hz
71 | byte wpmstor EEMEM = DEFWPM; // 15 WPM
72 | byte fwstor EEMEM = 0; // No farnsworth pause
73 | word user1 EEMEM = 0; // User storage
74 | word user2 EEMEM = 0; // User storage
75 |
76 | //char eebuffer1[100] EEMEM = "message 1";
77 | //char eebuffer2[100] EEMEM = "message 2";
78 | char eebuffer1[100] EEMEM = "message 1";
79 | char eebuffer2[100] EEMEM = "message 2";
80 | char eebuffer3[100] EEMEM = "message 3";
81 | char eebuffer4[100] EEMEM = "message 4";
82 |
83 | // Flash data
84 |
85 | //! Morse code table in Flash
86 |
87 | //! Encoding: Each byte is read from the left. 0 stands for a dot, 1
88 | //! stands for a dash. After each played element the content is shifted
89 | //! left. Playback stops when the leftmost bit contains a "1" and the rest
90 | //! of the bits are all zero.
91 | //!
92 | //! Example: A = .-
93 | //! Encoding: 01100000
94 | //! .-
95 | //! | This is the stop marker (1 with all trailing zeros)
96 |
97 | const byte morse[] PROGMEM =
98 | {
99 |
100 | 0b11111100, // 0
101 | 0b01111100, // 1
102 | 0b00111100, // 2
103 | 0b00011100, // 3
104 | 0b00001100, // 4
105 | 0b00000100, // 5
106 | 0b10000100, // 6
107 | 0b11000100, // 7
108 | 0b11100100, // 8
109 | 0b11110100, // 9
110 | 0b01100000, // A
111 | 0b10001000, // B
112 | 0b10101000, // C
113 | 0b10010000, // D
114 | 0b01000000, // E
115 | 0b00101000, // F
116 | 0b11010000, // G
117 | 0b00001000, // H
118 | 0b00100000, // I
119 | 0b01111000, // J
120 | 0b10110000, // K
121 | 0b01001000, // L
122 | 0b11100000, // M
123 | 0b10100000, // N
124 | 0b11110000, // O
125 | 0b01101000, // P
126 | 0b11011000, // Q
127 | 0b01010000, // R
128 | 0b00010000, // S
129 | 0b11000000, // T
130 | 0b00110000, // U
131 | 0b00011000, // V
132 | 0b01110000, // W
133 | 0b10011000, // X
134 | 0b10111000, // Y
135 | 0b11001000, // Z
136 | 0b00110010, // ?
137 | 0b01010110, // .
138 | 0b10010100, // /
139 | 0b11101000, // ! (American Morse version, commonly used in ham circles)
140 | 0b11001110, // ,
141 | 0b11100010, // :
142 | 0b10101010, // ;
143 | 0b01001010, // "
144 | 0b00010011, // $
145 | 0b01111010, // ' (Apostrophe)
146 | 0b10110100, // ( or [ (also prosign KN)
147 | 0b10110110, // ) or ]
148 | 0b10000110, // - (Hyphen or single dash)
149 | 0b01101010, // @
150 | 0b00110110, // _ (Underline)
151 | 0b01010010, // Paragaraph break symbol
152 | 0b10001100, // = and BT
153 | 0b00010110, // SK
154 | 0b01010100, // + and AR
155 | 0b10001011, // BK
156 | 0b01000100, // AS
157 | 0b10101100, // KA (also ! in alternate Continental Morse)
158 | 0b00010100, // VE
159 | 0b01011000 // AA
160 | };
161 |
162 |
163 | // The special characters at the end of the above table can not be decoded
164 | // without a small table to define their content. # stands for SK, $ for AR
165 |
166 | // To add new characters, add them in the code table above at the end and below
167 | // Do not forget to increase the legth of the array..
168 |
169 | const char spechar[24] PROGMEM = "?./!,:;~$^()-@_|=#+*%&<>";
170 |
171 |
172 |
173 | // Functions
174 |
175 | // ***************************************************************************
176 | // Control functions
177 | // ***************************************************************************
178 |
179 | void yackreset (void)
180 | /*!
181 | @brief Sets all yack parameters to standard values
182 |
183 | This function resets all YACK EEPROM settings to their default values as
184 | stored in the .h file. It sets the dirty flag and calls the save routine
185 | to write the data into EEPROM immediately.
186 | */
187 | {
188 |
189 | ctcvalue=DEFCTC; // Initialize to 800 Hz
190 | wpm=DEFWPM; // Init to default speed
191 | wpmcnt=(1200/YACKBEAT)/DEFWPM; // default speed
192 | farnsworth=0; // No Farnsworth gap
193 | yackflags = FLAGDEFAULT;
194 |
195 | volflags |= DIRTYFLAG;
196 | yacksave(); // Store them in EEPROM
197 |
198 | }
199 |
200 |
201 | void yackinit (void)
202 | /*!
203 | @brief Initializes the YACK library
204 |
205 | This function initializes the keyer hardware according to configurations in the .h file.
206 | Then it attempts to read saved configuration settings from EEPROM. If not possible, it
207 | will reset all values to their defaults.
208 | This function must be called once before the remaining fuctions can be used.
209 | */
210 | {
211 |
212 | byte magval;
213 |
214 | // Configure DDR. Make OUT and ST output ports
215 | SETBIT (OUTDDR,OUTPIN);
216 | SETBIT (STDDR,STPIN);
217 |
218 | // Raise internal pullups for all inputs
219 | SETBIT (KEYPORT,DITPIN);
220 | SETBIT (KEYPORT,DAHPIN);
221 | SETBIT (BTNPORT,BTNPIN);
222 |
223 | magval = eeprom_read_byte(&magic); // Retrieve magic value
224 |
225 | if (magval == MAGPAT) // Is memory valid
226 | {
227 | ctcvalue = eeprom_read_word(&ctcstor); // Retrieve last ctc setting
228 | wpm = eeprom_read_byte(&wpmstor); // Retrieve last wpm setting
229 | wpmcnt=(1200/YACKBEAT)/wpm; // Calculate speed
230 | farnsworth = eeprom_read_byte(&fwstor); // Retrieve last wpm setting
231 | yackflags = eeprom_read_byte(&flagstor); // Retrieve last flags
232 | }
233 | else
234 | {
235 | yackreset();
236 | }
237 |
238 | yackinhibit(OFF);
239 |
240 | #ifdef POWERSAVE
241 |
242 | PCMSK |= PWRWAKE; // Define which keys wake us up
243 | GIMSK |= (1< 0))
449 | farnsworth--;
450 |
451 | if ((dir == DOWN) && (farnsworth < MAXFARN))
452 | farnsworth++;
453 | }
454 | else // WPMSPEED
455 | {
456 | if ((dir == UP) && (wpm < MAXWPM))
457 | wpm++;
458 |
459 | if ((dir == DOWN) && (wpm > MINWPM))
460 | wpm--;
461 |
462 | wpmcnt=(1200/YACKBEAT)/wpm; // Calculate beats
463 |
464 | }
465 |
466 | volflags |= DIRTYFLAG; // Set the dirty flag
467 |
468 | yackplay(DIT);
469 | yackdelay(IEGLEN); // Inter Element gap
470 | yackplay(DAH);
471 | yackdelay(ICGLEN); // Inter Character gap
472 | yackfarns(); // Additional Farnsworth delay
473 |
474 | }
475 |
476 |
477 |
478 | void yackbeat (void)
479 | /*!
480 | @brief Heartbeat delay
481 |
482 | Several functions in the keyer are timing dependent. The most prominent example is the
483 | yackiambic function that implements the IAMBIC keyer finite state machine.
484 | The same expects to be called in intervals of YACKBEAT milliseconds. How this is
485 | implemented is left to the user. In a more complex application this would be done
486 | using an interrupt or a timer. For simpler cases this is a busy wait routine
487 | that delays exactly YACKBEAT ms.
488 |
489 | */
490 | {
491 | while((TIFR & (1< MINCTC)
517 | ctcvalue = MINCTC;
518 |
519 | volflags |= DIRTYFLAG; // Set the dirty flag
520 |
521 | }
522 |
523 |
524 |
525 |
526 | void yacktune (void)
527 | /*!
528 | @brief Activates Tuning mode
529 |
530 | This produces a solid keydown for TUNEDURATION seconds. After this the TX is unkeyed.
531 | The same can be achieved by presing either the DIT or the DAH contact or the control key.
532 |
533 | */
534 | {
535 | word timer = YACKSECS(TUNEDURATION);
536 |
537 | key(DOWN);
538 |
539 | while(timer && (KEYINP & (1<0 if flag(s) were set
578 |
579 | */
580 | {
581 | return yackflags & flag;
582 | }
583 |
584 |
585 |
586 | void yacktoggle(byte flag)
587 | /*!
588 | @brief Toggle feature flags
589 |
590 | When passed one (or more) flags, this routine flips the according bit in yackflags and
591 | thereby enables or disables the corresponding feature.
592 |
593 | @param flag A byte where any bit to toggle is set e.g. SIDETONE
594 | @return TRUE if all was OK, FALSE if configuration lock prevented changes
595 |
596 | */
597 | {
598 |
599 | yackflags ^= flag; // Toggle the feature bit
600 | volflags |= DIRTYFLAG; // Set the dirty flag
601 |
602 | }
603 |
604 |
605 |
606 |
607 | void yackerror (void)
608 | /*!
609 | @brief Creates a series of 8 dits
610 |
611 | The error prosign (8 dits) can not be encoded in our coding table. A call to this
612 | function produces it..
613 |
614 | */
615 | {
616 | byte i;
617 |
618 | for (i=0;i<8;i++)
619 | {
620 | yackplay(DIT);
621 | yackdelay(DITLEN);
622 | }
623 | yackdelay(DAHLEN);
624 |
625 | }
626 |
627 |
628 |
629 |
630 | // ***************************************************************************
631 | // CW Playback related functions
632 | // ***************************************************************************
633 |
634 | static void key(byte mode)
635 | /*!
636 | @brief Keys the transmitter and produces a sidetone
637 |
638 | .. but only if the corresponding functions (TXKEY and SIDETONE) have been set in
639 | the feature register. This function also handles a request to invert the keyer line
640 | if necessary (TXINV bit).
641 |
642 | This is a private function.
643 |
644 | @param mode UP or DOWN
645 |
646 | */
647 | {
648 |
649 | if (mode == DOWN)
650 | {
651 | if (volflags & SIDETONE) // Are we generating a Sidetone?
652 | {
653 | OCR0A = ctcvalue; // Then switch on the Sidetone generator
654 | OCR0B = ctcvalue;
655 |
656 | // Activate CTC mode
657 | TCCR0A |= (1<='0' && c<='9') // Is it a numerical digit?
799 | code = pgm_read_byte(&morse[c-'0']); // Find it in the beginning of array
800 |
801 | if(c>='a' && c<='z') // Is it a character?
802 | code = pgm_read_byte(&morse[c-'a'+10]); // Find it from position 10
803 |
804 | if(c>='A' && c<='Z') // Is it a character in upper case?
805 | code = pgm_read_byte(&morse[c-'A'+10]); // Same as above
806 |
807 | // Last we need to handle special characters. There is a small char
808 | // array "spechar" which contains the characters for the morse elements
809 | // at the end of the "morse" array (see there!)
810 | for(i=0;i=RBSIZE) // End of buffer reached?
1083 | {
1084 | yackerror();
1085 | i = 0;
1086 | }
1087 |
1088 | yackbeat(); // 10 ms heartbeat
1089 | }
1090 |
1091 | // Extimer has expired. Message has ended
1092 |
1093 | if(i) // Was anything received at all?
1094 | {
1095 | rambuffer[--i] = 0; // Add a \0 end marker over last space
1096 |
1097 | // Replay the message
1098 | //for (n=0;n