Created
February 11, 2024 20:59
-
-
Save nikp123/c45f0e37f73bd5fa47e395da9ad34cbe to your computer and use it in GitHub Desktop.
Morse code on a ThinkPad sleep status LED
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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