#define HIBIT_MASK B10000000
const char* mCodes[] = {
".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..",
".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.",
"...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..", "-----",
".----", "..---", "...--", "....-", ".....", "-....", "--...",
"---..", "----."
};
byte mCode[] = {
B01000010, B10000100, B10100100, B10000011, B00000001, B00100100,
B11000011, B00000100, B00000010, B01110100, B10100011, B01000100,
B11000010, B10000010, B11100011, B01100100, B11010100, B01000011,
B00000011, B10000001, B00100011, B00010100, B01100011, B10010100,
B10110100, B11000100, B11111101, B01111101, B00111101, B00011101,
B00001101, B00000101, B10000101, B11000101, B11100101, B11110101
};
void setup() {
Serial.begin(115200);
int x;
byte bc;
char code[6];
for (int i = 0; i < 36; i++) {
Serial.print(mCodes[i]);
Serial.print(" : ");
bc = mCode[i]; // take a copy of the byte so we can manipulate it
x = bc & ((1 << 3)-1); // set x to the value of the lower 3 bits
memset(&code[0], 0, 6); // clear out target char array
for(int j = 0; j < x; j++){
if((bc & HIBIT_MASK) == 0) // take care with the brackets
{
code[j] = '.';
} else {
code[j] = '-';
}
bc = bc << 1; // shift the code bits left
}
Serial.println(code); // ready for visual comparison
}
}
You may see a host of compiler warnings related to the mCode[] byte array. This is because the preferred format for a binary literal value is changing.
Binary literals should now be preceeded with 0b or 0B rather than just plain old B. The old format is still valid but the warning messages might prove a pain. It might therefore be time to switch and define the array as follows.
const byte mCode[] = { 0b01000010, 0b10000100, 0b10100100, 0b10000011, 0b00000001, 0b00100100, 0b11000011, 0b00000100, 0b00000010, 0b01110100, 0b10100011, 0b01000100, 0b11000010, 0b10000010, 0b11100011, 0b01100100, 0b11010100, 0b01000011, 0b00000011, 0b10000001, 0b00100011, 0b00010100, 0b01100011, 0b10010100, 0b10110100, 0b11000100, 0b11111101, 0b01111101, 0b00111101, 0b00011101, 0b00001101, 0b00000101, 0b10000101, 0b11000101, 0b11100101, 0b11110101 };
#define HIBIT_MASK B10000000
#define C6 1047
const int SOUNDER = 3; // set unused pin values to zero
const int LED_PIN = LED_BUILTIN;
const int DATA_PIN = 8;
enum CodePart {
dash, dot, space, letterSpace, wordSpace
};
const char text[] = "NOW IS THE TIME FOR ALL GOOD MEN TO COME TO OUR AID";
const byte mCode[] = {
B01000010, B10000100, B10100100, B10000011, B00000001, B00100100,
B11000011, B00000100, B00000010, B01110100, B10100011, B01000100,
B11000010, B10000010, B11100011, B01100100, B11010100, B01000011,
B00000011, B10000001, B00100011, B00010100, B01100011, B10010100,
B10110100, B11000100, B11111101, B01111101, B00111101, B00011101,
B00001101, B00000101, B10000101, B11000101, B11100101, B11110101
};
const int wordsPerMin = 10;
unsigned long timeUnit = 0;
void setup() {
Serial.begin(115200);
if(LED_PIN > 0) {
pinMode(LED_PIN, OUTPUT);
}
if(DATA_PIN > 0) {
pinMode(DATA_PIN, OUTPUT);
digitalWrite(DATA_PIN, HIGH);
}
timeUnit = 1200 / wordsPerMin; // set time unit in milliseconds
Serial.println(timeUnit);
encode();
}
void loop() {
}
void encode() {
byte code;
bool blank = false;
for(int ci = 0; ci < sizeof(text); ci++) {
switch (text[ci]) {
case 'A'...'Z':
code = mCode[text[ci] - 65];
break;
case '0'...'9':
code = mCode[26 + text[ci] - 48];
case ' ':
blank = true;
break;
}
if(blank) {
send(wordSpace);
blank = false;
} else {
int bc = code & ((1 << 3)-1);
for(int bi = 0; bi < bc; bi++) {
if(bi > 0) {send(space);}
if((code & HIBIT_MASK) == 0){
send(dot);
} else {
send(dash);
}
code = code << 1;
}
send(letterSpace);
}
}
}
void send(CodePart codePart) {
unsigned long startMillis = millis();
unsigned long elapsedMillis = timeUnit;
switch(codePart) {
case dash:
elapsedMillis *= 3; // note drop through to dot
case dot:
if(LED_PIN > 0) { digitalWrite(LED_PIN, HIGH);}
if(DATA_PIN > 0) {digitalWrite(DATA_PIN, LOW);}
if(SOUNDER > 0) {tone(SOUNDER, C6, elapsedMillis);}
break;
case letterSpace:
elapsedMillis *= 3;
break;
case wordSpace:
elapsedMillis *= 6;
break;
}
while(true) {
if((unsigned long)(millis() - startMillis) >= elapsedMillis) {
break;
}
}
if(LED_PIN > 0) {digitalWrite(LED_PIN, LOW);}
if(DATA_PIN > 0) {digitalWrite(DATA_PIN, HIGH);}
}
#include <util/atomic.h>
const int MORSE_PIN = 2; // External interrupt 0
struct SignalInt {
bool isCode = false;
unsigned long intTime = 0;
};
volatile int signalCount = -1;
int countCopy = 0;
SignalInt testSignals[60];
unsigned long lastMicros = micros();
void setup() {
Serial.begin(115200);
pinMode(MORSE_PIN, INPUT_PULLUP);
noInterrupts();
attachInterrupt(digitalPinToInterrupt(MORSE_PIN),morseInter,CHANGE);
interrupts();
}
void morseInter() {
unsigned long currentMicros = micros();
bool pinLow = (digitalRead(MORSE_PIN) == LOW);
if(signalCount == -1 && !pinLow) {return;}
if(signalCount >= 0) {
testSignals[signalCount].intTime =
(unsigned long)(currentMicros - lastMicros);
}
lastMicros = currentMicros;
signalCount++;
testSignals[signalCount].isCode = pinLow;
// pinLow flags a code element rather than an interval
}
void loop() {
ATOMIC_BLOCK(ATOMIC_RESTORESTATE){
countCopy = signalCount;
}
if(countCopy > 59) {
detachInterrupt(digitalPinToInterrupt(MORSE_PIN));
analyse();
signalCount = -1; // stop
}
}
void analyse() {
for(int i=0; i<60;i++) {
Serial.print(testSignals[i].isCode);
Serial.print(": ");
Serial.println(testSignals[i].intTime);
}
}
enum CodePart {
dot, dash, space, letterSpace, wordSpace
};
struct CodeTimes {
int minMillis;
int maxMillis;
};
CodeTimes codeTimes[] = {
{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}
};
void setDefaults() {
int dotTime = 1200 / WORD_RATE;
codeTimes[dot].minMillis = codeTimes[space].minMillis = dotTime - 2;
codeTimes[dot].maxMillis = codeTimes[space].maxMillis = dotTime + 2;
codeTimes[dash].minMillis = codeTimes[letterSpace].minMillis =
dotTime * 3 - 2;
codeTimes[dash].maxMillis = codeTimes[letterSpace].maxMillis =
dotTime * 3 + 2;
codeTimes[wordSpace].minMillis = dotTime * 6 - 2;
codeTimes[wordSpace].maxMillis = dotTime * 6 + 2;
}
void analyse() {
for(int i=0; i<60;i++) {
long millTime = testSignals[i].intTime / 1000;
if(testSignals[i].isCode) {
if(millTime >= codeTimes[dot].minMillis &&
millTime <= codeTimes[dot].maxMillis) {
Serial.println("dot");
}else if(millTime >= codeTimes[dash].minMillis &&
millTime <= codeTimes[dash].maxMillis) {
Serial.println("dash");
} else {
Serial.print("Unknown Signal: ");
Serial.println(millTime);
}
} else {
if(millTime >= codeTimes[letterSpace].minMillis &&
millTime <= codeTimes[letterSpace].maxMillis) {
Serial.println("End of letter");
} else if(millTime >= codeTimes[wordSpace].minMillis &&
millTime <= codeTimes[wordSpace].maxMillis) {
Serial.println("End of word");
}
}
}
}
void readBytes() {
int cCount = 0;
int bCount = 0;
byte wrk = B00000000;
unsigned long thisTime;
for(int i = 0; i < 60; i++) {
thisTime = testSignals[i].intTime / 1000;
if(testSignals[i].isCode) {
wrk = wrk << 1;
if(thisTime >= codeTimes[1].minMillis && thisTime <=
codeTimes[1].maxMillis) {
wrk ^= 1;
}
bCount++;
} else {
if(thisTime >= codeTimes[3].minMillis) {
wrk = wrk << (8 - bCount);
wrk ^= bCount;
bCount = 0;
readCodes[cCount] = wrk;
cCount++;
wrk = B00000000;
if(thisTime >= codeTimes[4].minMillis && thisTime <=
codeTimes[4].maxMillis) {
readCodes[cCount] = wrk;
cCount++;
}
}
}
}
}
void showCode() {
for(int i = 0; i < sizeof(readCodes); i++) {
if(readCodes[i] == B00000000) {
if(i > 0 and readCodes[i-1] == B00000000) {
break;
}
Serial.println(" ");
} else {
for(int j = 0; j < 26; j++) {
if(mCode[j] == readCodes[i]) {
Serial.print((char)(65 + j));
break;
}
}
}
}
}
struct SignalInt {
bool isCode = false;
unsigned long intTime = 0;
struct SignalInt* next;
};
struct SignalQueue {
struct SignalInt* head;
struct SignalInt* tail;
int count;
};
struct SignalQueue* signalQ = NULL;
volatile byte sStatus = 0; // signal status
struct SignalQueue* newQueue() {
struct SignalQueue* p = malloc(sizeof(*p));
p->head = p->tail = NULL;
p->count - 0;
return p;
}
bool queueAdd(const bool isCode, const long intTime) {
struct SignalInt* p = malloc(sizeof(*p));
if(p == NULL) {return false;}
p->isCode = isCode;
p->intTime = intTime;
p->next = NULL;
if(signalQ->head == NULL) {
//queue is empty so update both ends
signalQ->head = signalQ->tail = p;
} else {
signalQ->tail->next = p; // update the previous last item in Q
signalQ->tail = p; // update the Q tail
}
signalQ->count++; // increment the count of Q items
return true;
}
struct SignalInt* readFirst() {
return signalQ->head;
}
bool deQueue() {
if(signalQ->head == NULL) {return false;}
struct SignalInt* h = signalQ->head;
struct SignalInt* n = h->next;
free(h);
signalQ->head = n;
signalQ->count--;
return true;
}
void setupTimer() {
TCCR1A = 0; // Timer control register
TCCR1B = 0;
TCNT1 = 3036; // start value 65536 - (16Mhz / 256)
TCCR1B |= (1 << CS12); // 256 prescaler
TIMSK1 |= (1 << TOIE1); // set timer overflow interrupt
}
ISR(TIMER1_OVF_vect){
byte cStatus = sStatus;
switch (cStatus){
case 0:
TCNT1 = 3036; // not started yet so reset timer
break;
case 1:
sStatus = 2; // no items added to Q in last second
break;
}
}
void morseInter() {
static bool wasCode;
unsigned long currentMicros = micros();
bool pinLow = (digitalRead(MORSE_PIN) == LOW);
if(sStatus == 0 && !pinLow) {return;}
if(sStatus == 0) {
TCNT1 = 3036; // reset before status change
sStatus = 1; // signal started
} else {
if(queueAdd(wasCode, ((unsigned long)(currentMicros -
lastMicros)) / 1000)) {
TCNT1 = 3036; // reset timer
} else {
sStatus = 2; // error adding to Q so stop
}
}
lastMicros = currentMicros;
wasCode = pinLow;
}
void readBytes() {
int cCount = 0;
int bCount = 0;
byte wrk = B00000000;
while(signalQ->count) {
SignalInt* item = readFirst();
long t = item->intTime;
if(item->isCode) {
wrk = wrk << 1;
if(t >= codeTimes[dash].minMillis &&
t <= codeTimes[dash].maxMillis) {
wrk ^= 1;
}
bCount++;
} else {
if(t >= codeTimes[letterSpace].minMillis) {
wrk = wrk << (8 - bCount);
wrk ^= bCount;
bCount = 0;
readCodes[cCount] = wrk;
cCount++;
wrk = B00000000;
if(t >= codeTimes[wordSpace].minMillis &&
t <= codeTimes[wordSpace].maxMillis){
readCodes[cCount] = wrk;
cCount++;
}
}
}
deQueue();
}
}
void setup() {
Serial.begin(115200);
setDefaults();
signalQ = newQueue();
pinMode(MORSE_PIN, INPUT_PULLUP);
noInterrupts();
attachInterrupt(digitalPinToInterrupt(MORSE_PIN),morseInter,CHANGE);
setupTimer();
interrupts();
Serial.println("Ready");
}
void loop() {
if(sStatus == 2) {
detachInterrupt(digitalPinToInterrupt(MORSE_PIN));
sStatus = 0;
readBytes();
showCode();
}
}