Page 166 and 167

#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 } }

Warnings about deprecated code

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
};
                    

Pages 170 to 172

#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);} }

Page 173

IDE image with Unicode characters

Pages 174 & 175

#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); } }

Page 176

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");      }     } } }

Page 178

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;         }      }     } } }

Page 179

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

Page 180

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; }

Page 181

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 }

Page 182

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; }

Page 183

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"); }

Page 184

void loop() { if(sStatus == 2) {     detachInterrupt(digitalPinToInterrupt(MORSE_PIN));     sStatus = 0;     readBytes();     showCode(); } }
Continue to more code from Chapter 12...