├── 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