Reputation: 25
So I am developing a BACnet automated control system, I am relatively new to it, as this is my first time working with BACnet. I've used ASN.1 protocol with the asn1c compiler which converted my code to a C format. I'm have a very difficult time finding a clear example on how to implement the code for a number of reasons. 1, I'm not entirely sure how ASN.1 actually works, and 2, now that the code has been converted to C, its appears vastly different, and the physical syntax is hanging me up. I was wondering if someone could explain the actual process by which ASN.1 transmits data. I've read that using ASN.1 its possible for a cell phone to communicate with a super computer, I would like to know exactly how, and also, if anyone has a clear "idiot-proof" example of how to actually decode and encode message that can be read from and written to a BACnet message. Below I have posted the BACnetObjectIdentifier
#include "BACnetObjectIdentifier.h"
main()
{
int
BACnetObjectIdentifier_constraint(asn_TYPE_descriptor_t *td, const void
asn_app_constraint_failed_f *ctfailcb, void *app_key) {
const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
size_t size;
if(!sptr) {
_ASN_CTFAIL(app_key, td, sptr,
"%s: value not given (%s:%d)",
td->name, __FILE__, __LINE__);
return -1;
}
size = st->size;
if((size == 4)) {
/* Constraint check succeeded */
return 0;
} else {
_ASN_CTFAIL(app_key, td, sptr,
"%s: constraint failed (%s:%d)",
td->name, __FILE__, __LINE__);
return -1;
}
}
static void
BACnetObjectIdentifier_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) {
td->free_struct = asn_DEF_OCTET_STRING.free_struct;
td->print_struct = asn_DEF_OCTET_STRING.print_struct;
td->check_constraints = asn_DEF_OCTET_STRING.check_constraints;
td->ber_decoder = asn_DEF_OCTET_STRING.ber_decoder;
td->der_encoder = asn_DEF_OCTET_STRING.der_encoder;
td->xer_decoder = asn_DEF_OCTET_STRING.xer_decoder;
td->xer_encoder = asn_DEF_OCTET_STRING.xer_encoder;
td->uper_decoder = asn_DEF_OCTET_STRING.uper_decoder;
td->uper_encoder = asn_DEF_OCTET_STRING.uper_encoder;
if(!td->per_constraints){
td->per_constraints = asn_DEF_OCTET_STRING.per_constraints;
td->elements = asn_DEF_OCTET_STRING.elements;
td->elements_count = asn_DEF_OCTET_STRING.elements_count;
td->specifics = asn_DEF_OCTET_STRING.specifics;
}
void
BACnetObjectIdentifier_free(asn_TYPE_descriptor_t *td,
void *struct_ptr, int contents_only) {
BACnetObjectIdentifier_1_inherit_TYPE_descriptor(td);
td->free_struct(td, struct_ptr, contents_only);
}
int
BACnetObjectIdentifier_print(asn_TYPE_descriptor_t *td, const void *struct_ptr,
int ilevel, asn_app_consume_bytes_f *cb, void *app_key) {
BACnetObjectIdentifier_1_inherit_TYPE_descriptor(td);
return td->print_struct(td, struct_ptr, ilevel, cb, app_key);
}
asn_dec_rval_t
BACnetObjectIdentifier_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
void **structure, const void *bufptr, size_t size, int tag_mode) {
BACnetObjectIdentifier_1_inherit_TYPE_descriptor(td);
return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode);
}
asn_enc_rval_t
BACnetObjectIdentifier_encode_der(asn_TYPE_descriptor_t *td,
void *structure, int tag_mode, ber_tlv_tag_t tag,
asn_app_consume_bytes_f *cb, void *app_key) {
BACnetObjectIdentifier_1_inherit_TYPE_descriptor(td);
return td->der_encoder(td, structure, tag_mode, tag, cb, app_key);
}
asn_dec_rval_t
BACnetObjectIdentifier_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
void **structure, const void *bufptr, size_t size, int tag_mode) {
BACnetObjectIdentifier_1_inherit_TYPE_descriptor(td);
return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode);
}
asn_enc_rval_t
BACnetObjectIdentifier_encode_der(asn_TYPE_descriptor_t *td,
void *structure, int tag_mode, ber_tlv_tag_t tag,
asn_app_consume_bytes_f *cb, void *app_key) {
BACnetObjectIdentifier_1_inherit_TYPE_descriptor(td);
return td->der_encoder(td, structure, tag_mode, tag, cb, app_key);
}
asn_dec_rval_t
BACnetObjectIdentifier_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
void **structure, const char *opt_mname, const void *bufptr, size_t size) {
BACnetObjectIdentifier_1_inherit_TYPE_descriptor(td);
return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size);
}
asn_enc_rval_t
BACnetObjectIdentifier_encode_xer(asn_TYPE_descriptor_t *td, void *structure,
int ilevel, enum xer_encoder_flags_e flags,
asn_app_consume_bytes_f *cb, void *app_key) {
BACnetObjectIdentifier_1_inherit_TYPE_descriptor(td);
return td->xer_encoder(td, structure, ilevel, flags, cb, app_key);
}
asn_dec_rval_t
BACnetObjectIdentifier_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
asn_per_constraints_t *constraints, void **structure, asn_per_data_t *per_data) {
BACnetObjectIdentifier_1_inherit_TYPE_descriptor(td);
return td->uper_decoder(opt_codec_ctx, td, constraints, structure, per_data);
}
asn_enc_rval_t
BACnetObjectIdentifier_encode_uper(asn_TYPE_descriptor_t *td,
asn_per_constraints_t *constraints,
void *structure, asn_per_outp_t *per_out) {
BACnetObjectIdentifier_1_inherit_TYPE_descriptor(td);
return td->uper_encoder(td, constraints, structure, per_out);
}
static asn_per_constraints_t asn_PER_type_BACnetObjectIdentifier_constr_1 GCC_NOTUSED = {
{ APC_UNCONSTRAINED, -1, -1, 0, 0 },
{ APC_CONSTRAINED, 0, 0, 4, 4 } /* (SIZE(4..4)) */,
0, 0 /* No PER value map */
};
static ber_tlv_tag_t asn_DEF_BACnetObjectIdentifier_tags_1[] = {
(ASN_TAG_CLASS_APPLICATION | (12 << 2)),
(ASN_TAG_CLASS_UNIVERSAL | (4 << 2))
};
asn_TYPE_descriptor_t asn_DEF_BACnetObjectIdentifier = {
"BACnetObjectIdentifier",
"BACnetObjectIdentifier",
BACnetObjectIdentifier_free,
BACnetObjectIdentifier_print,
BACnetObjectIdentifier_constraint,
BACnetObjectIdentifier_decode_ber,
BACnetObjectIdentifier_encode_der,
BACnetObjectIdentifier_decode_xer,
BACnetObjectIdentifier_encode_xer,
BACnetObjectIdentifier_decode_uper,
BACnetObjectIdentifier_encode_uper,
0, /* Use generic outmost tag fetcher */
asn_DEF_BACnetObjectIdentifier_tags_1,
sizeof(asn_DEF_BACnetObjectIdentifier_tags_1)
/sizeof(asn_DEF_BACnetObjectIdentifier_tags_1[0]) - 1, /* 1 */
asn_DEF_BACnetObjectIdentifier_tags_1, /* Same as above */
sizeof(asn_DEF_BACnetObjectIdentifier_tags_1)
/sizeof(asn_DEF_BACnetObjectIdentifier_tags_1[0]), /* 2 */
&asn_PER_type_BACnetObjectIdentifier_constr_1,
0, 0, /* No members */
0 /* No specifics */
};
}
The above code is what the asn1c compiler produced. Any help is greatly appreciated.
Upvotes: 2
Views: 1900
Reputation: 488
If you're looking to delve into (the world of) BACnet then I fear that you might be coming at it from the wrong angle / straight in at the deep-end (or at least a specific facet/depth of it), therefore chewing on the complexity before giving yourself the chance to dip your toe in, to first understand/test the water (in a more general/cross-cutting manner).
E.g. Using Karate as a rough example, if learning BACnet is getting a/to Black Belt, then learning ASN is probably the further progression to 1st or 2nd Dan.
I'd recommend trying a tool like YABE, and then (instead of Wireshark) VTS (Visual Test Shell), and then one day - if you write part of your own BACnet (mock) device, then you would have gained yet a further understanding.
(YABE is written in C#, but VTS is written in C++, and the BACnetStack is written in C.)
Upvotes: 0
Reputation: 1110
What you really need is a copy of the Ashrae 135-2012 (or later) standard. (unfortunately non free - although errata and addentum are free).
ASN1 just describes some encoding rules, but that's not because my emails are encoded in base64 that you can read emails if you read base64. You also need to understand other headers, contexts, rules and semantics.
The encodings, types, enumerations and service codes are completely detailed, in the Ashrae 135 standard. And this kind of information is really needed to understand and "read" BACnet packets.
Using Wireshark to view and open some captured packets, do really help also, in order to understand how the informations are listed, and sent, depending on the various message contexts.
You can also pick a free or a non-free C or Java or C# (or other) implementation of the BACnet communication protocol and play with that, too.
Upvotes: 0
Reputation: 1978
What you need is an introduction to ASN.1 and an introduction to the tool you are using. For the former, you might start here: http://www.obj-sys.com/resources/links_asn1_info.php. I can't help you with the latter.
To help orient you, a very brief summary: ASN.1 is Abstract Syntax Notation. It is a notation for describing the syntax of messages in the abstract. "In the abstract" means, for example, that using the notation you will specify that one integer follows another in a sequence, but you don't specify how those integers are actually represented in transmission (e.g. how many bits will be used?). The abstract notation becomes concrete when you combine it with a set of encoding rules (e.g BER, PER; encoding rules are standardized - you don't write them). The encoding rules in combination with the abstract syntax fully specifies what is transmitted.
What the code generation tools do is conceptually simple. They read an ASN.1 description and produce data structures in your favorite programming language that model the messages from the ASN.1, plus functions that can take those data structures and encode/decode the corresponding messages according to your chosen set of encoding rules. As a programmer, you populate the data structures, invoke the encode method, and receive an ASN.1 message encoded according to the rules you chose (e.g. BER).
Upvotes: 1