| 7 | #include "MbusParser.h" |
| 8 | |
| 9 | int8_t MBUSParser::parse(uint8_t *d, DataParserContext &ctx) { |
| 10 | int len; |
| 11 | int headersize = 3; |
| 12 | int footersize = 1; |
| 13 | |
| 14 | uint8_t* ptr; |
| 15 | |
| 16 | // https://m-bus.com/documentation-wired/06-application-layer |
| 17 | if(ctx.length < 4) |
| 18 | return DATA_PARSE_INCOMPLETE; |
| 19 | |
| 20 | MbusHeader* mh = (MbusHeader*) d; |
| 21 | if(mh->flag1 != MBUS_START || mh->flag2 != MBUS_START) |
| 22 | return DATA_PARSE_BOUNDARY_FLAG_MISSING; |
| 23 | |
| 24 | // First two bytes is 1-byte length value repeated. Only used for last segment |
| 25 | if(mh->len1 != mh->len2) |
| 26 | return MBUS_FRAME_LENGTH_NOT_EQUAL; |
| 27 | len = mh->len1; |
| 28 | ptr = (uint8_t*) &mh[1]; |
| 29 | headersize = 4; |
| 30 | footersize = 2; |
| 31 | |
| 32 | if(len == 0x00) |
| 33 | len = ctx.length - headersize - footersize; |
| 34 | // Payload can max be 255 bytes, so I think the following case is only valid for austrian meters |
| 35 | if(len < headersize) |
| 36 | len += 256; |
| 37 | |
| 38 | if((headersize + footersize + len) > ctx.length) |
| 39 | return DATA_PARSE_INCOMPLETE; |
| 40 | |
| 41 | MbusFooter* mf = (MbusFooter*) (d + len + headersize); |
| 42 | if(mf->flag != MBUS_END) |
| 43 | return DATA_PARSE_BOUNDARY_FLAG_MISSING; |
| 44 | if(checksum(d + headersize, len) != mf->fcs) |
| 45 | return DATA_PARSE_FOOTER_CHECKSUM_ERROR; |
| 46 | |
| 47 | ptr += 2; len -= 2; |
| 48 | |
| 49 | // Control information field |
| 50 | uint8_t ci = *ptr; |
| 51 | |
| 52 | // Skip CI, STSAP and DTSAP |
| 53 | ptr += 3; len -= 3; |
| 54 | |
| 55 | // Bits 7 6 5 4 3 2 1 0 |
| 56 | // 0 0 0 Finished Sequence number |
| 57 | uint8_t sequenceNumber = (ci & 0x0F); |
| 58 | if((ci & 0x10) == 0x00) { // Not finished yet |
| 59 | if(sequenceNumber == 0) { |
| 60 | if(buf == NULL) buf = (uint8_t *)malloc((size_t)1024); // TODO find out from first package ? |
| 61 | pos = 0; |
| 62 | } else if(buf == NULL || pos + len > 1024 || sequenceNumber != (lastSequenceNumber + 1)) { |
| 63 | return DATA_PARSE_FAIL; |
| 64 | } |
| 65 | memcpy(buf+pos, ptr, len); |
| 66 | pos += len; |
nothing calls this directly
no outgoing calls
no test coverage detected