1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <cstring>
17 #include <string>
18 #include "packet.h"
19 #include "hfp_ag_defines.h"
20 #include "hfp_ag_command_parser.h"
21
22
23 namespace OHOS {
24 namespace bluetooth {
GetInstance()25 HfpAgCommandParser &HfpAgCommandParser::GetInstance()
26 {
27 static HfpAgCommandParser instance;
28 return instance;
29 }
30
Read(HfpAgDataConnection & dataConn) const31 void HfpAgCommandParser::Read(HfpAgDataConnection &dataConn) const
32 {
33 Packet *pkt = nullptr;
34 Buffer *buf = nullptr;
35 uint8_t *pData = nullptr;
36
37 dataConn.ReadData(&pkt);
38 if (pkt != nullptr) {
39 auto len = PacketPayloadSize(pkt);
40 buf = PacketContinuousPayload(pkt);
41 pData = (uint8_t *)BufferPtr(buf);
42
43 std::vector<uint8_t> data(pData, pData + len);
44 Parse(dataConn, data, len);
45 PacketFree(pkt);
46 }
47 }
48
Parse(HfpAgDataConnection & dataConn,std::vector<uint8_t> & data,size_t len) const49 void HfpAgCommandParser::Parse(HfpAgDataConnection &dataConn, std::vector<uint8_t> &data, size_t len) const
50 {
51 std::string cmd;
52 std::string arg;
53 size_t cmdLen = 0;
54 int cmdType = HFP_AG_CMD_UNKNOWN;
55
56 if (data.empty() == true) {
57 HILOGI("data is nullptr");
58 return;
59 }
60
61 for (size_t pos = 0; pos < len; pos++) {
62 // skip null characters
63 if (data[pos] == '\0') {
64 continue;
65 }
66 std::vector<uint8_t> partData(data.begin() + pos, data.end());
67 cmdType = Extract(partData, cmd, arg, cmdLen, len - pos);
68 pos += cmdLen;
69 HfpAgCommandProcessor::GetInstance().Handle(dataConn, cmd, arg, cmdType);
70 }
71 return;
72 }
73
Extract(std::vector<uint8_t> & data,std::string & cmd,std::string & arg,size_t & cmdLen,size_t len) const74 int HfpAgCommandParser::Extract(std::vector<uint8_t> &data, std::string &cmd, std::string &arg,
75 size_t &cmdLen, size_t len) const
76 {
77 HfpAgCommandParser::CommandPosition position {0, 0, 0, 0, 0, false, false};
78 GetCommandPosition(data, len, position);
79 HILOGI("headValid: %{public}d, tailValid: %{public}d,"
80 " startPos: %{public}hu, setPos: %{public}hu, getPos: %{public}hu, endPos: %{public}hu",
81 position.headValid,
82 position.tailValid,
83 position.startPos,
84 position.setPos,
85 position.getPos,
86 position.endPos);
87
88 if (!position.headValid || !position.tailValid || position.endPos < HFP_AG_AT_HEAD_SIZE ||
89 (position.setPos >= position.endPos) || (position.getPos >= position.endPos)) {
90 cmdLen = position.pos;
91 HILOGI("HFP_AG_CMD_INVALID");
92 return HFP_AG_CMD_INVALID;
93 }
94
95 int type;
96 cmdLen = position.endPos - position.startPos + 1;
97 // cmd include cmd itself and cmd arguments
98 cmd = std::string((char *)&data[position.startPos], cmdLen);
99 if (cmd.compare(0, ATA_LENGTH, "ATA", 0, ATA_LENGTH) == 0) {
100 type = HFP_AG_CMD_EXEC;
101 cmd = "ATA";
102 } else if (cmd.compare(0, ATD_LENGTH, "ATD", 0, ATD_LENGTH) == 0) {
103 type = HFP_AG_CMD_EXEC;
104 arg = std::string(cmd, ATD_LENGTH, cmd.length() - (ATD_LENGTH - 1));
105 cmd = "ATD";
106 } else if (!position.setPos && !position.getPos) {
107 type = HFP_AG_CMD_EXEC;
108 cmd = cmd.substr(0, cmd.length() - (AT_EXEC_OPERATOR_LENGTH + 1));
109 } else if (!position.setPos && position.getPos) {
110 type = HFP_AG_CMD_GET;
111 cmd = cmd.substr(0, cmd.length() - (AT_GET_OPERATOR_LENGTH + 1));
112 } else if (position.setPos && !position.getPos) {
113 type = HFP_AG_CMD_SET;
114 ExtractArg(cmd, arg);
115 } else if (position.setPos == position.getPos - 1) {
116 type = HFP_AG_CMD_TEST;
117 cmd = cmd.substr(0, cmd.length() - (AT_TEST_OPERATOR_LENGTH + 1));
118 } else {
119 type = HFP_AG_CMD_UNKNOWN;
120 }
121 HILOGI(
122 "cmd: %{public}s, arg: %{public}s, type: %{public}d, cmdLen: %{public}zu",
123 cmd.c_str(), arg.c_str(), type, cmdLen);
124 return type;
125 }
126
GetCommandPosition(const std::vector<uint8_t> & data,size_t len,HfpAgCommandParser::CommandPosition & position) const127 void HfpAgCommandParser::GetCommandPosition(const std::vector<uint8_t> &data,
128 size_t len,
129 HfpAgCommandParser::CommandPosition &position) const
130 {
131 for (position.pos = 0; position.pos < len; position.pos++) {
132 if (data[position.pos] == 'A' || data[position.pos] == 'a') {
133 if ((position.pos + 1 < (int)len) &&
134 ((data[position.pos + 1] == 'T') || (data[position.pos + 1] == 't'))) {
135 position.startPos = position.pos;
136 position.headValid = true;
137 }
138 }
139
140 if (data[position.pos] == '=') {
141 position.setPos = position.pos;
142 }
143 if (data[position.pos] == '?') {
144 position.getPos = position.pos;
145 }
146
147 if (((data[position.pos] == '\r') || (data[position.pos] == '\n')) &&
148 (position.pos > position.startPos) &&
149 (position.headValid)) {
150 position.tailValid = true;
151 position.endPos = position.pos;
152 break;
153 }
154 }
155 }
156
ExtractArg(std::string & cmd,std::string & arg) const157 void HfpAgCommandParser::ExtractArg(std::string &cmd, std::string &arg) const
158 {
159 for (auto it : g_atCmdMap) {
160 if (cmd.find(it.first) != std::string::npos) {
161 // -2 because '\r' and '=' occupied two chars
162 arg = std::string(cmd, it.first.length() + 1,
163 cmd.length() - it.first.length() - (AT_SET_OPERATOR_LENGTH + 1));
164 cmd = it.first;
165 break;
166 }
167 }
168 HILOGI("cmd: %{public}s arg: %{public}s", cmd.c_str(), arg.c_str());
169 }
170 } // namespace bluetooth
171 } // namespace OHOS