/** About this program
Charmsec7-5c : This program is a demonstration program for an error correcting characterization
code based on the Charmsec CoDec library Rev. 1.9x, an example application of JP-A2021-202714.
This code is capable of correcting single-character errors. Charmsec is an error-correcting code
that uses the Chinese remainder theorem to encode information data into a set of characters -
especially ASCII characters.
http://www.finetune.co.jp/~lyuka/technote/charmsec/
*/
#include <stdint.h>
#include <inttypes.h>
/* Charmsec7 (9c, 44) */
#define NUM_COPRIME 9
#define DATA_LEN 44
#define NUM_SUBSET (NUM_COPRIME - 2)
#define CHARMS_LEN (NUM_COPRIME + 3)
typedef struct {
uint64_t status;
uint64_t data;
char code[CHARMS_LEN];
const int data_len;
const uint64_t data_mask;
const int charms_len; // Length of the code string encoded by Charmsec
const int num_coprime; // number of coprime numbers
const int num_subset; // number of subset of the coprime number set
const uint8_t ascii_mask;
const char cmap[93]; // charactor mapping table (92 characters + \0)
const uint8_t rmap[128]; // charactor reverse mapping table
const uint64_t coprime[NUM_COPRIME]; // coprimes
const uint64_t modmax[NUM_COPRIME]; // Maximum value of the modulus system
const uint64_t minmodmax;
const uint64_t invmat[NUM_COPRIME][NUM_COPRIME];// Mudulus invert of the modulus system
const uint64_t corrected; // decode result flag : corrected
const uint64_t detected; // decode result flag : detected
const uint64_t superdata; // decode result flag : super code
const char *title;
const char *version;
const char *copyright;
} charms_t;
int ischarms(char);
char *encode(uint64_t);
uint64_t decode(char *);
charms_t charms = {
0, //.status
0, //.data
{0, 0, 0, 0, 0, 0, 0, 0, 0}, //.code
DATA_LEN, //.data_len
~0UL >> (64 - DATA_LEN), //.data_mask
CHARMS_LEN, //.charms_len
NUM_COPRIME, //.num_coprime
NUM_SUBSET, //.num_subset
0x7f, //.ascii_mask
"!\"#$%&'()+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~",//.cmap
{ 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,\
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,\
127, 0, 1, 2, 3, 4, 5, 6, 7, 8, 127, 9, 10, 11, 12, 13,\
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,\
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,\
46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 127, 58, 59, 60,\
61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,\
77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 127},//.rmap
/* Charmsec7-5c */
{ 71, 73, 79, 83, 85, 87, 88, 89, 91}, //.coprime
{ 22116033697560, 27722915480040, 34558702858680, 31059087379320, 27317028658920, 25388767812408, 24221468142872, \
23395736274365, 22869989391795}, //.modmax
0x0000141d4a551718, //.minmodmax
{ { 9033309538440, 4544390485800, 3639347317320, 11457704204760, 9366790742496, 13981400613400, 14325158190465, 0, 0}, \
{ 0, 23545489859760, 12984150288120, 26720882390400, 14350685660256, 26129644475440, 27407882349585, 7475842376640, 0}, \
{ 0, 0, 9186490633320, 27480414321360, 33338983934256, 24230814648040, 1963562662425, 29122502409000, 12912042826320}, \
{ 15748269657120, 0, 0, 8232529184880, 8404223643816, 26418074322640, 4588274271945, 4187742118560, 25598148939000}, \
{ 1154240647560, 25071793426680, 0, 0, 5784782539536, 14443486417360, 19556509153545, 15039712407720, 900561384360}, \
{ 8224530418104, 21215271733656, 16068840387600, 0, 0, 16050370456120, 6058683227961, 20824494947256, 13112880078936}, \
{ 2388032070424, 8958625203528, 6438618113928, 6128323265064, 0, 0, 15688905501633, 14696171682192, 18365728591848}, \
{ 14498766141860, 16665455976260, 21026547790885, 3100639747205, 2477195605521, 0, 0, 15246659594530, 20567680241200}, \
{ 4509575373030, 15351088769835, 19975054025745, 15981438370170, 4843056577086, 20767001861515, 0, 0, 10052742589800}
}, //.invmat
/* decode status at bit 63..61 */
1ULL << 61, //.corrected
1ULL << 62, //.detected
1ULL << 63, //.superdata
"charmsec8_5c - a subset of the Charmsec CoDec library.",//.title
"Rev.1.97 (Aug. 25, 2024)", //.version
"(c) 2004 Takayuki HOSODA, Finetune co., ltd." //.copyright
};
int ischarms(char c) {
return charms.rmap[(int)c] == charms.ascii_mask ? 0 : charms.ascii_mask;
}
char * encode(uint64_t data) {
int i;
if (data >= charms.minmodmax) data = (charms.minmodmax - 1UL);
for (i = 0; i < charms.num_coprime; i++) {
charms.code[i] = charms.cmap[data % charms.coprime[i]];
}
charms.code[i] = '\0';
return charms.code;
}
/** decode() return value
no error : data, superdata
corrected : data, superdate | charms.corrected
detected : charms.detected
*/
uint64_t decode(char *code) {
int i, j;
uint8_t a[NUM_COPRIME];
uint64_t b[NUM_COPRIME];
uint64_t data = 0;
/* decompose code */
for (i = 0; i < charms.num_coprime; i++) {
a[i] = charms.rmap[(int)code[i] & charms.ascii_mask];
}
/* majority decision */
/* subdecode 0 to 2 */
for (i = 0; i < 3; i++) {
/* subdecode */
data = 0;
/* mul-add in uint64_t followed by remainder calculation */
for (j = 0; j < charms.num_coprime; j++) {
data = data + a[j] * charms.invmat[i][j];
}
data %= charms.modmax[i];
b[i] = data;
}
data = b[0];
charms.status = charms.detected;
if ((data == b[1]) && (data == b[2])) {
charms.status = 0;
} else {
/* subdecode 3 to charms.num_coprime */
for (i = 3; i < charms.num_coprime; i++) {
/* subdecode*/
data = 0;
/* mul-add in uint64_t followed by remainder calculation */
for (j = 0; j < charms.num_coprime; j++) {
data = data + a[j] * charms.invmat[i][j];
}
data %= charms.modmax[i];
b[i] = data;
}
data = b[0];
/* compare adjacent data to find correct data. */
if (data == b[charms.num_coprime - 1]) {
charms.status = charms.corrected;
} else {
for (i = 0; i < charms.num_coprime - 1; i++) {
if (b[i] == b[i + 1]) {
charms.status = charms.corrected;
data = b[i];
break;
}
}
}
}
if (data > charms.data_mask) charms.status |= charms.superdata;
return data;
}
#ifdef DEBUG
#include <stdio.h>
#ifndef PRIx64
#define PRIx64 "llx"// uint64_t
#endif
const char *myname = "Charmsec7_5c_demo";
int main() {
int i, j;
char rxcode[CHARMS_LEN];
char rxdisp[CHARMS_LEN];
uint64_t rxdata, data;
rxdata = 0UL;
for (i = 0; i < charms.charms_len; i++) rxcode[i] = rxdisp[i] = '\0';
printf("%s : %s %s\n", myname, charms.version, charms.copyright);
printf("%s : Using %s\n", myname, charms.title);
printf("%s : '\\' is to be used as the error position indicator here.\n", myname);
for (i = 0; i < charms.charms_len; i++) rxcode[i] = '\0';// initialize rxcode. Note that '\0' is not a Charmsec code charactor.
data = 0xbadcafebabe;// A test data of 44-bit unsigned integer.
printf("%s : txdata = 0x%015" PRIx64 " -> txcode = %s%s\n", myname, \
data, encode(data), data > charms.data_mask ? data < charms.minmodmax - 1UL ? " (super data)" : " (saturated)" : "");
for (j = 0; j < charms.num_coprime; j++) {
for (i = 0; i < charms.charms_len; i++) rxcode[i] = charms.code[i];
rxcode[j] = '\t';// insert single character error. Note that '\t' is not a Charmsec code character.
rxdata = decode(rxcode);
for (i = 0; i < charms.num_coprime; i++) rxdisp[i] = ischarms(rxcode[i]) ? rxcode[i] : '\\';
printf("%s : rxdata = 0x%015" PRIx64 " <- rxcode = %s%s - %s\n", myname, rxdata, rxdisp,
charms.status & charms.superdata ? " (superdata)" : "",
charms.status & charms.corrected ? "Corrected an error"
: charms.status & charms.detected ? "Unrecoverable error detected" : "No error");
}
data = charms.minmodmax - 1UL;// the maximum value for superdata
printf("%s : txdata = 0x%015" PRIx64 " -> txcode = %s%s\n", myname, \
data, encode(data), data > charms.data_mask ? data < charms.minmodmax - 1UL ? " (super data)" : " (saturated)" : "");
for (j = 0; j < charms.num_coprime; j++) {
for (i = 0; i < charms.charms_len; i++) rxcode[i] = charms.code[i];
rxcode[j] = '\t';// insert single character error. Note that '\t' is not a Charmsec code character.
rxdata = decode(rxcode);
for (i = 0; i < charms.num_coprime; i++) rxdisp[i] = ischarms(rxcode[i]) ? rxcode[i] : '\\';
printf("%s : rxdata = 0x%015" PRIx64 " <- rxcode = %s%s - %s\n", myname, rxdata, rxdisp,
charms.status & charms.superdata ? " (superdata)" : "",
charms.status & charms.corrected ? "Corrected an error"
: charms.status & charms.detected ? "Unrecoverable error detected" : "No error");
}
return 0;
}
#endif