从协议的角度结合代码来看
看下coap_context_t object
在main函数中首先定义了这个结构体变量指针
coap_context_t *ctx;
看下其定义:
/** The CoAP stack's global state is stored in a coap_context_t object */
typedef struct coap_context_t {
coap_opt_filter_t known_options;
。。。。。。。
/**
* Fixed-size bit-vector we use for option filtering. It is large
* enough to hold the highest option number known at build time (20 in
* the core spec).
*/
typedef unsigned char coap_opt_filter_t[(COAP_MAX_OPT >> 3) + 1];
#define COAP_MAX_OPT 63 /**< the highest option number we know */
已知的最大的option number是63 ,这里把所有已知的option的标志位放在一个unsigned char的数组中,数组没有元素是一个Byte(8 bits).所以可以用8个大小的数组来保存这些标志位 。其中右移3位就是 2^3 = 8 . 加1防止除不尽多增加一个元素。
怎么去对这个filter赋值呢?搜下这个known_options,可以找到下面这个函数。
/**
* Registers the option type @p type with the given context object @p
* ctx.
*
* @param ctx The context to use.
* @param type The option type to register.
*/
inline static void
coap_register_option(coap_context_t *ctx, unsigned char type) {
coap_option_setb(ctx->known_options, type);
}
看下这个函数在哪里调用
/* register the critical options that we know */
coap_register_option(c, COAP_OPTION_IF_MATCH);
coap_register_option(c, COAP_OPTION_URI_HOST);
coap_register_option(c, COAP_OPTION_IF_NONE_MATCH);
coap_register_option(c, COAP_OPTION_URI_PORT);
coap_register_option(c, COAP_OPTION_URI_PATH);
coap_register_option(c, COAP_OPTION_URI_QUERY);
coap_register_option(c, COAP_OPTION_ACCEPT);
coap_register_option(c, COAP_OPTION_PROXY_URI);
coap_register_option(c, COAP_OPTION_PROXY_SCHEME);
coap_register_option(c, COAP_OPTION_BLOCK2);
coap_register_option(c, COAP_OPTION_BLOCK1);
看起来很简单,直接对需要的option注册就可以。
进去看下 coap_option_setb
/**
* Sets the corresponding bit for @p type in @p filter. This function
* returns @c 1 if bit was set or @c -1 on error (i.e. when the given
* type does not fit in the filter).
*
* @param filter The filter object to change.
* @param type The type for which the bit should be set.
*
* @return @c 1 if bit was set, @c -1 otherwise.
*/
inline static int
coap_option_setb(coap_opt_filter_t filter, unsigned short type) {
return bits_setb((uint8_t *)filter, sizeof(coap_opt_filter_t), type);
}
/**
* Sets the bit @p bit in bit-vector @p vec. This function returns @c
* 1 if bit was set or @c -1 on error (i.e. when the given bit does
* not fit in the vector).
*
* @param vec The bit-vector to change.
* @param size The size of @p vec in bytes.
* @param bit The bit to set in @p vec.
*
* @return @c -1 if @p bit does not fit into @p vec, @c 1 otherwise.
*/
inline static int
bits_setb(uint8_t *vec, size_t size, uint8_t bit) {
if (size <= (bit >> 3))
return -1;
*(vec + (bit >> 3)) |= (uint8_t)(1 << (bit & 0x07));
return 1;
}
上面这个函数就是在known_options中对应的元素中置对应的option位.
说的可能不太明白.
比如:
coap_register_option(c, COAP_OPTION_URI_PATH);
#define COAP_OPTION_URI_PATH 11 /* C, String, 0-255 B, (none) */
调用到bits_setb
inline static int
bits_setb(uint8_t *vec, size_t size, uint8_t bit) {
if (size <= (bit >> 3))
return -1;
*(vec + (bit >> 3)) |= (uint8_t)(1 << (bit & 0x07));
return 1;
}
c 就是申请的结构体
#ifdef WITH_POSIX
coap_context_t *c = coap_malloc( sizeof( coap_context_t ) );
int reuse = 1;
#endif /* WITH_POSIX */
if (size <= (bit >> 3))
return -1;
做一下判断,如果option的值太大,就不能存放在know_options这个数组中了,不然代码直接往下走会有溢出。
*(vec + (bit >> 3)) |= (uint8_t)(1 << (bit & 0x07));
return 1;
bit >> 3 先把这个type分下组,option小于8则在第0个数组元素中,小于16则在第1个元素中,小于32则在第2个元素中。
每个数组元素是unsigned char型的总共有8 bits.
那可以想象这个type(参数bit)对8 取余得到是分在哪组(第几个元素),余数是几就会被分在这个元素的第几位
这样就注册完了,当然libcoap中只是注册几个option,如果你想用其他的可以自己加。
看这个变量的名字就知道是个filter,可以想象代码中是用获取到的option和这个filter中的元素做比较,如果在这个filter中找到了对应的option说明是已知的option,否则就直接返回错误码,然后再做其他处理。