将 ASCII 字符串转换为 7 位 GSM 编码方案
Convert ASCII String to 7-bit GSM coding scheme
我编写的一个简单例程,用于将 ASCII
字符串转换为相应的 7-bit GSM
编码方案:
#include <stdio.h>
#include <process.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
/* convert ascii input string to 7-bit GSM alphabet */
bool ascii_to_gsm(const char* in, uint8_t len, uint8_t* out, uint8_t start_indx) {
if (in == NULL || out == NULL || len == 0)
return false;
uint8_t nshift = 7;
memcpy(out + start_indx, in, len);
for (size_t i = 0; i < len - 1; i++) {
nshift = (nshift == 255) ? 7 : nshift;
uint16_t l = out[start_indx + i];
uint16_t h = out[start_indx + i + 1];
h = (h << nshift--) | l;
out[start_indx + i] = h;
out[start_indx + i + 1] = h >> 8;
}
return true;
}
int main() {
char data[] = "ASCIIASCII";
uint8_t buff[sizeof(data) - 1];
memset(buff, 0, sizeof(buff));
ascii_to_gsm(data, sizeof(buff), buff, 0);
for (size_t i = 0; i < sizeof(buff); i++) {
printf("\n buff[%d]=%02x", i, buff[i]);
}
system("pause");
return 0;
}
对于像 ASCII
或 TEST
这样的字符串,它工作正常,输出分别是 C1E9309904
和 D4E2940A
。
但是对于字符串 ASCIIASCII
一些输出字节是错误的:
C1E930990C4E87498024
结果应该是:C1E930990C4E87C924
不知道是什么部分,我错了。
可以找到有关 GSM 编码的概念 here。
我使用this在线编码器比较结果
But for string ASCIIASCII some output byte is wrong:
C1E930990C4E87498024
The result should be:
C1E930990C4E87C924
OP 的代码没有考虑到输出的长度可能比输入的长度短。
如果输入的是10个ASCII字符,就是70位。输出需要是 ceiling(70/8) 或 9 个字节。另见 .
缺少 start_indx
的简化参考代码。由于输入是 string ("converting ASCII string"),因此不需要输入长度。
bool ascii_to_gsmA(const char* in, uint8_t* out) {
unsigned bit_count = 0;
unsigned bit_queue = 0;
while (*in) {
bit_queue |= (*in & 0x7Fu) << bit_count;
bit_count += 7;
if (bit_count >= 8) {
*out++ = (uint8_t) bit_queue;
bit_count -= 8;
bit_queue >>= 8;
}
in++;
}
if (bit_count > 0) {
*out++ = (uint8_t) bit_queue;
}
return true;
}
我编写的一个简单例程,用于将 ASCII
字符串转换为相应的 7-bit GSM
编码方案:
#include <stdio.h>
#include <process.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
/* convert ascii input string to 7-bit GSM alphabet */
bool ascii_to_gsm(const char* in, uint8_t len, uint8_t* out, uint8_t start_indx) {
if (in == NULL || out == NULL || len == 0)
return false;
uint8_t nshift = 7;
memcpy(out + start_indx, in, len);
for (size_t i = 0; i < len - 1; i++) {
nshift = (nshift == 255) ? 7 : nshift;
uint16_t l = out[start_indx + i];
uint16_t h = out[start_indx + i + 1];
h = (h << nshift--) | l;
out[start_indx + i] = h;
out[start_indx + i + 1] = h >> 8;
}
return true;
}
int main() {
char data[] = "ASCIIASCII";
uint8_t buff[sizeof(data) - 1];
memset(buff, 0, sizeof(buff));
ascii_to_gsm(data, sizeof(buff), buff, 0);
for (size_t i = 0; i < sizeof(buff); i++) {
printf("\n buff[%d]=%02x", i, buff[i]);
}
system("pause");
return 0;
}
对于像 ASCII
或 TEST
这样的字符串,它工作正常,输出分别是 C1E9309904
和 D4E2940A
。
但是对于字符串 ASCIIASCII
一些输出字节是错误的:
C1E930990C4E87498024
结果应该是:C1E930990C4E87C924
不知道是什么部分,我错了。
可以找到有关 GSM 编码的概念 here。
我使用this在线编码器比较结果
But for string ASCIIASCII some output byte is wrong:
C1E930990C4E87498024
The result should be:
C1E930990C4E87C924
OP 的代码没有考虑到输出的长度可能比输入的长度短。
如果输入的是10个ASCII字符,就是70位。输出需要是 ceiling(70/8) 或 9 个字节。另见
缺少 start_indx
的简化参考代码。由于输入是 string ("converting ASCII string"),因此不需要输入长度。
bool ascii_to_gsmA(const char* in, uint8_t* out) {
unsigned bit_count = 0;
unsigned bit_queue = 0;
while (*in) {
bit_queue |= (*in & 0x7Fu) << bit_count;
bit_count += 7;
if (bit_count >= 8) {
*out++ = (uint8_t) bit_queue;
bit_count -= 8;
bit_queue >>= 8;
}
in++;
}
if (bit_count > 0) {
*out++ = (uint8_t) bit_queue;
}
return true;
}