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

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...