BtStatus FMP_Close(FmpChannel *channel) { BtStatus status = BT_STATUS_FAILED; /* Validate parameters */ CheckUnlockedParm(BT_STATUS_INVALID_PARM, channel != 0); OS_LockStack(); CheckLockedParm(BT_STATUS_NOT_FOUND, IsNodeOnList(&FMP(dev_list), &(channel->node))); // check state if (channel->state == FMP_STATE_OPEN) { status = GattDisconnect(channel->link); } if (status == BT_STATUS_SUCCESS) { FmpClearConnection(channel, status); } OS_UnlockStack(); return status; }
BtStatus FMP_Open(FmpChannel **channel, BD_ADDR *addr) { BtStatus status = BT_STATUS_FAILED; FmpChannel *ch; CheckUnlockedParm(BT_STATUS_INVALID_PARM, addr != 0); OS_LockStack(); kal_trace(BT_TRACE_BLE_PROFILES, FMP_OPENCONNECTION); if ((*channel != NULL) && IsNodeOnList(&FMP(dev_list), &((*channel)->node))) { ch = *channel; } else { ch = FmpNewChannel(); if (ch == NULL) { return BT_STATUS_NO_RESOURCES; } } if (ch->state == FMP_STATE_CLOSED) { status = CMGR_CreateDataLink(&ch->cmgr_handler, addr); kal_trace(BT_TRACE_BLE_PROFILES, FMP_CREATEDATALINK_STATUS, status); if (status == BT_STATUS_SUCCESS) { status = GattClientConnect(ch->cmgr_handler.remDev); } if (status != BT_STATUS_SUCCESS && status != BT_STATUS_PENDING) { FmpFreeChannel(ch); return status; } ch->state = FMP_STATE_OPENING; *channel = ch; } OS_UnlockStack(); return status; }
/*--------------------------------------------------------------------------- * ME_Decode * * This function decodes AT commands received by a gateway (ME). */ AtStatus ME_Decode(AtContext *Atc, AtCommands *Command, XaBufferDesc *In) { I8 i, t; U16 len, offset=0; BOOL match = FALSE; const char **table; char cmdStr[COMMAND_STAGE_LEN]; AtStatus status = AT_STATUS_INVALID_PARM; CheckUnlockedParm(AT_STATUS_INVALID_PARM, (Atc && Command && In)); // Handle message data of SMS for send and write if(Command->bContinue) { if(Command->bContinue) { switch(Command->type) { #if AT_SMS == XA_ENABLED case AT_SEND_MESSAGE: Command->p.sms.sendMsg.msg = AtMakeString(&In->buff[In->readOffset], (U16)(In->writeOffset - In->readOffset)); break; case AT_STORE_MESSAGE: Command->p.sms.writeMsg.msg = AtMakeString(&In->buff[In->readOffset], (U16)(In->writeOffset - In->readOffset)); break; #endif default: break; } Command->bContinue = FALSE; } return AT_STATUS_OK; } OS_MemSet((U8 *)Command, 0, sizeof(AtCommands)); AtRemoveWhiteSpace(In); AtDebugOut(In); /* Commands we process must start with "AT" and end with <cr> */ if (((In->buff[In->readOffset] != 'A') && (In->buff[In->readOffset] != 'a')) || ((In->buff[In->readOffset + 1] != 'T') && (In->buff[In->readOffset + 1] != 't'))) { return AT_STATUS_NOT_FOUND; } len = (In->writeOffset - In->readOffset) - 1; if(len <= 1) { /* It is check alive CMD */ Command->type = AT_CHECK_ALIVE; status = AT_STATUS_OK; goto exit; } /* For efficiency, convert the first 6 characters to uppercase * for case-insensitive comparison with command string table. */ i = min (COMMAND_STAGE_LEN, len); OS_MemSet((U8*)cmdStr, 0, COMMAND_STAGE_LEN); while (i-- > 0) cmdStr[i] = ToUpper(In->buff[In->readOffset + 2 + i]); for (t = 0; (table = AT_CommandTable[t]) != 0; t++) { for (i = 0; table[i]; i++) { if(table[i][0] == 0) continue; for (offset = 0; offset < len; offset++) { if (table[i][offset] == 0) { match = TRUE; break; } if (cmdStr[offset] != table[i][offset]) { break; } } Assert (offset < COMMAND_STAGE_LEN); if (match) { break; } } if (match) { break; } } if (!match) { return AT_STATUS_NOT_FOUND; } In->readOffset += offset + 2; /* Skip over 'AT'<command type> */ Command->type = (AtCommand)(i | (0x0100 * t)); /* Check for Test and Read commands. */ len = In->writeOffset - In->readOffset; if (((len == 1) || (len == 2)) && (In->buff[In->writeOffset - 1] == '?')) { if (In->buff[In->readOffset] == '=') Command->type |= AT_TEST; else Command->type |= AT_READ; In->readOffset += len; status = AT_STATUS_OK; goto exit; } else if (len && (In->buff[In->readOffset] == '=')) { /* Strip off equals sign between command and value */ In->readOffset++; } Assert(In->readOffset <= In->writeOffset); switch (t) { case 0: status = ME_Decode_Common(Atc, &Command->type, Command, In); break; #if AT_HEADSET == XA_ENABLED case 1: status = ME_Decode_Headset(Atc, &Command->type, &Command->p.hs, In); break; #endif /* AT_HEADSET == XA_ENABLED */ #if AT_HANDSFREE == XA_ENABLED case 2: status = ME_Decode_Handsfree(Atc, &Command->type, &Command->p.hf, In); break; #endif /* AT_HANDSFREE == XA_ENABLED */ #if AT_PHONEBOOK == XA_ENABLED case 3: status = ME_Decode_Phonebook(Atc, &Command->type, &Command->p.pb, In); break; #endif /* AT_PHONEBOOK == XA_ENABLED */ #if AT_SMS == XA_ENABLED case 4: status = ME_Decode_Sms(Atc, &Command->type, &Command->p.sms, In); break; #endif /* AT_SMS == XA_ENABLED */ default: Assert(0); break; } exit: if(status != AT_STATUS_CONTINUE) In->readOffset = In->writeOffset = 0; else Command->bContinue = TRUE; return status; }
/*--------------------------------------------------------------------------- * ME_Encode * * This function encodes an AT result for transmission to the device (TE). */ AtStatus ME_Encode(AtContext *Atc, const AtResults *Result, XaBufferDesc *Out) { const char *cmdStr = 0; AtCommand idx, grp; U16 len; AtStatus status = AT_STATUS_INVALID_PARM; CheckUnlockedParm(AT_STATUS_INVALID_PARM, (Atc && Result && Out)); idx = (Result->type & 0x00ff); grp = (Result->type & 0x0f00) >> 8; if (idx > Atc->lastCmd[grp] || grp >= AT_NUM_GROUPS) { return AT_STATUS_NOT_FOUND; } cmdStr = AT_CommandTable[grp][(idx)]; len = OS_StrLen(cmdStr); /* Check space for "AT"<base command>"="<cr> */ /* Check space for <cr><lf><base command>":"<cr><lf> */ CheckUnlockedParm(AT_STATUS_NO_RESOURCES, (Out->buffSize - Out->writeOffset) > (len + 6)); Out->buff[Out->writeOffset++] = '\r'; Out->buff[Out->writeOffset++] = '\n'; OS_MemCopy(Out->buff + Out->writeOffset, (const U8 *)cmdStr, len); Out->writeOffset += len; Out->buff[Out->writeOffset++] = ':'; Out->buff[Out->writeOffset++] = ' '; /* Required by some Ericsson handsets */ switch (Result->type & 0x0f00) { case AT_GROUP_COMMON: status = ME_Encode_Common(Atc, Result->type, Result, Out); break; #if AT_HEADSET == XA_ENABLED case AT_GROUP_HEADSET: status = ME_Encode_Headset(Atc, Result->type, &Result->p.hs, Out); break; #endif /* AT_HEADSET == XA_ENABLED */ #if AT_HANDSFREE == XA_ENABLED case AT_GROUP_HANDSFREE: status = ME_Encode_Handsfree(Atc, Result->type, &Result->p.hf, Out); break; #endif /* AT_HANDSFREE == XA_ENABLED */ #if AT_PHONEBOOK == XA_ENABLED case AT_GROUP_PHONEBOOK: status = ME_Encode_Phonebook(Atc, Result->type, &Result->p.pb, Out); break; #endif /* AT_PHONEBOOK == XA_ENABLED */ #if AT_SMS == XA_ENABLED case AT_GROUP_SMS: status = ME_Encode_Sms(Atc, Result->type, &Result->p.sms, Out); break; #endif default: Assert(0); break; } if ((status == AT_STATUS_OK) && (Result->type != AT_RAW)) { Out->buff[Out->writeOffset++] = '\r'; Out->buff[Out->writeOffset++] = '\n'; } return status; }
/*--------------------------------------------------------------------------- * TE_Decode * * This function decodes an AT result received by the device (TE). */ AtStatus TE_Decode(AtContext *Atc, AtResults *Result, XaBufferDesc *In) { I8 i, t, skip; U16 len, offset; BOOL match = FALSE; const char **table; char resultStr[RESULT_STAGE_LEN]; AtStatus status = AT_STATUS_INVALID_PARM; CheckUnlockedParm(AT_STATUS_INVALID_PARM, (Atc && Result && In)); OS_MemSet((U8 *)Result, 0, sizeof(AtResults)); AtRemoveWhiteSpace(In); AtDebugOut(In); len = In->writeOffset - In->readOffset; /* For efficiency, convert the first 15 characters to uppercase * for case-insensitive comparison with command string table. */ i = min (RESULT_STAGE_LEN, len); OS_MemSet((U8*)resultStr, 0, RESULT_STAGE_LEN); while (i-- > 0) resultStr[i] = ToUpper(In->buff[In->readOffset + i]); for (t = 0; (table = AT_CommandTable[t]) != 0; t++) { for (skip = 0, i = 0; table[i]; i++) { for (offset = 0; (offset < len) || table[i][offset + skip] == 0; offset++) { if (table[i][offset + skip] == 0) { match = TRUE; break; } if (resultStr[offset] != table[i][offset + skip]) { /* We've hit a mismatch. If the StrTable entry has a space, * then it's been compressed out of the input buffer so skip it. */ if ((table[i][offset] != ' ') || (resultStr[offset] != table[i][offset + skip + 1])) { break; } skip += 1; } } Assert (offset < RESULT_STAGE_LEN); if (match) break; } if (match) break; } if (!match) { return AT_STATUS_NOT_FOUND; } In->readOffset += offset; /* Skip over <command type> */ Result->type = (AtCommand)(i | (0x0100 * t)); /* Strip the ':' between the command and the parameters. */ if ((In->writeOffset > In->readOffset) && (In->buff[In->readOffset] == ':')) In->readOffset++; Assert(In->readOffset <= In->writeOffset); switch (t) { case 0: status = TE_Decode_Common(Atc, &Result->type, Result, In); break; #if AT_HEADSET == XA_ENABLED case 1: status = TE_Decode_Headset(Atc, &Result->type, &Result->p.hs, In); break; #endif /* AT_HEADSET == XA_ENABLED */ #if AT_HANDSFREE == XA_ENABLED case 2: status = TE_Decode_Handsfree(Atc, &Result->type, &Result->p.hf, In); break; #endif /* AT_HANDSFREE == XA_ENABLED */ #if AT_PHONEBOOK == XA_ENABLED case 3: status = TE_Decode_Phonebook(Atc, &Result->type, &Result->p.pb, In); break; #endif /* AT_PHONEBOOK == XA_ENABLED */ default: Assert(0); break; } In->readOffset = In->writeOffset = 0; return status; }
/*--------------------------------------------------------------------------- * TE_Encode * * This function encodes an AT command for transmission to the gateway (ME). */ AtStatus TE_Encode(AtContext *Atc, const AtCommands *Command, XaBufferDesc *Out) { AtStatus status; const char *cmdStr = 0; U8 idx, grp; U16 len; CheckUnlockedParm(AT_STATUS_INVALID_PARM, Atc && Command && Out); idx = (Command->type & 0x00ff); grp = (Command->type & 0x0f00) >> 8; if (idx > Atc->lastCmd[grp]) { return AT_STATUS_NOT_FOUND; } cmdStr = AT_CommandTable[grp][(idx)]; len = OS_StrLen(cmdStr); /* Check space for "AT"<base command>"="<cr> */ CheckUnlockedParm(AT_STATUS_NO_RESOURCES, (Out->buffSize - Out->writeOffset) > (len + 4)); Out->buff[Out->writeOffset++] = 'A'; Out->buff[Out->writeOffset++] = 'T'; OS_MemCopy(Out->buff + Out->writeOffset, (const U8*)cmdStr, len); Out->writeOffset += len; Out->buff[Out->writeOffset++] = '='; switch (Command->type & 0xff00) { case AT_GROUP_COMMON: status = TE_Encode_Common(Atc, Command->type, Command, Out); break; #if AT_HEADSET == XA_ENABLED case AT_GROUP_HEADSET: status = TE_Encode_Headset(Atc, Command->type, &Command->p.hs, Out); break; #endif /* AT_HEADSET == XA_ENABLED */ #if AT_HANDSFREE == XA_ENABLED case AT_GROUP_HANDSFREE: status = TE_Encode_Handsfree(Atc, Command->type, &Command->p.hf, Out); break; #endif /* AT_HANDSFREE == XA_ENABLED */ #if AT_PHONEBOOK == XA_ENABLED case AT_GROUP_PHONEBOOK: status = TE_Encode_Phonebook(Atc, Command->type, &Command->p.pb, Out); break; #endif /* AT_HANDSFREE == XA_ENABLED */ default: if (Command->type & AT_TEST) { if ((Out->buffSize - Out->writeOffset) < 1) { return AT_STATUS_NO_RESOURCES; } } else if (Command->type & AT_READ) { Out->writeOffset--; /* remove the '=' */ } else { Assert(0); return AT_STATUS_NOT_SUPPORTED; } Out->buff[Out->writeOffset++] = '?'; status = AT_STATUS_OK; break; } if (status == AT_STATUS_OK) Out->buff[Out->writeOffset++] = '\r'; return status; }
/*--------------------------------------------------------------------------- * OBEXH_ParseTlv *--------------------------------------------------------------------------- * * Synopsis: Sniffs out a TLV from the current header * * Return: TRUE if parsing was successful. * FALSE if an error occurred or no more TLVs are present. */ BOOL OBEXH_ParseTlv(ObexAppHandle *AppHndl, ObexTlv *tlv) { U8 *buffer; U16 len; U8 toUse; BOOL success = FALSE; CheckUnlockedParm(FALSE, AppHndl && tlv); OS_LockObex(); /* On the first OBxx_HEADER_RX indication there is no data available. * Use this event to initialize the parser. */ if (AppHndl->parser.dataLen == 0) { /* ASSERT that we are in the correct internal state to parse * this header, and that it is a byte sequence header */ ASSERT((AppHndl->parser).rxState == OBSC_RX_PUT_HEAD2); ASSERT(((AppHndl->parser).header & 0xC0) == 0x40); /* Initialize key fields */ AppHndl->tlv.state = 0; buffer = 0; len = 0; goto Done; } /* Use these locals as aliases for the AppHndl fields */ buffer = AppHndl->tlv.headerBuff; len = AppHndl->tlv.headerLen; if (buffer == 0) { buffer = AppHndl->parser.rxBuff; len = AppHndl->parser.dataLen; } while (len) { switch (AppHndl->tlv.state) { case 0: /* Buff points to option type */ AppHndl->tlv.tag = *buffer++; AppHndl->tlv.state = 1; len--; break; case 1: /* Buff points to option length */ AppHndl->tlv.length = *buffer++; AppHndl->tlv.state = 2; AppHndl->tlv.valuePos = 0; len--; /* No break; fall through to handle option data */ case 2: /* Update length of option data we currently need. */ toUse = min(AppHndl->tlv.length - AppHndl->tlv.valuePos, len); /* Fill in tlv values in case they are necessary */ tlv->tag = AppHndl->tlv.tag; tlv->length = AppHndl->tlv.length; /* Is reassembly both necessary and possible for this TLV? */ #if OBEX_TLV_BUFF_SIZE > 0 if ((toUse < AppHndl->tlv.length) && (AppHndl->tlv.length < OBEX_TLV_BUFF_SIZE)) { /* Append recevied data into our staging buffer */ OS_MemCopy(AppHndl->tlv.value + AppHndl->tlv.valuePos, buffer, toUse); AppHndl->tlv.valuePos += toUse; tlv->value = AppHndl->tlv.value; tlv->valueLen = AppHndl->tlv.length; len -= toUse; buffer += toUse; /* Indicate success ONLY if we have completed staging */ tlv->remainLen = (tlv->length - AppHndl->tlv.valuePos); success = (tlv->remainLen == 0); } else { #endif /* OBEX_TLV_BUFF_SIZE > 0 */ /* If reassembly is impossible or unnecessary, simply copy * tag information */ tlv->value = buffer; tlv->valueLen = toUse; AppHndl->tlv.valuePos += toUse; len -= toUse; buffer += toUse; /* Indicate "last" if we are indicating the last chunk of bytes * as counted by valuePos */ tlv->remainLen = (tlv->length - AppHndl->tlv.valuePos); /* Indicate success because staging isn't going to happen */ success = TRUE; #if OBEX_TLV_BUFF_SIZE > 0 } #endif /* OBEX_TLV_BUFF_SIZE > 0 */ if (success) { /* If we have reached the end of the tlv then reset state for * next time */ if (tlv->remainLen == 0) { AppHndl->tlv.state = 0; } goto Done; } break; } } /* If control gets here we have exhausted the buffer */ buffer = 0; Done: /* Reset buffer/length from locals and return success */ AppHndl->tlv.headerBuff = buffer; AppHndl->tlv.headerLen = len; OS_UnlockObex(); return success; }