1 /**************************************************************************************************
2 * Filename: interface_devicelist.c
3 * Description: Socket Remote Procedure Call Interface - sample device application.
4 *
5 *
6 * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
7 *
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the
19 * distribution.
20 *
21 * Neither the name of Texas Instruments Incorporated nor the names of
22 * its contributors may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 */
39 /*********************************************************************
40 * INCLUDES
41 */
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
47 #include "interface_grouplist.h"
48 #include "hal_types.h"
49 #include "SimpleDBTxt.h"
51 static db_descriptor * db;
53 /*********************************************************************
54 * TYPEDEFS
55 */
57 void groupListInitDatabase(char * dbFilename)
58 {
59 db = sdb_init_db(dbFilename, sdbtGetRecordSize, sdbtCheckDeleted,
60 sdbtCheckIgnored, sdbtMarkDeleted,
61 (consolidation_processing_f) sdbtErrorComment, SDB_TYPE_TEXT, 0);
62 sdb_consolidate_db(&db);
63 }
65 static char * groupListComposeRecord(groupRecord_t *group, char * record)
66 {
67 groupMembersRecord_t *groupMembers;
69 sprintf(record, " 0x%04X , \"%s\"", //leave a space at the beginning to mark this record as deleted if needed later, or as bad format (can happen if edited manually). Another space to write the reason of bad format.
70 group->id, group->name ? group->name : "");
72 groupMembers = group->members;
74 while (groupMembers != NULL)
75 {
76 sprintf(record + strlen(record), " , 0x%04X , 0x%02X",
77 groupMembers->nwkAddr, groupMembers->endpoint);
78 groupMembers = groupMembers->next;
79 }
81 sprintf(record + strlen(record), "\n");
83 return record;
84 }
86 #define MAX_SUPPORTED_GROUP_NAME_LENGTH 32
87 #define MAX_SUPPORTED_GROUP_MEMBERS 20
89 static groupRecord_t * groupListParseRecord(char * record)
90 {
91 char * pBuf = record + 1; //+1 is to ignore the 'for deletion' mark that may just be added to this record.
92 static groupRecord_t group;
93 static char groupName[MAX_SUPPORTED_GROUP_NAME_LENGTH + 1];
94 static groupMembersRecord_t member[MAX_SUPPORTED_GROUP_MEMBERS];
95 groupMembersRecord_t ** nextMemberPtr;
96 parsingResult_t parsingResult =
97 { SDB_TXT_PARSER_RESULT_OK, 0 };
98 int i;
100 if (record == NULL)
101 {
102 return NULL;
103 }
105 sdb_txt_parser_get_numeric_field(&pBuf, (uint8_t *) &group.id, 2, FALSE,
106 &parsingResult);
107 sdb_txt_parser_get_quoted_string(&pBuf, groupName,
108 MAX_SUPPORTED_GROUP_NAME_LENGTH, &parsingResult);
109 nextMemberPtr = &group.members;
110 for (i = 0;
111 (parsingResult.code == SDB_TXT_PARSER_RESULT_OK)
112 && (i < MAX_SUPPORTED_GROUP_MEMBERS); i++)
113 {
114 *nextMemberPtr = &(member[i]);
115 sdb_txt_parser_get_numeric_field(&pBuf, (uint8_t *) &(member[i].nwkAddr), 2,
116 FALSE, &parsingResult);
117 sdb_txt_parser_get_numeric_field(&pBuf, (uint8_t *) &(member[i].endpoint),
118 1, FALSE, &parsingResult);
119 nextMemberPtr = &(member[i].next);
120 }
121 *nextMemberPtr = NULL;
123 if ((parsingResult.code != SDB_TXT_PARSER_RESULT_OK)
124 && (parsingResult.code != SDB_TXT_PARSER_RESULT_REACHED_END_OF_RECORD))
125 {
126 sdbtMarkError(db, record, &parsingResult);
127 return NULL;
128 }
130 if (strlen(groupName) > 0)
131 {
132 group.name = groupName;
133 }
134 else
135 {
136 group.name = NULL;
137 }
139 return &group;
140 }
142 static int groupListCheckKeyName(char * record, char * key)
143 {
144 groupRecord_t * group;
145 int result = SDB_CHECK_KEY_NOT_EQUAL;
147 group = groupListParseRecord(record);
148 if (group == NULL)
149 {
150 return SDB_CHECK_KEY_ERROR;
151 }
153 if (strcmp(group->name, key) == 0)
154 {
155 result = SDB_CHECK_KEY_EQUAL;
156 }
158 return result;
159 }
161 static int groupListCheckKeyId(char * record, uint16_t * key)
162 {
163 groupRecord_t * group;
164 int result = SDB_CHECK_KEY_NOT_EQUAL;
166 group = groupListParseRecord(record);
167 if (group == NULL)
168 {
169 return SDB_CHECK_KEY_ERROR;
170 }
172 if (group->id == *key)
173 {
174 result = SDB_CHECK_KEY_EQUAL;
175 }
177 return result;
178 }
180 groupRecord_t * groupListGetGroupByName(char * groupName)
181 {
182 char * rec;
184 rec = SDB_GET_UNIQUE_RECORD(db, groupName, (check_key_f)groupListCheckKeyName);
185 if (rec == NULL)
186 {
187 return NULL;
188 }
190 return groupListParseRecord(rec);
191 }
193 uint16_t groupListGetUnusedGroupId(void)
194 {
195 static uint16_t lastUsedGroupId = 0;
197 lastUsedGroupId++;
199 while (SDB_GET_UNIQUE_RECORD(db, &lastUsedGroupId, (check_key_f)groupListCheckKeyId)
200 != NULL)
201 {
202 lastUsedGroupId++;
203 }
205 return lastUsedGroupId;
206 }
208 uint16_t groupListAddGroup(char *groupNameStr)
209 {
210 groupRecord_t *exsistingGroup;
211 groupRecord_t newGroup;
212 char rec[MAX_SUPPORTED_RECORD_SIZE];
214 //printf("groupListAddGroup++\n");
216 exsistingGroup = groupListGetGroupByName(groupNameStr);
218 if (exsistingGroup != NULL)
219 {
220 return exsistingGroup->id;
221 }
223 newGroup.id = groupListGetUnusedGroupId();
224 newGroup.name = groupNameStr;
225 newGroup.members = NULL;
227 groupListComposeRecord(&newGroup, rec);
229 sdb_add_record(db, rec);
231 //printf("groupListAddGroup--\n");
233 return newGroup.id;
234 }
236 groupRecord_t * groupListRemoveGroupByName(char * groupName)
237 {
238 return groupListParseRecord(
239 sdb_delete_record(db, groupName, (check_key_f) groupListCheckKeyName));
240 }
242 uint16_t groupListAddDeviceToGroup(char *groupNameStr, uint16_t nwkAddr,
243 uint8_t endpoint)
244 {
245 groupRecord_t *group;
246 groupRecord_t newGroup;
247 char rec[MAX_SUPPORTED_RECORD_SIZE];
248 groupMembersRecord_t ** nextMemberPtr;
249 groupMembersRecord_t newMember;
250 bool memberExists = FALSE;
251 uint16_t groupId;
253 //printf("groupListAddGroup++\n");
255 group = groupListGetGroupByName(groupNameStr);
257 if (group == NULL)
258 {
259 group = &newGroup;
260 group->id = groupListGetUnusedGroupId();
261 group->name = groupNameStr;
262 group->members = NULL;
263 }
265 groupId = group->id;
267 nextMemberPtr = &(group->members);
268 while ((*nextMemberPtr != NULL) && (!memberExists))
269 {
270 if (((*nextMemberPtr)->nwkAddr == nwkAddr)
271 && ((*nextMemberPtr)->endpoint == endpoint))
272 {
273 memberExists = TRUE;
274 }
275 else
276 {
277 nextMemberPtr = &((*nextMemberPtr)->next);
278 }
279 }
281 if (!memberExists)
282 {
283 *nextMemberPtr = &newMember;
284 newMember.nwkAddr = nwkAddr;
285 newMember.endpoint = endpoint;
286 newMember.next = NULL;
287 groupListComposeRecord(group, rec);
288 groupListRemoveGroupByName(groupNameStr);
289 sdb_add_record(db, rec);
290 }
292 //printf("groupListAddGroup--\n");
294 return groupId;
295 }
297 groupRecord_t * groupListGetNextGroup(uint32_t *context)
298 {
299 char * rec;
300 groupRecord_t *group;
302 do
303 {
304 rec = SDB_GET_NEXT_RECORD(db,context);
306 if (rec == NULL)
307 {
308 return NULL;
309 }
311 group = groupListParseRecord(rec);
312 }
313 while (group == NULL); //in case of a bad-format record - skip it and read the next one
315 return group;
316 }