Get basic Morse LED control working with JLed.
This commit is contained in:
		| @ -17,4 +17,6 @@ lib_deps = | |||||||
| 	me-no-dev/AsyncTCP@^1.1.1 | 	me-no-dev/AsyncTCP@^1.1.1 | ||||||
| 	me-no-dev/ESP Async WebServer@^1.2.3 | 	me-no-dev/ESP Async WebServer@^1.2.3 | ||||||
| 	contrem/arduino-timer@^3.0.1 | 	contrem/arduino-timer@^3.0.1 | ||||||
| 	kj7rrv/Telegraph@^1.0.0 | 	;kj7rrv/Telegraph@^1.0.0 | ||||||
|  | 	;etherkit/Etherkit Morse@^1.1.2 | ||||||
|  | 	jandelgado/JLed@^4.13.0 | ||||||
|  | |||||||
							
								
								
									
										17
									
								
								vulpes/src/README.md
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										17
									
								
								vulpes/src/README.md
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | # JLed morse example | ||||||
|  |  | ||||||
|  | This examples demonstrates an efficient method to generate morse code on  | ||||||
|  | an micro controller like the Arduino. | ||||||
|  |  | ||||||
|  | The morse example uses the morse alphabet encoded in a binary tree to  | ||||||
|  | generate morse code using a JLed user defined brightness class. The text | ||||||
|  | to be morsed is transformed into morse code and then transformed into a  | ||||||
|  | sequence of `1` and `0` which are written out to a GPIO controlling a LED or | ||||||
|  | a sound generator.  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## Author  | ||||||
|  |  | ||||||
|  | Jan Delgado | ||||||
|  |  | ||||||
							
								
								
									
										53
									
								
								vulpes/src/bitset.h
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										53
									
								
								vulpes/src/bitset.h
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,53 @@ | |||||||
|  | // Copyright (c) 2019 Jan Delgado <jdelgado[at]gmx.net> | ||||||
|  | // https://github.com/jandelgado/jled | ||||||
|  |  | ||||||
|  | #ifndef EXAMPLES_MORSE_BITSET_H_ | ||||||
|  | #define EXAMPLES_MORSE_BITSET_H_ | ||||||
|  |  | ||||||
|  | // a simple bit set with capacity of N bits, just enough for the morse demo | ||||||
|  | class Bitset { | ||||||
|  |  private: | ||||||
|  |     size_t n_; | ||||||
|  |     uint8_t* bits_; | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |     // returns num bytes needed to store n bits. | ||||||
|  |     static constexpr size_t num_bytes(size_t n) { | ||||||
|  |         return n > 0 ? ((n - 1) >> 3) + 1 : 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  public: | ||||||
|  |     Bitset() : Bitset(0) {} | ||||||
|  |  | ||||||
|  |     Bitset(const Bitset& b) : Bitset() { *this = b; } | ||||||
|  |  | ||||||
|  |     explicit Bitset(size_t n) : n_(n), bits_{new uint8_t[num_bytes(n)]} { | ||||||
|  |         memset(bits_, 0, num_bytes(n_)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Bitset& operator=(const Bitset& b) { | ||||||
|  |         if (&b == this) return *this; | ||||||
|  |         const auto size_new = num_bytes(b.n_); | ||||||
|  |         if (num_bytes(n_) != size_new) { | ||||||
|  |             delete[] bits_; | ||||||
|  |             bits_ = new uint8_t[size_new]; | ||||||
|  |             n_ = b.n_; | ||||||
|  |         } | ||||||
|  |         memcpy(bits_, b.bits_, size_new); | ||||||
|  |         return *this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     virtual ~Bitset() { | ||||||
|  |         delete[] bits_; | ||||||
|  |         bits_ = nullptr; | ||||||
|  |     } | ||||||
|  |     void set(size_t i, bool val) { | ||||||
|  |         if (val) | ||||||
|  |             bits_[i >> 3] |= (1 << (i & 7)); | ||||||
|  |         else | ||||||
|  |             bits_[i >> 3] &= ~(1 << (i & 7)); | ||||||
|  |     } | ||||||
|  |     bool test(size_t i) const { return (bits_[i >> 3] & (1 << (i & 7))) != 0; } | ||||||
|  |     size_t size() const { return n_; } | ||||||
|  | }; | ||||||
|  | #endif  // EXAMPLES_MORSE_BITSET_H_ | ||||||
| @ -18,6 +18,11 @@ | |||||||
| #include <Preferences.h> | #include <Preferences.h> | ||||||
| #include <arduino-timer.h> | #include <arduino-timer.h> | ||||||
| #include <Telegraph.h> | #include <Telegraph.h> | ||||||
|  | //#include <morse.h> //arduino morse | ||||||
|  | //#include <Morse.h> //etherkit morse | ||||||
|  | #include <jled.h> // jled | ||||||
|  | #include "morse.h" //jled | ||||||
|  | //#include "morse_effect.h"  // jled | ||||||
|  |  | ||||||
| // download zip from https://github.com/me-no-dev/ESPAsyncWebServer and install. | // download zip from https://github.com/me-no-dev/ESPAsyncWebServer and install. | ||||||
| #include <ESPAsyncWebServer.h> | #include <ESPAsyncWebServer.h> | ||||||
| @ -201,12 +206,41 @@ void k(){ | |||||||
|  |  | ||||||
| // ^^^^ | // ^^^^ | ||||||
|  |  | ||||||
| Telegraph telegraph(LED_BUILTIN, 10, HIGH); | //telegraph | ||||||
|  | //Telegraph telegraph(LED_BUILTIN, 10, HIGH); | ||||||
|  | Telegraph telegraph26(output26, 10, HIGH); | ||||||
|  |  | ||||||
|  | //arduinomorse | ||||||
|  | //LEDMorseSender sender(LED_BUILTIN); | ||||||
|  |  | ||||||
|  | //Etherkit Morse | ||||||
|  | //Morse morse(LED_BUILTIN, 15); | ||||||
|  |  | ||||||
|  | //jled from https://github.com/jandelgado/jled/blob/master/examples/morse/morse_effect.h | ||||||
|  | class MorseEffect : public jled::BrightnessEvaluator { | ||||||
|  |     Morse morse_; | ||||||
|  |     // duration of a single 'dit' in ms | ||||||
|  |     const uint16_t speed_; | ||||||
|  |  | ||||||
|  |  public: | ||||||
|  |     explicit MorseEffect(const char* message, uint16_t speed = 200) | ||||||
|  |         : morse_(message), speed_(speed) {} | ||||||
|  |  | ||||||
|  |     uint8_t Eval(uint32_t t) const override { | ||||||
|  |         const auto pos = t / speed_; | ||||||
|  |         if (pos >= morse_.size()) return 0; | ||||||
|  |         return morse_.test(pos) ? 255 : 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     uint16_t Period() const override { return (morse_.size() + 1) * speed_; } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // Speed is milliseconds per dit, which is 1000 * (60 / (50 * WPM)) | ||||||
|  | // 60 is 20 wpm, 120 is 10 wpm, 90 is 15 wpm, etc. | ||||||
|  | // https://morsecode.world/international/timing.html | ||||||
|  | MorseEffect morseEffect("CQ CQ CQ DE W1CDN", 120); | ||||||
|  | auto morseLed = | ||||||
|  |     JLed(output26).UserFunc(&morseEffect).DelayAfter(2000).Forever(); | ||||||
|  |  | ||||||
| //================================================================================ | //================================================================================ | ||||||
| // setup(): stuff that only gets done once, after power up (KB1OIQ's description) | // setup(): stuff that only gets done once, after power up (KB1OIQ's description) | ||||||
| @ -293,7 +327,16 @@ void setup() { | |||||||
|   server.onNotFound(notFound); |   server.onNotFound(notFound); | ||||||
|   server.begin(); |   server.begin(); | ||||||
|  |  | ||||||
|   telegraph.send("CQ CQ CQ"); |   //telegraph | ||||||
|  |   //telegraph.send("CQ CQ CQ"); | ||||||
|  |   //telegraph26.send("CQ CQ CQ DE W1CDN K"); | ||||||
|  |  | ||||||
|  |   // arduinomorse | ||||||
|  |   // sender.setup(); | ||||||
|  | 	// sender.setMessage(String("73 de kb3jcy ")); | ||||||
|  | 	// sender.startSending(); | ||||||
|  |  | ||||||
|  |    | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -302,11 +345,31 @@ void loop() { | |||||||
|   time_until_start.tick(); |   time_until_start.tick(); | ||||||
|   timer.tick(); |   timer.tick(); | ||||||
|  |  | ||||||
|  |   //arduinomorse | ||||||
|  |   //sender.continueSending(); | ||||||
|  |  | ||||||
|   String yourInputString = readFile(SPIFFS, "/inputString.txt"); |   String yourInputString = readFile(SPIFFS, "/inputString.txt"); | ||||||
|   int yourInputInt = readFile(SPIFFS, "/inputInt.txt").toInt(); |   int yourInputInt = readFile(SPIFFS, "/inputInt.txt").toInt(); | ||||||
|   // float yourInputFloat = readFile(SPIFFS, "/inputFloat.txt").toFloat(); |   // float yourInputFloat = readFile(SPIFFS, "/inputFloat.txt").toFloat(); | ||||||
|  |  | ||||||
|  |   // if you want to send code, and it's not sending, then start it up | ||||||
|  |   if(yourInputInt != 0 & morseLed.IsRunning() == false){ | ||||||
|  |     //jled | ||||||
|  |     morseLed.Reset().Update(); | ||||||
|  |     //morse.send("CQ CQ CQ DE W1CDN K"); //etherkit morse | ||||||
|  |     //telegraph26.send("CQ CQ CQ DE W1CDN K"); //telegraph | ||||||
|  |      | ||||||
|  |   // if you want to send code, and it is sending, keep sending | ||||||
|  |   } else if(yourInputInt != 0 & morseLed.IsRunning() == true){ | ||||||
|  |     morseLed.Update(); | ||||||
|  |   // if you don't want to send code | ||||||
|  |   } else { | ||||||
|  |     // stop sending and make sure the pin is off | ||||||
|  |     morseLed.Stop(JLed::eStopMode::FULL_OFF).Update(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |    | ||||||
|  |    | ||||||
|   // Blink LED according to seconds entered |   // Blink LED according to seconds entered | ||||||
|   // if (yourInputInt > 0) { |   // if (yourInputInt > 0) { | ||||||
|   //     Serial.println("GPIO 26 on"); |   //     Serial.println("GPIO 26 on"); | ||||||
|  | |||||||
							
								
								
									
										121
									
								
								vulpes/src/morse.h
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										121
									
								
								vulpes/src/morse.h
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,121 @@ | |||||||
|  | // Copyright (c) 2019 Jan Delgado <jdelgado[at]gmx.net> | ||||||
|  | // https://github.com/jandelgado/jled | ||||||
|  | #include <Arduino.h> | ||||||
|  | #include <inttypes.h> | ||||||
|  | #include <stddef.h> | ||||||
|  | #include "bitset.h"  // NOLINT | ||||||
|  |  | ||||||
|  | #ifndef EXAMPLES_MORSE_MORSE_H_ | ||||||
|  | #define EXAMPLES_MORSE_MORSE_H_ | ||||||
|  |  | ||||||
|  | // The Morse class converts a text sequence into a bit sequence representing | ||||||
|  | // a morse code sequence. | ||||||
|  | class Morse { | ||||||
|  |     // pre-ordered tree of morse codes. Bit 1 = 'dah',  0 = 'dit'. | ||||||
|  |     // Position in string corresponds to position in binary tree starting w/ 1 | ||||||
|  |     // see https://www.pocketmagic.net/morse-encoder/ for info on encoding | ||||||
|  |     static constexpr auto LATIN = | ||||||
|  |         "*ETIANMSURWDKGOHVF*L*PJBXCYZQ**54*3***2*******16*******7***8*90"; | ||||||
|  |  | ||||||
|  |     static constexpr auto DURATION_DIT = 1; | ||||||
|  |     static constexpr auto DURATION_DAH = 3 * DURATION_DIT; | ||||||
|  |     static constexpr auto DURATION_PAUSE_CHAR = DURATION_DAH; | ||||||
|  |     static constexpr auto DURATION_PAUSE_WORD = 7 * DURATION_DIT; | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |     char upper(char c) const { return c >= 'a' && c <= 'z' ? c - 32 : c; } | ||||||
|  |     bool isspace(char c) const { return c == ' '; } | ||||||
|  |  | ||||||
|  |     // returns position of char in morse tree. Count starts with 1, i.e. | ||||||
|  |     // E=2, T=3, etc. | ||||||
|  |     size_t treepos(char c) const { | ||||||
|  |         auto i = 1u; | ||||||
|  |         while (LATIN[i++] != c) { | ||||||
|  |         } | ||||||
|  |         return i; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // returns uint16_t with size of morse sequence (dit's and dah's) in MSB | ||||||
|  |     // and the morse sequence in the LSB | ||||||
|  |     uint16_t pos_to_morse_code(int code) const { | ||||||
|  |         uint8_t res = 0; | ||||||
|  |         uint8_t size = 0; | ||||||
|  |         while (code > 1) { | ||||||
|  |             size++; | ||||||
|  |             res <<= 1; | ||||||
|  |             res |= (code & 1); | ||||||
|  |             code >>= 1; | ||||||
|  |         } | ||||||
|  |         return res | (size << 8); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     template <typename F> | ||||||
|  |     uint16_t iterate_sequence(const char* p, F f) const { | ||||||
|  |         // call f(count,val) num times, incrementing count each time | ||||||
|  |         // and returning num afterwards. | ||||||
|  |         auto set = [](int num, int count, bool val, F f) -> int { | ||||||
|  |             for (auto i = 0; i < num; i++) f(count + i, val); | ||||||
|  |             return num; | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         auto bitcount = 0; | ||||||
|  |         while (*p) { | ||||||
|  |             const auto c = upper(*p++); | ||||||
|  |             if (isspace(c)) {  // space not part of alphabet, treat separately | ||||||
|  |                 bitcount += set(DURATION_PAUSE_WORD, bitcount, false, f); | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             const auto morse_code = pos_to_morse_code(treepos(upper(c))); | ||||||
|  |             auto code = morse_code & 0xff;  // dits (0) and dahs (1) | ||||||
|  |             auto size = morse_code >> 8;    // number of dits and dahs in code | ||||||
|  |             while (size--) { | ||||||
|  |                 bitcount += set((code & 1) ? DURATION_DAH : DURATION_DIT, | ||||||
|  |                                 bitcount, true, f); | ||||||
|  |  | ||||||
|  |                 // pause between symbols := 1 dit | ||||||
|  |                 if (size) { | ||||||
|  |                     bitcount += set(DURATION_DIT, bitcount, false, f); | ||||||
|  |                 } | ||||||
|  |                 code >>= 1; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (*p && !isspace(*p)) { | ||||||
|  |                 bitcount += set(DURATION_PAUSE_CHAR, bitcount, false, f); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return bitcount; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  public: | ||||||
|  |     // returns ith bit of morse sequence | ||||||
|  |     bool test(uint16_t i) const { return bits_->test(i); } | ||||||
|  |  | ||||||
|  |     // length of complete morse sequence in in bits | ||||||
|  |     size_t size() const { return bits_->size(); } | ||||||
|  |  | ||||||
|  |     Morse() : bits_(new Bitset(0)) {} | ||||||
|  |  | ||||||
|  |     explicit Morse(const char* s) { | ||||||
|  |         const auto length = iterate_sequence(s, [](int, bool) -> void {}); | ||||||
|  |         auto bits = new Bitset(length); | ||||||
|  |         iterate_sequence(s, [bits](int i, bool v) -> void { bits->set(i, v); }); | ||||||
|  |         bits_ = bits; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ~Morse() { delete bits_; } | ||||||
|  |  | ||||||
|  |     // make sure that the following, currently not needed, methods are not used | ||||||
|  |     Morse(const Morse&m) {*this = m;} | ||||||
|  |     Morse& operator=(const Morse&m) { | ||||||
|  |         delete bits_; | ||||||
|  |         bits_ = new Bitset(*m.bits_); | ||||||
|  |         return *this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  private: | ||||||
|  |     // stores morse bit sequence | ||||||
|  |     const Bitset* bits_ = nullptr; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif  // EXAMPLES_MORSE_MORSE_H_ | ||||||
		Reference in New Issue
	
	Block a user