Skip to content

Instantly share code, notes, and snippets.

@nikp123
Created February 11, 2024 20:59
Show Gist options
  • Save nikp123/c45f0e37f73bd5fa47e395da9ad34cbe to your computer and use it in GitHub Desktop.
Save nikp123/c45f0e37f73bd5fa47e395da9ad34cbe to your computer and use it in GitHub Desktop.
Morse code on a ThinkPad sleep status LED
/*
Original code by Matthew Herbst - Last updated 7/21/2013
ThinkPad adaptation by nikp123 - 28/12/2023
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
// Morse Code Timings - change as desired
const double MULTIPLIER = 2.5; //Increase durations of dots/dashes
const uint32_t DOT = (uint32_t) 92.3 * MULTIPLIER; //1 dot
const uint32_t DASH = (uint32_t) 276.9 * MULTIPLIER; //3 dots
const uint32_t TIMING_SPACE = (uint32_t) 92.3 * MULTIPLIER; //1 dot: space between dots/dashes
const uint32_t CHAR_SPACE = (uint32_t) 276.9 * MULTIPLIER; //3 dots: space between characters
const uint32_t WORD_SPACE = (uint32_t) 646.1; //7 dots - space between words
// Morse Code timings holder array setup
#define NUM_CHARS 96
#define MORSE_MAX_CHAR_SIZE 7
// Array placement is based on a character's ASCII value
// IF YOU ADD A NEW VALUE BE SURE TO ADD IT TO THE ACCEPTED CHAR ERROR CHECK
// Note: since there is no difference between lower/upper case in Morse,
// only upper is entered here - lower case is converted to upper using ASCII
static const uint32_t TIMINGS[NUM_CHARS][MORSE_MAX_CHAR_SIZE] = {
{0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0},
{DASH, DOT, DASH, DOT, DASH, DASH, 0}, //!
{DOT, DASH, DOT, DOT, DASH, DOT, 0}, //"
{0, 0, 0, 0, 0, 0, 0},
{DOT, DOT, DOT, DASH, DOT, DOT, DASH}, //$
{0, 0, 0, 0, 0, 0, 0},
{DOT, DASH, DOT, DOT, DOT, 0, 0}, //&
{DOT, DASH, DASH, DASH, DASH, DOT, 0}, //'
{DASH, DOT, DASH, DASH, DOT, 0, 0}, //(
{DASH, DOT, DASH, DASH, DOT, DASH, 0}, //)
{0, 0, 0, 0, 0, 0, 0},
{DOT, DASH, DOT, DASH, DOT, 0, 0}, //+
{DASH, DASH, DOT, DOT, DASH, DASH, 0}, //,
{DASH, DOT, DOT, DOT, DOT, DASH, 0}, //-
{DOT, DASH, DOT, DASH, DOT, DASH, 0}, //.
{DASH, DOT, DOT, DASH, DOT, 0, 0}, ///
{DASH, DASH, DASH, DASH, DASH, 0, 0}, //0
{DOT, DASH, DASH, DASH, DASH, 0, 0}, //1
{DOT, DOT, DASH, DASH, DASH, 0, 0}, //2
{DOT, DOT, DOT, DASH, DASH, 0, 0}, //3
{DOT, DOT, DOT, DOT, DASH, 0, 0}, //4
{DOT, DOT, DOT, DOT, DOT, 0, 0}, //5
{DASH, DOT, DOT, DOT, DOT, 0, 0}, //6
{DASH, DASH, DOT, DOT, DOT, 0, 0}, //7
{DASH, DASH, DASH, DOT, DOT, 0, 0}, //8
{DASH, DASH, DASH, DASH, DOT, 0, 0}, //9
{DASH, DASH, DASH, DOT, DOT, DOT, 0}, //:
{DASH, DOT, DASH, DOT, DASH, DOT, 0}, //;
{0, 0, 0, 0, 0, 0, 0},
{DASH, DOT, DOT, DOT, DASH, 0, 0}, //=
{0, 0, 0, 0, 0, 0, 0},
{DOT, DOT, DASH, DASH, DOT, DOT, 0}, //?
{DOT, DASH, DASH, DOT, DASH, DOT, 0}, //@
{DOT, DASH, 0, 0, 0, 0, 0}, //A
{DASH, DOT, DOT, DOT, 0, 0, 0}, //B
{DASH, DOT, DASH, DOT, 0, 0, 0}, //C
{DASH, DOT, DOT, 0, 0, 0, 0}, //D
{DOT, 0, 0, 0, 0, 0, 0}, //E
{DOT, DOT, DASH, DOT, 0, 0, 0}, //F
{DASH, DASH, DOT, 0, 0, 0, 0}, //G
{DOT, DOT, DOT, DOT, 0, 0, 0}, //H
{DOT, DOT, 0, 0, 0, 0, 0}, //I
{DOT, DASH, DASH, DASH, 0, 0, 0}, //J
{DASH, DOT, DASH, 0, 0, 0, 0}, //K
{DOT, DASH, DOT, DOT, 0, 0, 0}, //L
{DASH, DASH, 0, 0, 0, 0, 0}, //M
{DASH, DOT, 0, 0, 0, 0, 0}, //N
{DASH, DASH, DASH, 0, 0, 0, 0}, //O
{DOT, DASH, DASH, DOT, 0, 0, 0}, //P
{DASH, DASH, DOT, DASH, 0, 0, 0}, //Q
{DOT, DASH, DOT, 0, 0, 0, 0}, //R
{DOT, DOT, DOT, 0, 0, 0, 0}, //S
{DASH, 0, 0, 0, 0, 0, 0}, //T
{DOT, DOT, DASH, 0, 0, 0, 0}, //U
{DOT, DOT, DOT, DASH, 0, 0, 0}, //V
{DOT, DASH, DASH, 0, 0, 0, 0}, //W
{DASH, DOT, DOT, DASH, 0, 0, 0}, //X
{DASH, DOT, DASH, DASH, 0, 0, 0}, //Y
{DASH, DASH, DOT, DOT, 0, 0, 0}, //Z
{0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0},
{DOT, DOT, DASH, DASH, DOT, DASH, 0}, //_
};
void delay(uint32_t msec) {
usleep(msec * 1000);
}
void ledWrite(uint8_t val) {
FILE *fp = fopen("/sys/class/leds/tpacpi::lid_logo_dot/brightness", "ab");
if(fp == NULL) {
fprintf(stderr, "Failed to open ThinkPad LED diode :)\n");
return;
}
fprintf(fp, "%hhu", val);
fclose(fp);
}
// The loop routine runs in an infinite loop:
int main(int argc, char *argv[]) {
if(argc == 1) {
fprintf(stderr, "no message supplied. exiting...\n");
}
// Read the user input
const int messages = argc;
// Display the user input back to the user
fprintf(stderr, "Displaying:");
for(int i = 1; i < argc; i++) {
fprintf(stderr, " %s", argv[i]);
for(int j = 0; j < strlen(argv[i]); j++) {
// Get the ASCII value of the character being looked at
int ASCII = argv[i][j];
// Convert lower case letters to upper case
if(ASCII >= 97 && ASCII <= 122) {
ASCII = ASCII - 32;
}
// Ensure the character is one that has been programmed in for Morse
if((ASCII >= 32 && ASCII <= 34) || ASCII == 36 ||
(ASCII >= 38 && ASCII <= 41) || (ASCII >= 43 && ASCII <= 59) ||
ASCII == 61 || (ASCII >= 63 && ASCII <= 90) || ASCII == 95) {
// If the character is a space
if(ASCII == 32) {
delay(WORD_SPACE);
} else {
// Go through the timing sequence for each character
for(int k = 0; k < MORSE_MAX_CHAR_SIZE; ++k) {
// If the timing sequence is over, break the loop
if(TIMINGS[ASCII][k] == 0) {
break;
} else { // Display the timing sequence on the LED
ledWrite(1);
delay(TIMINGS[ASCII][k]);
ledWrite(0);
delay(TIMING_SPACE);
}
}
}
} else {
fprintf(stderr, "'%c' does not have a Morse Code timing. Skipping it.\n", argv[i][j]);
}
delay(CHAR_SPACE);
}
}
fprintf(stderr, "\n");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment