Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Convert to header/implementation, for use as an Arduino library.

  • Loading branch information...
commit 362203a096772f10d8e3a8c75d36640b0c47967b 1 parent d65dddd
@markfickett authored
Showing with 298 additions and 253 deletions.
  1. +144 −0 morse.cpp
  2. +154 −0 morse.h
  3. +0 −253 morse.pde
View
144 morse.cpp
@@ -0,0 +1,144 @@
+// Morse Code sending library
+
+#include <morse.h>
+
+
+// MorseSender
+unsigned int MorseSender::fillTimings(char c)
+{
+ int t = 0;
+ unsigned int start = 0;
+ if (c >= 'a' && c <= 'z')
+ {
+ const morseTiming_t *letterTimings = MORSE[c-'a'];
+ while(letterTimings[t] != END)
+ {
+ timingBuffer[2*t] = letterTimings[t];
+ timingBuffer[2*t + 1] = DIT;
+ t++;
+ }
+ }
+ else if (c >= '0' && c <= '9')
+ {
+ int n = c - '0';
+ boolean ditsFirst = (n <= 5);
+ if (!ditsFirst)
+ {
+ n -= 5;
+ }
+ while(t < 5)
+ {
+ timingBuffer[2*t] = ((t < n) == ditsFirst) ? DIT : DAH;
+ timingBuffer[2*t + 1] = DIT;
+ t++;
+ }
+ }
+ else
+ {
+ start = t = 1; // start on a space
+ }
+
+ timingBuffer[2*t - 1] = DAH;
+ timingBuffer[2*t] = END;
+
+ //Serial.print("Refilled timing buffer for '");
+ //Serial.print(c);
+ //Serial.print("': ");
+ int i = start;
+ while(timingBuffer[i] != END)
+ {
+ //Serial.print((int)timingBuffer[i]);
+ //Serial.print(", ");
+ i++;
+ }
+ //Serial.println("END");
+
+ return start;
+}
+
+// see note in header about pure-virtual-ness
+void MorseSender::setOn() {};
+void MorseSender::setOff() {};
+
+MorseSender::MorseSender(unsigned int outputPin): pin(outputPin) {}
+
+void MorseSender::setup() { pinMode(pin, OUTPUT); }
+
+void MorseSender::setMessage(const String newMessage)
+{
+ message = newMessage;
+
+ // Force startSending() before continueSending().
+ messageIndex = message.length();
+}
+
+void MorseSender::sendBlocking()
+{
+ //Serial.println("Sending blocking: ");
+ //Serial.println(message);
+ startSending();
+ while(continueSending());
+}
+
+void MorseSender::startSending()
+{
+ messageIndex = 0;
+ if (message.length() == 0) { return; }
+ timingIndex = fillTimings(message[0]);
+ setOn();
+ lastChangedMillis = millis();
+ //Serial.print("Starting with (on) ");
+ //Serial.println((int)timingBuffer[timingIndex]);
+}
+
+boolean MorseSender::continueSending()
+{
+ if(messageIndex >= message.length()) { return false; }
+
+ unsigned long elapsedMillis = millis() - lastChangedMillis;
+ if (elapsedMillis < timingBuffer[timingIndex]) { return true; }
+
+ timingIndex++;
+ if (timingBuffer[timingIndex] == END)
+ {
+ messageIndex++;
+ if(messageIndex >= message.length()) {
+ setOff();
+ return false;
+ }
+ timingIndex = fillTimings(message[messageIndex]);
+ }
+
+ lastChangedMillis += elapsedMillis;
+ //Serial.print("Next is ");
+ if (timingIndex % 2 == 0) {
+ //Serial.print("(on) ");
+ setOn();
+ } else {
+ //Serial.print("(off) ");
+ setOff();
+ }
+ //Serial.println((int)timingBuffer[timingIndex]);
+
+ return true;
+}
+
+void *MorseSender::operator new(size_t size) { return malloc(size); }
+void MorseSender::operator delete(void* ptr) { if (ptr) free(ptr); }
+
+
+// SpeakerMorseSender
+
+void SpeakerMorseSender::setOn() { tone(pin, frequency); }
+void SpeakerMorseSender::setOff() { noTone(pin); }
+SpeakerMorseSender::SpeakerMorseSender(
+ int outputPin, unsigned int toneFrequency)
+: MorseSender(outputPin), frequency(toneFrequency) {};
+
+
+// LEDMorseSender
+
+void LEDMorseSender::setOn() { digitalWrite(pin, HIGH); }
+void LEDMorseSender::setOff() { digitalWrite(pin, LOW); }
+LEDMorseSender::LEDMorseSender(int outputPin) : MorseSender(outputPin) {};
+
View
154 morse.h
@@ -0,0 +1,154 @@
+#pragma once
+/**
+ * Generate and send Morse Code on an LED or a speaker. Allow sending
+ * in a non-blocking manner (by calling a 'continue sending' method
+ * every so often to turn an LED on/off, or to call tone/noTone appropriately).
+ */
+
+// for malloc and free, for the new/delete operators
+#include <stdlib.h>
+
+// Arduino language types
+#include "WProgram.h"
+
+// define lengths
+typedef int morseTiming_t;
+#define UNIT 100
+#define DIT UNIT
+#define DAH 3*UNIT
+
+// sentinel
+#define END 0
+
+// the most timing numbers any unit will need; ex: k = on,off,on,off,on,end = 5
+#define MAX_TIMINGS 10
+
+// Morse Code (explicit declaration of letter timings)
+const morseTiming_t MORSE[26][5] = {
+ /* a */ {DIT, DAH, END},
+ /* b */ {DAH, DIT, DIT, DIT, END},
+ /* c */ {DAH, DIT, DAH, DIT, END},
+ /* d */ {DAH, DIT, DIT, END},
+ /* e */ {DIT, END},
+ /* f */ {DIT, DIT, DAH, DIT, END},
+ /* g */ {DAH, DAH, DIT, END},
+ /* h */ {DIT, DIT, DIT, DIT, END},
+ /* i */ {DIT, DIT, END},
+ /* j */ {DIT, DAH, DAH, DAH, END},
+ /* k */ {DAH, DIT, DAH, END},
+ /* l */ {DIT, DAH, DIT, DIT, END},
+ /* m */ {DAH, DAH, END},
+ /* n */ {DAH, DIT, END},
+ /* o */ {DAH, DAH, DAH, END},
+ /* p */ {DIT, DAH, DAH, DIT, END},
+ /* q */ {DAH, DAH, DIT, DAH, END},
+ /* r */ {DIT, DAH, DIT, END},
+ /* s */ {DIT, DIT, DIT, END},
+ /* t */ {DAH, END},
+ /* u */ {DIT, DIT, DAH, END},
+ /* v */ {DIT, DIT, DIT, DAH},
+ /* w */ {DIT, DAH, DAH, END},
+ /* x */ {DAH, DIT, DIT, DAH, END},
+ /* y */ {DAH, DIT, DAH, DAH, END},
+ /* z */ {DAH, DAH, DIT, DIT, END},
+};
+
+
+/**
+ * Define the logic of converting characters to on/off timing,
+ * and encapsulate the state of one sending-in-progress Morse message.
+ *
+ * Subclasses define setOn and setOff for (for example) LED and speaker output.
+ */
+class MorseSender {
+protected:
+ const unsigned int pin;
+ // These would be pure virtual, but that has compiler issues.
+ // See: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1167672075 .
+ virtual void setOn();
+ virtual void setOff();
+
+private:
+ String message;
+
+ // on,off,...,wait,0 list, millis
+ morseTiming_t timingBuffer[MAX_TIMINGS+1];
+
+ // index of the character currently being sent
+ unsigned int messageIndex;
+ // timing unit currently being sent
+ unsigned int timingIndex;
+
+ // when this timing unit was started
+ unsigned long lastChangedMillis;
+
+ /**
+ * Fill a buffer with on,off,..,END timings (millis)
+ * @return the index at which to start within the new timing sequence
+ */
+ unsigned int fillTimings(char c);
+
+public:
+ /**
+ * Create a sender which will output to the given pin.
+ */
+ MorseSender(unsigned int outputPin);
+
+ /**
+ * To be called during the Arduino setup(); set the pin as OUTPUT.
+ */
+ void setup();
+
+ /**
+ * Set the message to be sent.
+ * This halts any sending in progress.
+ */
+ void setMessage(const String newMessage);
+
+ /**
+ * Send the entirety of the current message before returning.
+ */
+ void sendBlocking();
+
+ /**
+ * Prepare to send and begin sending the current message.
+ */
+ void startSending();
+
+ /**
+ * Switch outputs on and off (and refill the internal timing buffer)
+ * as necessary to continue with the sending of the current message.
+ * This should be called every few milliseconds (at a significantly
+ * smaller interval than UNIT) to produce a legible fist.
+ *
+ * @see startSending, which must be called first
+ * @return false if sending is complete, otherwise true (keep sending)
+ */
+ boolean continueSending();
+
+ void *operator new(size_t size);
+ void operator delete(void* ptr);
+};
+
+
+class SpeakerMorseSender: public MorseSender {
+ private:
+ unsigned int frequency;
+ protected:
+ virtual void setOn();
+ virtual void setOff();
+ public:
+ // concert A = 440
+ // middle C = 261.626; higher octaves = 523.251, 1046.502
+ SpeakerMorseSender(int outputPin, unsigned int toneFrequency=1046);
+};
+
+
+class LEDMorseSender: public MorseSender {
+ protected:
+ virtual void setOn();
+ virtual void setOff();
+ public:
+ LEDMorseSender(int outputPin);
+};
+
View
253 morse.pde
@@ -1,253 +0,0 @@
-/**
- * Generate and send Morse Code on an LED or a speaker. Allow sending
- * in a non-blocking manner (by calling a 'continue sending' method every so often
- * to turn an LED on/off, or to call tone/noTone appropriately).
- *
- * Example:
- LEDMorseSender cqSender(13);
- void setup() {
- cqSender.setup();
- cqSender.setMessage(String("cq de kb3jcy "));
- }
- void loop() {
- // check sensors, do some other work
- if (!cqSender.continueSending()) // returns false initially or when done
- {
- cqSender.startSending(); // start the first time; restart after finishing
- }
- }
- */
-
-#include <stdlib.h>
-
-// define lengths
-typedef int morseTiming_t;
-#define UNIT 100
-#define DIT UNIT
-#define DAH 3*UNIT
-// sentinel
-#define END 0
-// the most timing numbers any unit will need; ex: k = on,off,on,off,on,end = 5
-#define MAX_TIMINGS 10
-
-// Morse Code (explicit declaration of letter timings)
-const morseTiming_t MORSE[26][5] = {
- /* a */ {DIT, DAH, END},
- /* b */ {DAH, DIT, DIT, DIT, END},
- /* c */ {DAH, DIT, DAH, DIT, END},
- /* d */ {DAH, DIT, DIT, END},
- /* e */ {DIT, END},
- /* f */ {DIT, DIT, DAH, DIT, END},
- /* g */ {DAH, DAH, DIT, END},
- /* h */ {DIT, DIT, DIT, DIT, END},
- /* i */ {DIT, DIT, END},
- /* j */ {DIT, DAH, DAH, DAH, END},
- /* k */ {DAH, DIT, DAH, END},
- /* l */ {DIT, DAH, DIT, DIT, END},
- /* m */ {DAH, DAH, END},
- /* n */ {DAH, DIT, END},
- /* o */ {DAH, DAH, DAH, END},
- /* p */ {DIT, DAH, DAH, DIT, END},
- /* q */ {DAH, DAH, DIT, DAH, END},
- /* r */ {DIT, DAH, DIT, END},
- /* s */ {DIT, DIT, DIT, END},
- /* t */ {DAH, END},
- /* u */ {DIT, DIT, DAH, END},
- /* v */ {DIT, DIT, DIT, DAH},
- /* w */ {DIT, DAH, DAH, END},
- /* x */ {DAH, DIT, DIT, DAH, END},
- /* y */ {DAH, DIT, DAH, DAH, END},
- /* z */ {DAH, DAH, DIT, DIT, END},
-};
-
-/**
- * Define the logic of converting characters to on/off timing,
- * and encapsulate the state of one sending-in-progress Morse message.
- *
- * Subclasses define setOn and setOff for (for example) LED and speaker output.
- */
-class MorseSender {
- private:
- String message;
- morseTiming_t timingBuffer[MAX_TIMINGS+1]; // on,off,...,wait,0 list, millis
- unsigned int messageIndex; // index of the character currently being sent
- unsigned int timingIndex; // timing unit currently being sent
- unsigned long lastChangedMillis; // when this timing unit was started
-
- /**
- * Fill a buffer with on,off,..,END timings (millis)
- * @return the index at which to start within the new timing sequence
- */
- unsigned int fillTimings(char c)
- {
- int t = 0;
- unsigned int start = 0;
- if (c >= 'a' && c <= 'z')
- {
- const morseTiming_t *letterTimings = MORSE[c-'a'];
- while(letterTimings[t] != END)
- {
- timingBuffer[2*t] = letterTimings[t];
- timingBuffer[2*t + 1] = DIT;
- t++;
- }
- }
- else if (c >= '0' && c <= '9')
- {
- int n = c - '0';
- boolean ditsFirst = (n <= 5);
- if (!ditsFirst)
- {
- n -= 5;
- }
- while(t < 5)
- {
- timingBuffer[2*t] = ((t < n) == ditsFirst) ? DIT : DAH;
- timingBuffer[2*t + 1] = DIT;
- t++;
- }
- }
- else
- {
- start = t = 1; // start on a space
- }
-
- timingBuffer[2*t - 1] = DAH;
- timingBuffer[2*t] = END;
-
- //Serial.print("Refilled timing buffer for '");
- //Serial.print(c);
- //Serial.print("': ");
- int i = start;
- while(timingBuffer[i] != END)
- {
- //Serial.print((int)timingBuffer[i]);
- //Serial.print(", ");
- i++;
- }
- //Serial.println("END");
-
- return start;
- }
-
- protected:
- const unsigned int pin;
- // These would be pure virtual, but that has compiler issues.
- // See: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1167672075 .
- virtual void setOn() {};
- virtual void setOff() {};
-
- public:
- /**
- * Create a sender which will output to the given pin.
- */
- MorseSender(unsigned int outputPin): pin(outputPin) {}
-
- /**
- * To be called during the Arduino setup(); set the pin as OUTPUT.
- */
- void setup() { pinMode(pin, OUTPUT); }
-
- /**
- * Set the message to be sent.
- * This halts any sending in progress.
- */
- void setMessage(const String newMessage)
- {
- message = newMessage;
-
- // Force startSending() before continueSending().
- messageIndex = message.length();
- }
-
- /**
- * Send the entirety of the current message before returning.
- */
- void sendBlocking()
- {
- //Serial.println("Sending blocking: ");
- //Serial.println(message);
- startSending();
- while(continueSending());
- }
-
- /**
- * Prepare to send and begin sending the current message.
- */
- void startSending()
- {
- messageIndex = 0;
- if (message.length() == 0) { return; }
- timingIndex = fillTimings(message[0]);
- setOn();
- lastChangedMillis = millis();
- //Serial.print("Starting with (on) ");
- //Serial.println((int)timingBuffer[timingIndex]);
- }
-
- /**
- * Switch outputs on and off (and refill the internal timing buffer)
- * as necessary to continue with the sending of the current message.
- * This should be called every few milliseconds (at a significantly smaller
- * interval than UNIT) to produce a legible fist.
- *
- * @see startSending, which must be called first
- * @return false if sending is complete, otherwise true (keep sending)
- */
- boolean continueSending()
- {
- if(messageIndex >= message.length()) { return false; }
-
- unsigned long elapsedMillis = millis() - lastChangedMillis;
- if (elapsedMillis < timingBuffer[timingIndex]) { return true; }
-
- timingIndex++;
- if (timingBuffer[timingIndex] == END)
- {
- messageIndex++;
- if(messageIndex >= message.length()) {
- setOff();
- return false;
- }
- timingIndex = fillTimings(message[messageIndex]);
- }
-
- lastChangedMillis += elapsedMillis;
- //Serial.print("Next is ");
- if (timingIndex % 2 == 0) {
- //Serial.print("(on) ");
- setOn();
- } else {
- //Serial.print("(off) ");
- setOff();
- }
- //Serial.println((int)timingBuffer[timingIndex]);
-
- return true;
- }
-
- void *operator new(size_t size) { return malloc(size); }
- void operator delete(void* ptr) { if (ptr) free(ptr); }
-};
-
-class SpeakerMorseSender: public MorseSender {
- private:
- unsigned int frequency;
- protected:
- virtual void setOn() { tone(pin, frequency); }
- virtual void setOff() { noTone(pin); }
- public:
- // concert A = 440
- // middle C = 261.626; higher octaves = 523.251, 1046.502
- SpeakerMorseSender(int outputPin, unsigned int toneFrequency=1046)
- : MorseSender(outputPin), frequency(toneFrequency) {};
-};
-
-class LEDMorseSender: public MorseSender {
- protected:
- virtual void setOn() { digitalWrite(pin, HIGH); }
- virtual void setOff() { digitalWrite(pin, LOW); }
- public:
- LEDMorseSender(int outputPin) : MorseSender(outputPin) {};
-};
-
Please sign in to comment.
Something went wrong with that request. Please try again.