Code Segment about PDU

本文介绍了一种通过PDU协议实现短信发送的技术方案,包括消息内容的编码转换、字符串处理及最终PDU编码的生成过程。

/*

* =====================================================================================

*

* Filename: gmesg.c

*

* =====================================================================================

*/

 

/* 头文件开始 1.编码转换需要iconv.h 2.对消息内容特殊转换需要gmesg.h */

/*{{{*/

#include

#include

#include

#include

#include

#include

#include

#include

 

#include

#include "gmesg.h"

#include "gport.h"

 

#define SLEEP3S 0

/*}}}*/

/* 头文件结束 1.编码转换需要iconv.h 2.对消息内容特殊转换需要gmesg.h */

 

 

 

/*

* === FUNCTION ======================================================================

* Name: init_gprs_pdu

* Description: 从数据库中读出默认设置的pdu数据

* =====================================================================================

*/

/*{{{*/

int init_gprs_pdu ( struct gprs_pdu **gpdu, char *signal )

{

    sqlite3 *db = NULL;

    int rc, i;

    char *dbname = "gprsPdu.db";

    char *ErrMsg = NULL;

    char **dbResult = NULL;

    char sql_select[MSIZE] = { 0 };

    int nrow, ncolumn;

 

    if ( NULL == signal )

    {

        strcpy(sql_select, "select * from gprs_pdu where id=1");

    }

    else

    {

        sprintf(sql_select, "select * from gprs_pdu where status = /'%s/'", signal);

    }

 

    rc = sqlite3_open(dbname, &db);

    if ( SQLITE_OK != rc )

    {

        fprintf(stderr, "Cannot open database :%s/n", sqlite3_errmsg(db));

        sqlite3_close(db);

        return -1;

    }

 

    rc = sqlite3_get_table (db, sql_select, &dbResult, &nrow, &ncolumn, &ErrMsg);

 

    i = ncolumn + 1; /* 去掉id字段 */

    (*gpdu) = (struct gprs_pdu *) malloc (sizeof(struct gprs_pdu));

 

    memset(*gpdu, 0, sizeof(struct gprs_pdu));

    strcpy( (*gpdu)->sim_attr, dbResult[i] );

    i++;

    strcpy( (*gpdu)->sim_center, dbResult[i] );

    i++;

    strcpy( (*gpdu)->phone_attr, dbResult[i] );

    i++;

    strcpy( (*gpdu)->phone, dbResult[i] );

    i++;

    strcpy( (*gpdu)->fix, dbResult[i] );

    i++;

    strcpy( (*gpdu)->gb2312_msg, dbResult[i] );

    i++;

    sqlite3_free_table( dbResult );

    sqlite3_close(db);

    return 0;

}        

/* ----- end of function init_gprs_pdu ----- */

/*}}}*/

 

 

/*

* === FUNCTION ======================================================================

* Name: clear_gprs_pdu

* Description: 清除结构体struct gprs_pdu

* =====================================================================================

*/

/*{{{*/

int clear_gprs_pdu ( struct gprs_pdu *gpdu )

{

    free(gpdu);

    return 0;

}        

/* ----- end of function clear_gprs_pdu ----- */

/*}}}*/

 

 

/*

* === FUNCTION ======================================================================

* Name: code_convert

* Description: 代码转换:从一种编码转为另一种编码

* =====================================================================================

*/

/*{{{*/

int code_convert(char *from_charset,char *to_charset,char *inbuf,int inlen,char *outbuf, int outlen )

{

    iconv_t cd; /* 字符集转换描述符 */

    char **pin = &inbuf; /* 被转换的编码 */

    char **pout = &outbuf; /* 转换后的编码 */

 

    /* iconv_open 申请编码转换描述符,对系统有依赖,可以使用iconv --list查看 */

    cd = iconv_open(to_charset, from_charset);

    if ( cd == 0 )

    {

        return -1;

    }

 

    memset(outbuf, 0, outlen);

 

    /* iconv 实现编码转换 */

    if ( iconv(cd, pin, &inlen, pout, &outlen) == -1 )

    {

        return -1;

    }

 

    /* 关闭编码转换描述符 */

    iconv_close(cd);

 

    return 0;

}        

/* ----- end of function code_convert ----- */

/*}}}*/

 

 

 

/*

* === FUNCTION ======================================================================

* Name: u2g

* Description: UNICODE码转为GB2312码

* =====================================================================================

*/

/*{{{*/

int u2g ( char *inbuf, int inlen, char *outbuf, int outlen )

{

    //return code_convert("unicode","utf-8",inbuf,inlen,outbuf,outlen);

    /* 交叉编译后在,开发板中个人使用下面的,iconv_open对系统有依赖 */

    return code_convert("UTF-16", "GB2312", inbuf, inlen, outbuf, outlen);

}        

/* ----- end of function u2g ----- */

/*}}}*/

 

 

 

/*

* === FUNCTION ======================================================================

* Name: g2u

* Description: GB2312码转为UNICODE码

* =====================================================================================

*/

/*{{{*/

int g2u ( char *inbuf, int inlen, char *outbuf, int outlen )

{

    /* 交叉编译后在,开发板中个人使用下面的,iconv_open对系统有依赖 */

    /* GB2312 -> UTF-16 转换之后,前端会有多余字节 */

    return code_convert("GB2312", "UTF-16", inbuf, inlen, outbuf, outlen);

    /* GB2312 -> UCS2 主机正常,在开发板上使用时会段错误,断点在iconv_open处,可能缺少lib*/

    //return code_convert("GB2312", "UCS2", inbuf, inlen, outbuf, outlen);

}        

/* ----- end of function g2u ----- */

/*}}}*/

 

 

 

/*

* === FUNCTION ======================================================================

* Name: bytes2string

* Description: 将字节流转换成字符串,为了PDU编码作准备

* =====================================================================================

*/

/*{{{*/

int bytes2string ( const unsigned char *pSrc, char *pDst, int nSrcLength )

{

    const char tab[] = "0123456789ABCDEF";

    int i;

 

    for ( i=0; i

    {

        *pDst++ = tab[*pSrc >> 4]; /* 取出高4位 */

        *pDst++ = tab[*pSrc & 0x0f]; /* 取出底4位 */

        pSrc++;

    }

 

    /* 加上结束标志 */

    *pDst = '/0';

 

    /* 返回字符串长度,将一个字节分成两个字符,所以长度乘以2 */

    return nSrcLength*2;

}        

/* ----- end of function bytes2string ----- */

/*}}}*/

 

 

 

/*

* === FUNCTION ======================================================================

* Name: switch_byte1

* Description: 实现字符串中相邻的字符交换,为了PDU编码作准备,电话号码相邻数字交换。

* =====================================================================================

*/

/*{{{*/

int switch_byte1 ( char *src, int len )

{

    int i;

    char tch;

 

    for ( i=0; i

    {

        tch = *(src + i + 1);

        *(src + i + 1) = *(src + i);

        *(src + i) = tch;

    }

 

    return len;

}        

/* ----- end of function switch_byte1 ----- */

/*}}}*/

 

 

 

/*

* === FUNCTION ======================================================================

* Name: switch_byte2

* Description: 与编码有关的函数,经过iconv转换(GB2312 -> UTF-16)的编码,再经字节流转变成字符串后,字符串

*          中的十六进制字符,顺序双对换,根据系统的不同,决定该函数是否需要调用.例如:

*          在宿主机上(Unbuntu)上需要调用,目标板(s3c2410)不需要.

* =====================================================================================

*/

/*{{{*/

int switch_byte2 ( char *src, int len )

{

    int i;

    char tch;

 

    for ( i=0; i

    {

        /* 将第1个字符与第3个字符交换 */

        tch = *(src + i + 2);

        *(src + i + 2) = *(src + i);

        *(src + i) = tch;

 

        /* 将第2个字符与第4个字符交换 */

        tch = *(src + i + 3);

        *(src + i + 3) = *(src + i + 1);

        *(src + i + 1) = tch;

 

        /* eg. "1234" ---> "3412" */

    }

    return len;

}        

/* ----- end of function switch_byte2 ----- */

/*}}}*/

 

 

 

/*

* === FUNCTION ======================================================================

* Name: change_sim_attr

* Description: 更改短信息中心地址长度和号码类型

* =====================================================================================

*/

/*{{{*/

int change_sim_attr ( const char *src , char *des )

{

    printf ( "/nsrc : %s/n", src );

    memset(des, 0, strlen(des));

    strcpy(des, src);

    return 0;

}        

/* ----- end of function make_sim_attr ----- */

/*}}}*/

 

 

 

/*

* === FUNCTION ======================================================================

* Name: change_sim_center

* Description: 更改短信息中心服务号码 (参数改变)

* =====================================================================================

*/

/*{{{*/

int change_sim_center ( const char *src , char *des )

{

    memset(des, 0, strlen(des));

    strcat(des, "86");

    strcat(des, src);

    if( strlen(des)%2 != 0 )

    {

        strcat(des, "F");

    }

    return 0;

}        

/* ----- end of function change_sim_center ----- */

/*}}}*/

 

 

 

/*

* === FUNCTION ======================================================================

* Name: change_phone_attr

* Description: 更改发送到目的地址(手机)的属性

* =====================================================================================

*/

/*{{{*/

int change_phone_attr ( const char *src, char *des )

{

    memset(des, 0, strlen(des));

    strcpy(des, src);

    return 0;

}        

/* ----- end of function change_phone_attr ----- */

/*}}}*/

 

 

 

/*

* === FUNCTION ======================================================================

* Name: change_other_phone

* Description: 更改发送到目的手机号码 (参数改变)

* =====================================================================================

*/

/*{{{*/

int change_other_phone ( const char *src , char *des )

{

    memset(des, 0, strlen(des));

    strcat(des, "86");

    strcat(des, src);

    if ( strlen(des)%2 != 0 )

    {

        strcat(des, "F");

    }

    return 0;

}        

/* ----- end of function change_other_phone ----- */

/*}}}*/

 

 

 

/*

* === FUNCTION ======================================================================

* Name: change_fix

* Description: 改变固定格式,详细请参考其他(没有不变的东西)

* =====================================================================================

*/

/*{{{*/

int change_fix ( const char *src , char *des )

{

    memset(des, 0, strlen(des));

    strcpy(des, src);

    return 0;

}        

/* ----- end of function change_fix ----- */

/*}}}*/

 

 

 

/*

* === FUNCTION ======================================================================

* Name: change_gb2312_msg

* Description: 改变要发送的实际信息内容

* =====================================================================================

*/

/*{{{*/

int change_gb2312_msg ( const char *src, char *des )

{

    memset(des, 0, strlen(des));

    strcpy(des, src);

    return 0;

}        

/* ----- end of function change_gb2312_msg ----- */

/*}}}*/

 

 

 

/*

* === FUNCTION ======================================================================

* Name: make_mesg

* Description: 该函数是该文件的'主'函数,它调动上面的函数来实现短信消息的内容合成。

* =====================================================================================

*/

/*{{{*/

int make_mesg ( char *src, char *dest, int src_len, int des_len )

{

    int rc;

    char b2s[MSIZE]; /* 字节流转换字符串 */

    char nhex[6]; /* 计算消息的内容长度(十六进制表示)*/

    char nhex_even[4] = {'0'}; /* PDU规则,长度为奇数前加0 */

    g2u(src, src_len, dest, des_len); /* 将GB2312流转换成UTF-16 */

    rc = bytes2string(dest, b2s, strlen(dest));

 

    /* 开发板中不需要switch_byte2,主机上需要. 让我伤心的地方 */

    //rc = switch_byte2(b2s, rc);

    /* GB2312 -> UTF-16 转换之后,再经过字节流转换成字符串,前端多了4个字符. */

    sprintf(nhex, "%X", (rc-4)/2); /* (GB2312 -> UTF-16)除以2是得到的汉字字符个数,在格式化输出十六进制 */

    //sprintf(nhex, "%X", rc/2); /* 使用(GB2312 -> UCS2)时 */

 

    /* 判断长度是否是偶数 */

    if ( strlen(nhex)%2 == 1 )

    {

        /* 奇数 前端加0 */

        strcat(nhex_even, nhex);

        memset(dest, 0, MSIZE);

        strcpy(dest, nhex_even);

    }

    else

    {

        memset(dest, 0, MSIZE);

        strcpy(dest, nhex);

    }

    strcat(dest, b2s+4); /* (GB2312 -> UTF-16)前面的4个字节是没用的 */

    //strcat(dest, b2s); /* 使用(GB2312 -> UCS2)时 */

    return strlen(dest);

}        

/* ----- end of function make_mesg ----- */

/*}}}*/

 

 

 

/*

* === FUNCTION ======================================================================

* Name: make_content

* Description: 将不同部分的内容组合成完整PDU编码内容

* =====================================================================================

*/

/*{{{*/

int make_content(struct gprs_pdu *gpdu, char *content)

{

    int nsim = 0; /* SIM用户识别卡所占字节(转换为十六进制)*/

    char unicode_msg[MSIZE];

    /* 1. 先将消息内容进行编码转换 */

    make_mesg(gpdu->gb2312_msg, unicode_msg, strlen(gpdu->gb2312_msg), MSIZE);    

    /* 2. 短信消息中心号码数字奇偶转换 */

    switch_byte1(gpdu->sim_center, strlen(gpdu->sim_center));

    /* 3. 接受方手机号码数字奇偶转换 */

    switch_byte1(gpdu->phone, strlen(gpdu->phone));

    /* 4. 将短消息中心地址长度(16/2)和号码类型拼接到content数组中 */

    strcat(content, gpdu->sim_attr);

    /* 5. 将短信息中心号码拼接到content数组中 */

    strcat(content, gpdu->sim_center);

    /* 6. 计算SMSC(Short Message Server Center)相关内容的长度, */

    nsim = strlen(content);

    /* 7. 将接收方的手机号属性拼接到content数组中 */

    strcat(content, gpdu->phone_attr);

    /* 8. 将接受方的手机号拼接到content数组中 */

    strcat(content, gpdu->phone);

    /* 9. 将手机号后面的固定格式拼接到content数组中 */

    strcat(content, gpdu->fix);

    /* 10.将消息的实际内容拼接到content数组中 */

    strcat(content, unicode_msg);

    /* 11.返回:PDU总长度减去SIM用户识别卡所占字节*/

    return (strlen(content) - nsim) ;

}

/* ----- end of function make_content ----- */

/*}}}*/

 

 

 

 

/*

* === FUNCTION ======================================================================

* Name: send_msg

* Description: 功能:发送信息

* =====================================================================================

*/

/*{{{*/

void send_msg ( int fd, char *content, int len, char *dail )

{

    char cmd_buff[C_SIZE];

    char call_buff[C_SIZE] = "ATD"; /* 拨号功能 */

    int n_rw = 0;

 

    printf("Start:/n");

 

    /* 第一阶段:先发送 "AT" 命令,测试ARM与GPRS是否建立通信 */

    write(fd, "AT/r", 3);

    printf("1. Send AT/n");

#ifdef SLEEP3S

    sleep(3);

#endif

    memset(cmd_buff, 0, C_SIZE);

    n_rw = read(fd, cmd_buff, C_SIZE);

    printf("Receive %d bytes is %s/n", n_rw, cmd_buff);

 

 

    /* 第二阶段:设置信息的模式 0:PDU, 1:Plain */

    write(fd, "AT+CMGF=0/r", 10);

    printf("2. Send AT+CMGF=0/n");

#ifdef SLEEP3S

    sleep(3);

#endif

    memset(cmd_buff, 0, C_SIZE);

    n_rw = read(fd, cmd_buff, C_SIZE);

    printf("Receive %d bytes is %s/n", n_rw, cmd_buff);

 

 

    /* 第三阶段:PDU模式下发送消息密令 */

    memset(cmd_buff, 0, C_SIZE);

    sprintf(cmd_buff, "AT+CMGS=%d/r", len);

    write(fd, cmd_buff, strlen(cmd_buff));

    printf("3. Send %s/n", cmd_buff);

#ifdef SLEEP3S

    sleep(3);

#endif

    memset(cmd_buff, 0, C_SIZE);

    n_rw = read(fd, cmd_buff, C_SIZE);

    printf("Receive %d bytes is %s/n", n_rw, cmd_buff);

 

 

    /* 第四阶段:发送消息内容,以0x1A结尾 */

    strcat(content, "/x1a");

    n_rw = write(fd, content, strlen(content));

    printf("4. Send %d Message /n", n_rw);

#ifdef SLEEP3S

    sleep(3);

#endif

    memset(cmd_buff, 0, C_SIZE);

    n_rw = read(fd, cmd_buff, C_SIZE);

    printf("Receive %d bytes is %s/n", n_rw, cmd_buff);

 

 

    /* 第五阶段:实现拨号 */

    if ( NULL != dail )

    {

        sleep(10);

        strncat(call_buff, dail, 11);

        printf("call_buff :%s/n", call_buff);

        strcat(call_buff, ";/r");

        write(fd, call_buff, strlen(call_buff));

        printf("Call some one!/n");

        memset(cmd_buff, 0, C_SIZE);

        n_rw = read(fd, cmd_buff, C_SIZE);

        printf("Receive %d bytes is %s/n", n_rw, cmd_buff);

        printf("/nEnd/n");

    }

 

    return ;

}        

/* ----- end of function send_msg ----- */

/*}}}*/

 

<think> 嗯,用户询问汇编代码中"CODE SEGMENT"和"ASSUME CS:CODE"的含义和用法。这属于汇编语言的基础概念,我需要结合引用的材料进行详细解释。 首先看引用[1]和[2]中的示例代码,它们都使用了类似的段定义结构。CODE SEGMENT是定义代码段的伪指令,告诉汇编器后续的指令属于代码段。ASSUME则是段约定伪指令,将代码段寄存器CS与名为CODE的段关联起来。 引用[3]提供了更深入的解释:ASSUME的作用就是把段地址和段寄存器联系起来。当写ASSUME CS:CODE时,就是把代码段起始地址保存到CS寄存器。这非常重要,因为处理器执行指令时依赖CS:IP来定位代码位置。 关于内存分段机制,汇编程序通常分为代码段、数据段、堆栈段等。每个段都需要用SEGMENT定义。引用[3]还提到ORG伪指令可以指定代码起始偏移地址,如果没有ORG则默认从0开始。 在用法上,引用[1][2][4]的示例都展示了标准写法:先用CODE SEGMENT定义代码段,再用ASSUME CS:CODE建立关联。程序结束时用END START指定入口点。特别要注意的是,定义段后还需要用MOV指令将段地址加载到寄存器,如引用[4]中的"MOV AX,DATAS MOV DS,AX"。 用户可能还隐含想知道为什么需要这样做。这涉及到x86架构的设计:分段内存管理要求明确指定各段的位置和用途。ASSUME帮助汇编器计算标号偏移地址,但实际运行时仍需手动初始化段寄存器。 最后检查是否需要补充其他相关知识。引用中提到的DOS功能调用(INT 21H)和BIOS中断(INT 10H)虽然相关,但用户当前问题聚焦在段定义语法上,暂时不需要展开。 </think>在汇编语言中,`CODE SEGMENT` 和 `ASSUME CS:CODE` 是用于定义代码段和建立段寄存器与段之间关联的关键伪指令: ### 1. `CODE SEGMENT` * **含义**: 定义一个名为 `CODE` 的**代码段**的开始。 * **作用**: * **逻辑划分**: 将程序中的**可执行指令**(机器码)组织在一个连续的代码区域中。 * **内存管理**: 告知汇编器和链接器,后续的指令代码应放置在这个特定的段内。 * **结构清晰**: 使程序结构模块化,便于阅读和维护。代码段通常包含程序的执行逻辑。 * **结束标记**: 代码段的结束使用 `CODE ENDS` 伪指令。 ### 2. `ASSUME CS:CODE` * **含义**: 这是一个**段约定伪指令**。它告诉汇编器:**在汇编(翻译)当前源程序时**,请**假定**代码段寄存器 `CS` 中存放的是名为 `CODE` 的那个段的**段基地址**。 * **作用**: * **地址计算**: 这是它最核心的作用。汇编器在汇编过程中需要计算指令和标号(如 `START:`)在段内的**偏移地址**。`ASSUME CS:CODE` 明确告知汇编器,`CODE` 段内的所有偏移地址都是**相对于 `CS` 寄存器所指向的段基地址**来计算的。 * **语法检查**: 汇编器可以根据这个约定进行一些基本的语法检查,例如确保跳转指令的目标地址在代码段内。 * **代码生成**: 帮助汇编器生成正确的机器码指令,特别是那些涉及地址操作的指令。 * **关键点**: * **仅为汇编器提示**: `ASSUME` **并未**在程序运行时自动将 `CODE` 段的实际物理地址加载到 `CS` 寄存器中!它只是汇编器在翻译源代码时使用的约定。 * **运行时初始化**: 程序实际运行时,操作系统(如 DOS)加载可执行文件(如 `.COM` 或 `.EXE`)时,负责将 `CS` 和 `IP`(指令指针)设置到正确的入口点(如 `START:`)。在 `.EXE` 程序中,链接器生成的程序头信息会告诉加载器代码段的位置。在引用[1][2][4]中,程序的入口点(`START:`)都在代码段内,加载器会自动设置 `CS:IP` 指向它。 * **数据段/堆栈段**: 类似地,对于数据段(通常名为 `DATA` 或 `DATAS`)和堆栈段(通常名为 `STACK` 或 `STACKS`),需要使用 `ASSUME DS:DATA, SS:STACK` 等约定。但**运行时必须手动初始化 `DS` 和 `SS` 寄存器**(如引用[4]中的 `MOV AX, DATAS; MOV DS, AX`),因为加载器通常只保证 `CS:IP` 指向程序入口。 ### 典型用法 (结合引用[1][2][4]示例) ```assembly CODE SEGMENT ; 开始定义名为 CODE 的代码段 ASSUME CS:CODE ; 告诉汇编器:汇编时,假设CS寄存器指向这个CODE段 ; 还可以有其他ASSUME,例如:ASSUME DS:DATA, SS:STACK (如果定义了这些段) START: MOV DL, 1 ; 程序入口点标签 (通常用 END START 指定) ADD DL, 2 ... ; 主要的程序指令放在这里 MOV AH, 4CH ; DOS功能调用:程序结束 INT 21H CODE ENDS ; 结束 CODE 段的定义 END START ; 汇编结束,并指定程序入口点为 START ``` ### 总结 1. **`CODE SEGMENT ... CODE ENDS`**: 定义了一个逻辑容器(代码段),用于存放程序的可执行指令。 2. **`ASSUME CS:CODE`**: 告诉汇编器在翻译这个源文件时,计算代码段内所有地址(偏移量)都基于 `CS` 寄存器指向 `CODE` 段这个**约定**。这是汇编器正确计算偏移地址和生成代码的关键。 3. **运行时**: `CS` 寄存器的实际值由操作系统加载器在程序启动时设置,指向内存中真正的代码段基地址。程序员通常**不需要**(在简单程序中也不能)直接修改 `CS`,除非执行远跳转/调用等特殊操作。而对于 `DS`(数据段)和 `SS`(堆栈段)寄存器,程序员**必须在代码中显式初始化**(如引用[4]所示),即使使用了 `ASSUME` 约定[^1][^2][^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值