国标二阶段VIR消息集调试总结

国标二阶段VIR消息集调试总结

最近项目需要,开始着手VIR消息集合的填充、收发调试,遇到几个坑,记录一下。

一、msgFrameExt帧中的messageId

仔细看国标、仔细看国标、仔细看国标

标准中有明确告知该字段对应填充的值,若随意填充回导致接收端decode时出现错误。

ExtMsgID ::= INTEGER (0..32767)  
********** Test Message ************************
testData ExtMsgID ::= 0
********** DAY II Messages *********************
rtcmData ExtMsgID ::= 10
rscData ExtMsgID ::= 11
ssmData ExtMsgID ::= 12
virData ExtMsgID ::= 13
pamData ExtMsgID ::= 14
psmData ExtMsgID ::= 15
clpmmData ExtMsgID ::= 16
vpmData ExtMsgID ::= 17
二、uper_encode函数

使用uper_encode函数进行的uper编码,uper_encode源码如下:

asn_enc_rval_t uper_encode(const asn_TYPE_descriptor_t *td, const asn_per_constraints_t *constraints, const void *sptr, asn_app_consume_bytes_f *cb, void *app_key) {

  asn_per_outp_t po;

  asn_enc_rval_t er;


  /*

   \* Invoke type-specific encoder.

   */

  if(!td || !td->op->uper_encoder)

	 ASN__ENCODE_FAILED; /* PER is not compiled in */
    

  po.buffer = po.tmpspace;

  po.nboff = 0;

  po.nbits = 8 * sizeof(po.tmpspace);

  po.output = cb ? cb : ignore_output;

  po.op_key = app_key;

  po.flushed_bytes = 0;

  er = td->op->uper_encoder(td, constraints, sptr, &po);

  if(er.encoded != -1) {

	size_t bits_to_flush;

	bits_to_flush = ((po.buffer - po.tmpspace) << 3) + po.nboff;

	/* Set number of bits encoded to a firm value */

	er.encoded = (po.flushed_bytes << 3) + bits_to_flush;

      
	if(_uper_encode_flush_outp(&po)) ASN__ENCODE_FAILED;

  }

  return er;

}

需要留意的是返回值asn_enc_rval_t和回调函数asn_app_consume_bytes_f *cb;

/*
 * Type of the return value of the encoding functions (der_encode, xer_encode).
 */
typedef struct asn_enc_rval_s {
	/*
	 * Number of bytes encoded.
	 * -1 indicates failure to encode the structure.
	 * In this case, the members below this one are meaningful.
	 */
	ssize_t encoded;

	/*
	 * Members meaningful when (encoded == -1), for post mortem analysis.
	 */

	/* Type which cannot be encoded */
	const struct asn_TYPE_descriptor_s *failed_type;

	/* Pointer to the structure of that type */
	const void *structure_ptr;
} asn_enc_rval_t;

该结构体包含3个成员【编码的字节数、无法编码的类型描述指针、指向该类型结构的指针】。asn1c库编码函数返回的encoded,存在一个小问题 - 渤海深处的博客 (rustintherubble.github.io) 由该描述可知,直接通过encode函数获取编码长度需确认返回值编码长度的含义,这里一般不建议使用ec.encoded作为编码输出的最后长度,建议使用per_encoder.c里面的encode_to_buffer_cb这个函数。

static int encode_to_buffer_cb(const void *buffer, size_t size, void *key) {
	enc_to_buf_arg *arg = (enc_to_buf_arg *)key;

	if(arg->left < size)
		return -1;	/* Data exceeds the available buffer size */

	memcpy(arg->buffer, buffer, size);
	arg->buffer = ((char *)arg->buffer) + size;
	arg->left -= size;
	printf("encode_to_buffer_cb:\n");
	for (int i = 0; i < size; i++)
	{
		printf("%02x", *((unsigned char *)buffer + i));
	}
	printf("\n");
	return 0;
}

三、关于ASN_FREE_STRUCT

在使用ASN_FREE_STRUCT(&asn_DEF_MessageFrame, msg)的时候,仅仅释放了msg还不够,通过单步调试看到,即使free了msg,但是在下一次为msg申请空间后,msg所在地址空间内居然保留了上一次解码所产生的数值,这样的话,如果每次解码的消息体结构是一样的还好说,如果消息体结构不一致,也会报段错误,而且也会导致数据重复,最保险的做法是,在为msg申请空间后,将其地址空间内的值都置为0,即memset(mf, 0, sizeof(MessageFrame_t));当然了,其实不管在哪,自己申请了一块地址空间后,最保险还是将其内的数值重置为0。关于再次申请结构不一致,导致段错误的问题,暂时不是知道怎么解决,现有的解决思路是在free前把msg中的值都置0,但这种思路暂时没有验证过。

四、关于xer_fprint

在调试过程中多使用xer_fprint函数打印填充的消息集合,建议在encode之前和decode之后都进行一次打印,很容易找到问题。若encode之前xer_fprint打印有问题,那么encode肯定会失败,而且问题一般出在xer_fprint打印中断的地方,多注意这个地方填充的数据;decode之后的xer_fprint打印也同理。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值