• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "nanoapp_cmd"
18 
19 #include <assert.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <inttypes.h>
23 #include <signal.h>
24 #include <stdbool.h>
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <string.h>
31 #include <unistd.h>
32 
33 #include <android/log.h>
34 
35 #include <nanohub/nanohub.h>
36 #include <eventnums.h>
37 #include <sensType.h>
38 
39 #define SENSOR_RATE_ONCHANGE    0xFFFFFF01UL
40 #define SENSOR_RATE_ONESHOT     0xFFFFFF02UL
41 #define SENSOR_HZ(_hz)          ((uint32_t)((_hz) * 1024.0f))
42 #define MAX_APP_NAME_LEN        32
43 #define MAX_INSTALL_CNT         8
44 #define MAX_UNINSTALL_CNT       8
45 #define MAX_DOWNLOAD_RETRIES    4
46 #define UNINSTALL_CMD           "uninstall"
47 
48 #define NANOHUB_EXT_APP_DELETE  2
49 
50 #define LOGE(fmt, ...) do { \
51         __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##__VA_ARGS__); \
52         printf(fmt "\n", ##__VA_ARGS__); \
53     } while (0)
54 
55 enum ConfigCmds
56 {
57     CONFIG_CMD_DISABLE      = 0,
58     CONFIG_CMD_ENABLE       = 1,
59     CONFIG_CMD_FLUSH        = 2,
60     CONFIG_CMD_CFG_DATA     = 3,
61     CONFIG_CMD_CALIBRATE    = 4,
62 };
63 
64 struct ConfigCmd
65 {
66     uint32_t evtType;
67     uint64_t latency;
68     uint32_t rate;
69     uint8_t sensorType;
70     uint8_t cmd;
71     uint16_t flags;
72     uint8_t data[];
73 } __attribute__((packed));
74 
75 struct App
76 {
77     uint32_t num;
78     uint64_t id;
79     uint32_t version;
80     uint32_t size;
81 };
82 
83 struct LedsCfg {
84     uint32_t led_num;
85     uint32_t value;
86 } __attribute__((packed));
87 
setType(struct ConfigCmd * cmd,char * sensor)88 static int setType(struct ConfigCmd *cmd, char *sensor)
89 {
90     if (strcmp(sensor, "accel") == 0) {
91         cmd->sensorType = SENS_TYPE_ACCEL;
92     } else if (strcmp(sensor, "gyro") == 0) {
93         cmd->sensorType = SENS_TYPE_GYRO;
94     } else if (strcmp(sensor, "mag") == 0) {
95         cmd->sensorType = SENS_TYPE_MAG;
96     } else if (strcmp(sensor, "uncal_gyro") == 0) {
97         cmd->sensorType = SENS_TYPE_GYRO;
98     } else if (strcmp(sensor, "uncal_mag") == 0) {
99         cmd->sensorType = SENS_TYPE_MAG;
100     } else if (strcmp(sensor, "als") == 0) {
101         cmd->sensorType = SENS_TYPE_ALS;
102     } else if (strcmp(sensor, "prox") == 0) {
103         cmd->sensorType = SENS_TYPE_PROX;
104     } else if (strcmp(sensor, "baro") == 0) {
105         cmd->sensorType = SENS_TYPE_BARO;
106     } else if (strcmp(sensor, "temp") == 0) {
107         cmd->sensorType = SENS_TYPE_TEMP;
108     } else if (strcmp(sensor, "orien") == 0) {
109         cmd->sensorType = SENS_TYPE_ORIENTATION;
110     } else if (strcmp(sensor, "gravity") == 0) {
111         cmd->sensorType = SENS_TYPE_GRAVITY;
112     } else if (strcmp(sensor, "geomag") == 0) {
113         cmd->sensorType = SENS_TYPE_GEO_MAG_ROT_VEC;
114     } else if (strcmp(sensor, "linear_acc") == 0) {
115         cmd->sensorType = SENS_TYPE_LINEAR_ACCEL;
116     } else if (strcmp(sensor, "rotation") == 0) {
117         cmd->sensorType = SENS_TYPE_ROTATION_VECTOR;
118     } else if (strcmp(sensor, "game") == 0) {
119         cmd->sensorType = SENS_TYPE_GAME_ROT_VECTOR;
120     } else if (strcmp(sensor, "win_orien") == 0) {
121         cmd->sensorType = SENS_TYPE_WIN_ORIENTATION;
122         cmd->rate = SENSOR_RATE_ONCHANGE;
123     } else if (strcmp(sensor, "tilt") == 0) {
124         cmd->sensorType = SENS_TYPE_TILT;
125         cmd->rate = SENSOR_RATE_ONCHANGE;
126     } else if (strcmp(sensor, "step_det") == 0) {
127         cmd->sensorType = SENS_TYPE_STEP_DETECT;
128         cmd->rate = SENSOR_RATE_ONCHANGE;
129     } else if (strcmp(sensor, "step_cnt") == 0) {
130         cmd->sensorType = SENS_TYPE_STEP_COUNT;
131         cmd->rate = SENSOR_RATE_ONCHANGE;
132     } else if (strcmp(sensor, "double_tap") == 0) {
133         cmd->sensorType = SENS_TYPE_DOUBLE_TAP;
134         cmd->rate = SENSOR_RATE_ONCHANGE;
135     } else if (strcmp(sensor, "flat") == 0) {
136         cmd->sensorType = SENS_TYPE_FLAT;
137         cmd->rate = SENSOR_RATE_ONCHANGE;
138     } else if (strcmp(sensor, "anymo") == 0) {
139         cmd->sensorType = SENS_TYPE_ANY_MOTION;
140         cmd->rate = SENSOR_RATE_ONCHANGE;
141     } else if (strcmp(sensor, "nomo") == 0) {
142         cmd->sensorType = SENS_TYPE_NO_MOTION;
143         cmd->rate = SENSOR_RATE_ONCHANGE;
144     } else if (strcmp(sensor, "sigmo") == 0) {
145         cmd->sensorType = SENS_TYPE_SIG_MOTION;
146         cmd->rate = SENSOR_RATE_ONESHOT;
147     } else if (strcmp(sensor, "gesture") == 0) {
148         cmd->sensorType = SENS_TYPE_GESTURE;
149         cmd->rate = SENSOR_RATE_ONESHOT;
150     } else if (strcmp(sensor, "hall") == 0) {
151         cmd->sensorType = SENS_TYPE_HALL;
152         cmd->rate = SENSOR_RATE_ONCHANGE;
153     } else if (strcmp(sensor, "vsync") == 0) {
154         cmd->sensorType = SENS_TYPE_VSYNC;
155         cmd->rate = SENSOR_RATE_ONCHANGE;
156     } else if (strcmp(sensor, "activity") == 0) {
157         cmd->sensorType = SENS_TYPE_ACTIVITY;
158         cmd->rate = SENSOR_RATE_ONCHANGE;
159     } else if (strcmp(sensor, "twist") == 0) {
160         cmd->sensorType = SENS_TYPE_DOUBLE_TWIST;
161         cmd->rate = SENSOR_RATE_ONCHANGE;
162     } else if (strcmp(sensor, "leds") == 0) {
163         cmd->sensorType = SENS_TYPE_LEDS;
164     } else if (strcmp(sensor, "leds_i2c") == 0) {
165         cmd->sensorType = SENS_TYPE_LEDS_I2C;
166     } else if (strcmp(sensor, "humidity") == 0) {
167         cmd->sensorType = SENS_TYPE_HUMIDITY;
168     } else {
169         return 1;
170     }
171 
172     return 0;
173 }
174 
175 bool drain = false;
176 bool stop = false;
177 char *buf;
178 int nread, buf_size = 2048;
179 struct App apps[32];
180 uint8_t appCount;
181 char appsToInstall[MAX_INSTALL_CNT][MAX_APP_NAME_LEN+1];
182 uint64_t appsToUninstall[MAX_UNINSTALL_CNT];
183 
sig_handle(int sig)184 void sig_handle(__attribute__((unused)) int sig)
185 {
186     assert(sig == SIGINT);
187     printf("Terminating...\n");
188     stop = true;
189 }
190 
openFile(const char * fname,const char * mode)191 FILE *openFile(const char *fname, const char *mode)
192 {
193     FILE *f = fopen(fname, mode);
194     if (f == NULL) {
195         LOGE("Failed to open %s: err=%d [%s]", fname, errno, strerror(errno));
196     }
197     return f;
198 }
199 
parseInstalledAppInfo()200 void parseInstalledAppInfo()
201 {
202     FILE *fp;
203     char *line = NULL;
204     size_t len;
205     ssize_t numRead;
206 
207     appCount = 0;
208 
209     fp = openFile("/sys/class/nanohub/nanohub/app_info", "r");
210     if (!fp)
211         return;
212 
213     while ((numRead = getline(&line, &len, fp)) != -1) {
214         struct App *currApp = &apps[appCount++];
215         sscanf(line, "app: %d id: %" PRIx64 " ver: %" PRIx32 " size: %" PRIx32 "\n", &currApp->num, &currApp->id, &currApp->version, &currApp->size);
216     }
217 
218     fclose(fp);
219 
220     if (line)
221         free(line);
222 }
223 
findApp(uint64_t appId)224 struct App *findApp(uint64_t appId)
225 {
226     uint8_t i;
227 
228     for (i = 0; i < appCount; i++) {
229         if (apps[i].id == appId) {
230             return &apps[i];
231         }
232     }
233 
234     return NULL;
235 }
236 
parseConfigAppInfo(int * installCnt,int * uninstallCnt)237 int parseConfigAppInfo(int *installCnt, int *uninstallCnt)
238 {
239     FILE *fp;
240     char *line = NULL;
241     size_t len;
242     ssize_t numRead;
243 
244     fp = openFile("/vendor/firmware/napp_list.cfg", "r");
245     if (!fp)
246         return -1;
247 
248     parseInstalledAppInfo();
249 
250     *installCnt = *uninstallCnt = 0;
251     while (((numRead = getline(&line, &len, fp)) != -1) && (*installCnt < MAX_INSTALL_CNT) && (*uninstallCnt < MAX_UNINSTALL_CNT)) {
252         uint64_t appId;
253         uint32_t appVersion;
254         struct App *installedApp;
255 
256         sscanf(line, "%" STRINGIFY(MAX_APP_NAME_LEN) "s %" PRIx64 " %" PRIx32 "\n", appsToInstall[*installCnt], &appId, &appVersion);
257 
258         installedApp = findApp(appId);
259         if (strncmp(appsToInstall[*installCnt], UNINSTALL_CMD, MAX_APP_NAME_LEN) == 0) {
260             if (installedApp) {
261                 appsToUninstall[*uninstallCnt] = appId;
262                 (*uninstallCnt)++;
263             }
264         } else if (!installedApp || (installedApp->version < appVersion)) {
265             (*installCnt)++;
266         }
267     }
268 
269     fclose(fp);
270 
271     if (line)
272         free(line);
273 
274     return *installCnt + *uninstallCnt;
275 }
276 
fileWriteData(const char * fname,const void * data,size_t size)277 bool fileWriteData(const char *fname, const void *data, size_t size)
278 {
279     int fd;
280     bool result;
281 
282     fd = open(fname, O_WRONLY);
283     if (fd < 0) {
284         LOGE("Failed to open %s: err=%d [%s]", fname, errno, strerror(errno));
285         return false;
286     }
287 
288     result = true;
289     if ((size_t)write(fd, data, size) != size) {
290         LOGE("Failed to write to %s; err=%d [%s]", fname, errno, strerror(errno));
291         result = false;
292     }
293     close(fd);
294 
295     return result;
296 }
297 
downloadNanohub()298 void downloadNanohub()
299 {
300     char c = '1';
301 
302     printf("Updating nanohub OS [if required]...");
303     fflush(stdout);
304     if (fileWriteData("/sys/class/nanohub/nanohub/download_bl", &c, sizeof(c)))
305         printf("done\n");
306 }
307 
removeApps(int updateCnt)308 void removeApps(int updateCnt)
309 {
310     uint8_t buffer[sizeof(struct HostMsgHdr) + 1 + sizeof(uint64_t)];
311     struct HostMsgHdr *mHostMsgHdr = (struct HostMsgHdr *)(&buffer[0]);
312     uint8_t *cmd = (uint8_t *)(&buffer[sizeof(struct HostMsgHdr)]);
313     uint64_t *appId = (uint64_t *)(&buffer[sizeof(struct HostMsgHdr) + 1]);
314     int i;
315 
316     for (i = 0; i < updateCnt; i++) {
317         mHostMsgHdr->eventId = EVT_APP_FROM_HOST;
318         mHostMsgHdr->appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0);
319         mHostMsgHdr->len = 1 + sizeof(uint64_t);
320         *cmd = NANOHUB_EXT_APP_DELETE;
321         memcpy(appId, &appsToUninstall[i], sizeof(uint64_t));
322         printf("Deleting \"%016" PRIx64 "\"...", appsToUninstall[i]);
323         fflush(stdout);
324         if (fileWriteData("/dev/nanohub", buffer, sizeof(buffer)))
325             printf("done\n");
326     }
327 }
328 
downloadApps(int updateCnt)329 void downloadApps(int updateCnt)
330 {
331     int i;
332 
333     for (i = 0; i < updateCnt; i++) {
334         printf("Downloading \"%s.napp\"...", appsToInstall[i]);
335         fflush(stdout);
336         if (fileWriteData("/sys/class/nanohub/nanohub/download_app", appsToInstall[i], strlen(appsToInstall[i])))
337             printf("done\n");
338     }
339 }
340 
eraseSharedArea()341 void eraseSharedArea()
342 {
343     char c = '1';
344 
345     printf("Erasing entire nanohub shared area...");
346     fflush(stdout);
347     if (fileWriteData("/sys/class/nanohub/nanohub/erase_shared", &c, sizeof(c)))
348         printf("done\n");
349 }
350 
resetHub()351 void resetHub()
352 {
353     char c = '1';
354 
355     printf("Resetting nanohub...");
356     fflush(stdout);
357     if (fileWriteData("/sys/class/nanohub/nanohub/reset", &c, sizeof(c)))
358         printf("done\n");
359 }
360 
main(int argc,char * argv[])361 int main(int argc, char *argv[])
362 {
363     struct ConfigCmd mConfigCmd;
364     struct ConfigCmd *pConfigCmd = &mConfigCmd;
365     size_t length = sizeof(mConfigCmd);
366     int fd;
367     int i;
368 
369     if (argc < 3 && (argc < 2 || strcmp(argv[1], "download") != 0)) {
370         printf("usage: %s <action> <sensor> <data> -d\n", argv[0]);
371         printf("       action: config|cfgdata|calibrate|flush|download\n");
372         printf("       sensor: accel|(uncal_)gyro|(uncal_)mag|als|prox|baro|temp|orien\n");
373         printf("               gravity|geomag|linear_acc|rotation|game\n");
374         printf("               win_orien|tilt|step_det|step_cnt|double_tap\n");
375         printf("               flat|anymo|nomo|sigmo|gesture|hall|vsync\n");
376         printf("               activity|twist|leds|leds_i2c|humidity\n");
377         printf("       data: config: <true|false> <rate in Hz> <latency in u-sec>\n");
378         printf("             cfgdata: leds: led_num value\n");
379         printf("             calibrate: [N.A.]\n");
380         printf("             flush: [N.A.]\n");
381         printf("       -d: if specified, %s will keep draining /dev/nanohub until cancelled.\n", argv[0]);
382 
383         return 1;
384     }
385 
386     if (strcmp(argv[1], "config") == 0) {
387         if (argc != 6 && argc != 7) {
388             printf("Wrong arg number\n");
389             return 1;
390         }
391         if (argc == 7) {
392             if(strcmp(argv[6], "-d") == 0) {
393                 drain = true;
394             } else {
395                 printf("Last arg unsupported, ignored.\n");
396             }
397         }
398         if (strcmp(argv[3], "true") == 0)
399             mConfigCmd.cmd = CONFIG_CMD_ENABLE;
400         else if (strcmp(argv[3], "false") == 0) {
401             mConfigCmd.cmd = CONFIG_CMD_DISABLE;
402         } else {
403             printf("Unsupported data: %s For action: %s\n", argv[3], argv[1]);
404             return 1;
405         }
406         mConfigCmd.evtType = EVT_NO_SENSOR_CONFIG_EVENT;
407         mConfigCmd.rate = SENSOR_HZ((float)atoi(argv[4]));
408         mConfigCmd.latency = atoi(argv[5]) * 1000ull;
409         if (setType(&mConfigCmd, argv[2])) {
410             printf("Unsupported sensor: %s For action: %s\n", argv[2], argv[1]);
411             return 1;
412         }
413     } else if (strcmp(argv[1], "cfgdata") == 0) {
414         mConfigCmd.evtType = EVT_NO_SENSOR_CONFIG_EVENT;
415         mConfigCmd.rate = 0;
416         mConfigCmd.latency = 0;
417         mConfigCmd.cmd = CONFIG_CMD_CFG_DATA;
418         if (setType(&mConfigCmd, argv[2])) {
419             printf("Unsupported sensor: %s For action: %s\n", argv[2], argv[1]);
420             return 1;
421         }
422         if (mConfigCmd.sensorType == SENS_TYPE_LEDS ||
423             mConfigCmd.sensorType == SENS_TYPE_LEDS_I2C) {
424             struct LedsCfg mLedsCfg;
425 
426             if (argc != 5) {
427                 printf("Wrong arg number\n");
428                 return 1;
429             }
430             length = sizeof(struct ConfigCmd) + sizeof(struct LedsCfg *);
431             pConfigCmd = (struct ConfigCmd *)malloc(length);
432             if (!pConfigCmd)
433                 return 1;
434             mLedsCfg.led_num = atoi(argv[3]);
435             mLedsCfg.value = atoi(argv[4]);
436             memcpy(pConfigCmd, &mConfigCmd, sizeof(mConfigCmd));
437             memcpy(pConfigCmd->data, &mLedsCfg, sizeof(mLedsCfg));
438         } else {
439             printf("Unsupported sensor: %s For action: %s\n", argv[2], argv[1]);
440             return 1;
441         }
442     } else if (strcmp(argv[1], "calibrate") == 0) {
443         if (argc != 3) {
444             printf("Wrong arg number\n");
445             return 1;
446         }
447         mConfigCmd.evtType = EVT_NO_SENSOR_CONFIG_EVENT;
448         mConfigCmd.rate = 0;
449         mConfigCmd.latency = 0;
450         mConfigCmd.cmd = CONFIG_CMD_CALIBRATE;
451         if (setType(&mConfigCmd, argv[2])) {
452             printf("Unsupported sensor: %s For action: %s\n", argv[2], argv[1]);
453             return 1;
454         }
455     } else if (strcmp(argv[1], "flush") == 0) {
456         if (argc != 3) {
457             printf("Wrong arg number\n");
458             return 1;
459         }
460         mConfigCmd.evtType = EVT_NO_SENSOR_CONFIG_EVENT;
461         mConfigCmd.rate = 0;
462         mConfigCmd.latency = 0;
463         mConfigCmd.cmd = CONFIG_CMD_FLUSH;
464         if (setType(&mConfigCmd, argv[2])) {
465             printf("Unsupported sensor: %s For action: %s\n", argv[2], argv[1]);
466             return 1;
467         }
468     } else if (strcmp(argv[1], "download") == 0) {
469         int installCnt, uninstallCnt;
470 
471         if (argc != 2) {
472             printf("Wrong arg number\n");
473             return 1;
474         }
475         downloadNanohub();
476         for (i = 0; i < MAX_DOWNLOAD_RETRIES; i++) {
477             int updateCnt = parseConfigAppInfo(&installCnt, &uninstallCnt);
478             if (updateCnt > 0) {
479                 if (i == MAX_DOWNLOAD_RETRIES - 1) {
480                     LOGE("Download failed after %d retries; erasing all apps "
481                          "before final attempt", i);
482                     eraseSharedArea();
483                     parseConfigAppInfo(&installCnt, &uninstallCnt);
484                 }
485                 removeApps(uninstallCnt);
486                 downloadApps(installCnt);
487                 resetHub();
488             } else if (!updateCnt){
489                 return 0;
490             }
491         }
492 
493         if (parseConfigAppInfo(&installCnt, &uninstallCnt) != 0) {
494             LOGE("Failed to download all apps!");
495         }
496         return 1;
497     } else {
498         printf("Unsupported action: %s\n", argv[1]);
499         return 1;
500     }
501 
502     while (!fileWriteData("/dev/nanohub", pConfigCmd, length))
503         continue;
504 
505     if (pConfigCmd != &mConfigCmd)
506         free(pConfigCmd);
507 
508     if (drain) {
509         signal(SIGINT, sig_handle);
510         fd = open("/dev/nanohub", O_RDONLY);
511         while (!stop) {
512             (void) read(fd, buf, buf_size);
513         }
514         close(fd);
515     }
516     return 0;
517 }
518