heyyy....
i created arduino library for morse code encoding for light and audio like 7 months ago.
and i want some help to make it use bit packed mode to save memory and optimized it. if you can contribute, here is the link.
is this what you want to represent with a more compact binary encoding ?
const char* const morseCodes[36] PROGMEM = {
".-", // A
"-...", // B
"-.-.", // C
"-..", // D
".", // E
"..-.", // F
"--.", // G
"....", // H
"..", // I
".---", // J
"-.-", // K
".-..", // L
"--", // M
"-.", // N
"---", // O
".--.", // P
"--.-", // Q
".-.", // R
"...", // S
"-", // T
"..-", // U
"...-", // V
".--", // W
"-..-", // X
"-.--", // Y
"--..", // Z
"-----", // 0
".----", // 1
"..---", // 2
"...--", // 3
"....-", // 4
".....", // 5
"-....", // 6
"--...", // 7
"---..", // 8
"----." // 9
};
const char* const morseSpecialChars[17] PROGMEM = {
".-.-.-", // .
"--..--", // ,
"---...", // :
"-.-.-.", // ;
"..--..", // ?
"-..-.", // =
"-..-.", // /
"-.-.--", // !
"-....-", // -
"..--.-", // _
".-..-.", // "
"-.--.", // (
"-.--.-", // )
"...-..-", // $
".--.-.", // @
".-...", // &
".-.-." // +
};
as you are using PROGMEM, you don't use up RAM for that. Do you feel flash memory is a concern?
yes that what I wanna represent in binary coding
yeahhh... i mean library is working fine. and its not taking huge space but. i think if we use binary representation I think its going to be more optimized right..
you have codes with 6 signs and some with only 1 sign, so you would need to encode the length and you need 3 bits for coding 6.
You need up to 6 bits to code the longest sequence
==> that means the coding will be on 9 bits minimum so it has to be 2 bytes (unless you want complicated access) which means you have 7 bits extra which could be used to store the ASCII representation of your symbol.
struct __attribute__((packed, aligned(1))) MorseCode {
uint16_t length: 3;
uint16_t morseCode: 6;
uint16_t asciiCode: 7;
};
You can define a morse character as a single 8 bit byte.
Bits 0 to 4 when not set are a dot, when set are a dash.
Bits 5,6,7 contain the number of bits to send.
he has special characters for extended morse code with up to 6 dah/di like
but may be he could say that if the two most significant bits of the length are set (so 6) then it's coded on 6 bits and bit 5 is not part of the length but it's part of the code... and so it would still fit on one byte
so
".-.-.-"
would be coded 11
for the length and 010101
➜ 0b11010101
Have you had complaints or requests to reduce the space taken by the library? There is such a thing as Premature Optimisation.
Another option, add a 1 bit to the end of the morse sequence. Then when the current bit is a 1, and the remainder of the byte is 0's (or you are on the last bit of the byte), that would indicate the character is complete.
I did not see that the $ sign had 7 signs...
{"...-..-", '$'},
so that makes the coding on one byte more complicated
I also noticed an error in the original codes '=' and '/' have the same morse representation
I also noted you define the progmem in the .h. This has no business in the .h, it should be in the .cpp and possibly declared as extern if you plan to export access to those to the main program. I you include your .h in multiple files for a larger project you'll get an error as it stands.
You could stay with the current string representation but compress it.
"--" becomes "="
".." becomes ":"
".-" becomes "i"
"-." becomes "!"
".-." becomes "%"
etc...
That is storing an array of char* in PROGMEM, the actual char arrays are being stored in RAM.
well
struct __attribute__((packed, aligned(1))) MorseCode {
uint8_t length;
uint8_t morseCode; // 0 for dot, 1 for dash starting at LSb
char asciiCode;
};
will give you a constant 3 bytes per character, so will occupy less flash memory than your current representation and is easy to access and can be used for encoding or decoding as you have the symbol too.
I got everything down to 2 characters except the digits and special characters, none of which are more than 3.
const char* const morseCodes[36] PROGMEM = {
"i", // A
"!:", // B
"!!", // C
"-:", // D
".", // E
":!", // F
"=.", // G
"::", // H
":", // I
"i=", // J
"!-", // K
"i:", // L
"=", // M
"-.", // N
"=-", // O
"i!", // P
"=i", // Q
"i.", // R
":.", // S
"-", // T
":-", // U
":i", // V
".=", // W
"!i", // X
"!=", // Y
"=:", // Z
"==", // 0
".==", // 1
":-=", // 2
":.=", // 3
"::-", // 4
"::.", // 5
"-::", // 6
"=.:", // 7
"=-:", // 8
"==." // 9
};
const char* const morseSpecialChars[17] PROGMEM = {
"iii", // .
"=:=", // ,
"=!:", // :
"!!!", // ;
":=:", // ?
"!%", // =
"!%", // / umm... error here
"!!=", // !
"!:i", // -
":=i", // _
"i:!", // "
"!=.", // (
"!=i", // )
":%i", // $
".=%", // @
"%:", // &
"i%" // +
};
Maybe go to fixed length char arrays (padded with space when needed) so that null terminators are not needed.
@ktauchathuranga does your print function block?
I did a Morse sender that was FSM based, hand it a string and keep calling the object's service method from your loop(), attend to other things that may also be happening.
TBH it was quite ugly, but did function cooperatively.
If I live long enough, I'll get to it on my list of things to make prettier.
a7
At that point, it makes more sense to use a two-dimensional char array instead of an array of char* to the individual char arrays. With the longest char array having three characters plus a terminating null, a 36 x 4 array takes 144 bytes, while the char* array alone takes 72 bytes. Eliminating the terminating null would reduce the size to 36 x 3 = 108 bytes.
Also, note my previous comment, the code you posted does not store the actual char arrays in PROGMEM, only the array of char*. Each of the individual char arrays need to be stored in PROGMEM, then the array of char* is created from those.
Here is an example of compressing the morse code down into a single byte.
Starting with the MSB, a 0 represents a dot, 1 represents a dash, and the final 1 indicates the end of the morse code. This should work with any code up to 7 dots/dashes.
struct _morseCode {
const uint8_t code;
const char chr;
};
const _morseCode morseCodes[53] PROGMEM = {
{0b01100000, 'A'},
{0b10001000, 'B'},
{0b10101000, 'C'},
{0b10010000, 'D'},
{0b01000000, 'E'},
{0b00101000, 'F'},
{0b11010000, 'G'},
{0b00001000, 'H'},
{0b00100000, 'I'},
{0b01111000, 'J'},
{0b10110000, 'K'},
{0b01001000, 'L'},
{0b11100000, 'M'},
{0b10100000, 'N'},
{0b11110000, 'O'},
{0b01101000, 'P'},
{0b11011000, 'Q'},
{0b01010000, 'R'},
{0b00010000, 'S'},
{0b11000000, 'T'},
{0b00110000, 'U'},
{0b00011000, 'V'},
{0b01110000, 'W'},
{0b10011000, 'X'},
{0b10111000, 'Y'},
{0b11001000, 'Z'},
{0b11111100, '0'},
{0b01111100, '1'},
{0b00111100, '2'},
{0b00011100, '3'},
{0b00001100, '4'},
{0b00000100, '5'},
{0b10000100, '6'},
{0b11000100, '7'},
{0b11100100, '8'},
{0b11110100, '9'},
{0b01010110, '.'},
{0b11001110, ','},
{0b11100010, ':'},
{0b10101010, ';'},
{0b00110010, '?'},
{0b10010100, '='},
{0b10010100, '/'},
{0b10101110, '!'},
{0b10000110, '-'},
{0b00110110, '_'},
{0b01001010, '"'},
{0b10110100, '('},
{0b10110110, ')'},
{0b00010011, '$'},
{0b01101010, '@'},
{0b01000100, '&'},
{0b01010100, '+'},
};
void setup() {
Serial.begin(9600);
Serial.println(F("\nstartup"));
const char text[] = "HELLOWORLD24+$";
const char* txt = text;
while (*txt != '\0') {
//iterate through each character in the text string
for (size_t i = 0; i < sizeof(morseCodes) / sizeof(morseCodes[0]); i++) {
//search the morseCodes table for the text character
const _morseCode* ptr = &(morseCodes[i]);
if ( (char)pgm_read_byte(&ptr->chr) == *txt) {
Serial.print(*txt);
Serial.print('\t');
Serial.print((char)pgm_read_byte(&ptr->chr));
Serial.print('\t');
uint8_t mc = pgm_read_byte(&ptr->code);
do {
//print out the dots and dashes
if ( (mc & 0b10000000) == 0) {
Serial.print('.');
} else {
Serial.print('-');
}
mc = mc << 1;
} while (mc != 0b10000000); //final 1 in byte signifies end of morse code
Serial.println();
}
}
txt++;
}
Serial.println(F("end of code"));
}
void loop() {
}
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.