Exportable version of WizziLab's modem driver.
Diff: src/alp_helpers.cpp
- Revision:
- 19:701d5669f2e9
- Parent:
- 16:3cdc2e00f5ed
- Child:
- 26:2c934a269914
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/alp_helpers.cpp Tue Dec 12 16:03:12 2017 +0000 @@ -0,0 +1,239 @@ +/// @copyright +/// ========================================================================={{{ +/// Copyright (c) 2012-2017 WizziLab / +/// All rights reserved / +/// / +/// Should you have any questions regarding your right to use this Software, / +/// contact WizziLab at www.wizzilab.com. / +/// / +/// =========================================================================}}} +/// @endcopyright + +// ==================================================================== +// @file alp_helpers.c +// @brief ALP public helpers functions. +// This code should be disclosable in source. +// ==================================================================== + + +#include "alp.h" + +//====================================================================== +// alp_size +//---------------------------------------------------------------------- +/// @brief Return payload length of most ALP operations +/// @param op : ALP Action amongst alp_opcodes_t +/// @param offset : Associated Offset if relevant +/// @param size : Associated Size if relevant +/// @retval payload size in bytes +//====================================================================== +public uint alp_size(u8 op, u32 offset, u32 length) +{ + uint len=2;// At least OP+FID / OP+TAG + switch (op) + { + case ALP_OPCODE_NOP: + case ALP_OPCODE_F_TOUCH: + case ALP_OPCODE_F_EXIST: + case ALP_OPCODE_F_DELETE: + case ALP_OPCODE_F_FLUSH: + case ALP_OPCODE_RSP_TAG: + case ALP_OPCODE_F_RD_PROP: + break; + case ALP_OPCODE_RSP_STATUS: + len += 1; + break; + case ALP_OPCODE_F_CREATE: + case ALP_OPCODE_F_DECLARE: + case ALP_OPCODE_RSP_F_PROP: + len += ALP_FILE_HEADER_SIZE; + break; + case ALP_OPCODE_F_WR_PROP: + case ALP_OPCODE_F_WR_DATA: + case ALP_OPCODE_RSP_F_DATA: + len = length; + case ALP_OPCODE_F_RD_DATA: + len += ALP_LFIELD_SIZE(offset) + ALP_LFIELD_SIZE(length); + break; + default: + //ASSERT(false,"ASSERT: ALP: alp_size unsupported op %d\n",op); + break; + } + return len; +} + +//====================================================================== +// alp_encode_length +//---------------------------------------------------------------------- +/// @brief Encodes an ALP length/offset field +/// @param p : pointer to the payload buffer +/// @param len : value to be encoded +/// @retval resulting payload size in bytes +//====================================================================== +public u8 alp_encode_length(u8* p, u32 len) +{ + if (len <= 0x3F) + { + *p++ = len; + return 1; + } + else if (len <= 0x3FFF) + { + *p++ = 0x40 + (u8)(len >> 8); + *p++ = (u8)(len & 0xFF); + return 2; + } + else if (len <= 0x3FFFFF) + { + *p++ = 0x80 + (u8) (len >> 16); + *p++ = (u8)((len >> 8) & 0xFF); + *p++ = (u8) (len & 0xFF); + return 3; + } + else + { + *p++ = 0xC0 + (u8) (len >> 24); + *p++ = (u8)((len >> 16) & 0xFF); + *p++ = (u8)((len >> 8) & 0xFF); + *p++ = (u8) (len & 0xFF); + return 4; + } +} + + +//====================================================================== +// alp_decode_length +//---------------------------------------------------------------------- +/// @brief Decodes an ALP length/offset field +/// @param p : pointer to the pointer to payload buffer +/// @param actp : pointer to ALP's Action Protocol Substitution flag +/// Result amongst alp_actp_substitution_mode_t +/// @retval decoded value +//====================================================================== +public u32 alp_decode_length(u8** p, u8* actp) +{ + u32 tmp = 0; + switch ((**p) & 0xC0) + { + case 0xC0: // 0xCx xx xx xx + tmp = ((*(*p)++) & 0x3F) << 24; + tmp += (*(*p)++) << 16; + tmp += (*(*p)++) << 8; + tmp += (*(*p)++) << 0; + break; + case 0x80: // 0x8x xx xx : 16384 <= Len <4194303 + tmp = ((*(*p)++) & 0x3F) << 16; + tmp += (*(*p)++) << 8; + if (tmp == 0) + { + // 0x8000 ActP special ActP code + // Do not fetch the extra byte + *actp = 2; + } + else + { + tmp += (*(*p)++) << 0; + } + break; + case 0x40: // 0x4x xx : 64 <= Len < 16383 + tmp = ((*(*p)++) & 0x3F) << 8; + tmp += (*(*p)++) << 0; + if (tmp == 0) + { + // 0x4000 ActP special ActP code + *actp = 1; + } + break; + case 0: // Len <63 + tmp = (*(*p)++ & 0x3F) << 0; + break; + } + return tmp; +} + + +//====================================================================== +// alp_parse_chunk +//---------------------------------------------------------------------- +/// @brief Parses an ALP payload and extract a single chunk (action or +/// response) to a more generic alp_parsed_chunk_t structure. +/// @param payload : pointer to the pointer to payload buffer +/// @param resp : pointer to alp_parsed_chunk_t structure +/// @retval number of parsed bytes +//====================================================================== +public int alp_parse_chunk(u8** payload, alp_parsed_chunk_t* resp) // {{{ +{ + u8* p = *payload; + u8 op = *p++; + u8 actp; + u32 bytes; + resp->type = op & 0x3F; + resp->data = (u8*)NULL; + switch(resp->type) // XXX preemption bits squashed + { + case ALP_OPCODE_RSP_TAG: + case ALP_OPCODE_TAG: + resp->meta.tag.id = *p++; // PID + resp->meta.tag.eop = !!(op & ALP_OPCODE_EOP); + resp->meta.tag.err = !!(op & ALP_OPCODE_ERR); + break; + case ALP_OPCODE_RSP_F_DATA: + case ALP_OPCODE_F_WR_DATA: + resp->meta.f_data.fid = *p++; // FID + resp->meta.f_data.offset = alp_decode_length(&p,&actp); // Offset + resp->meta.f_data.length = alp_decode_length(&p,&actp); // Length + resp->data = p; + p += resp->meta.f_data.length; + break; + case ALP_OPCODE_F_RD_DATA: + resp->meta.f_data.fid = *p++; // FID + resp->meta.f_data.offset = alp_decode_length(&p,&actp); // Offset + resp->meta.f_data.length = alp_decode_length(&p,&actp); // Length + break; + case ALP_OPCODE_F_RD_PROP: + resp->meta.f_prop.fid = *p++; // FID + resp->meta.f_prop.offset = 0; + resp->meta.f_prop.length = ALP_FILE_HEADER_SIZE; // Hardcoded Length + break; + case ALP_OPCODE_RSP_F_PROP: + resp->meta.f_prop.fid = *p++; // FID + resp->meta.f_prop.offset = 0; + resp->meta.f_prop.length = ALP_FILE_HEADER_SIZE; // Hardcoded Length + resp->data = p; + p += resp->meta.f_prop.length; + break; + case ALP_OPCODE_RSP_STATUS: + if (op == ALP_OPCODE_RSP_ISTATUS) + { + resp->type = ALP_OPCODE_RSP_ISTATUS; + resp->meta.itf.type = *p++; // ITF Type + resp->meta.itf.length = alp_decode_length(&p,&actp); // Length + resp->data = p; + p += resp->meta.itf.length; + } + else + { + resp->meta.status.id = *p++; // Action ID + resp->meta.status.code = *p++; // status + } + break; + case ALP_OPCODE_RSP_URC: + resp->meta.urc.type = *p++; // Type + resp->meta.urc.ifid = *p++; // Ifid + if (resp->meta.urc.type == ALP_URC_TYPE_LQUAL) + resp->meta.urc.per = *p++; // Per + break; + case ALP_OPCODE_F_DELETE: + case ALP_OPCODE_F_FLUSH: + resp->meta.f_data.fid = *p++; // FID + break; + default: + resp->type = ALP_OPCODE_UNKNOWN; + *payload = (u8*)NULL; + return 0; + } + bytes = p - *payload; + *payload = p; + return bytes; +} // }}} +