1 /*
2  * Copyright (c) 2020-2023 Huawei Device Co., Ltd.
3  *
4  * HDF is dual licensed: you can use it either under the terms of
5  * the GPL, or the BSD license, at your option.
6  * See the LICENSE file in the root of this repository for complete details.
7  */
8 
9 #include "i2c_test.h"
10 #include "hdf_base.h"
11 #include "hdf_io_service_if.h"
12 #include "hdf_log.h"
13 #include "i2c_if.h"
14 #include "osal_mem.h"
15 #include "osal_thread.h"
16 #include "osal_time.h"
17 #include "securec.h"
18 
19 #define HDF_LOG_TAG i2c_test
20 
21 #define I2C_TEST_8BIT          8
22 #define I2C_TEST_MSG_NUM       2
23 #define I2C_TEST_BUF_SIZE_MAX  128
24 #define I2C_TEST_REG_LEN       2
25 #define I2C_TEST_MLTTHD_TIMES  1000
26 #define I2C_TEST_STACK_SIZE    (1024 * 100)
27 #define I2C_TEST_WAIT_TIMES    200
28 #define I2C_TEST_WAIT_TIMEOUT  40
29 
30 static struct I2cMsg g_msgs[I2C_TEST_MSG_NUM];
31 static uint8_t *g_buf;
32 static uint8_t g_regs[I2C_TEST_REG_LEN];
33 
I2cTestGetConfig(struct I2cTestConfig * config)34 static int32_t I2cTestGetConfig(struct I2cTestConfig *config)
35 {
36     int32_t ret;
37     struct HdfSBuf *reply = NULL;
38     struct HdfIoService *service = NULL;
39     const void *buf = NULL;
40     uint32_t len;
41 
42     HDF_LOGD("I2cTestGetConfig: enter!");
43     service = HdfIoServiceBind("I2C_TEST");
44     if (service == NULL) {
45         return HDF_ERR_NOT_SUPPORT;
46     }
47 
48     reply = HdfSbufObtain(sizeof(*config) + sizeof(uint64_t));
49     if (reply == NULL) {
50         HDF_LOGE("I2cTestGetConfig: failed to obtain reply!");
51         HdfIoServiceRecycle(service);
52         return HDF_ERR_MALLOC_FAIL;
53     }
54 
55     ret = service->dispatcher->Dispatch(&service->object, 0, NULL, reply);
56     if (ret != HDF_SUCCESS) {
57         HDF_LOGE("I2cTestGetConfig: remote dispatch fail:%d", ret);
58         ret = HDF_ERR_IO;
59         goto EXIT;
60     }
61 
62     if (!HdfSbufReadBuffer(reply, &buf, &len)) {
63         HDF_LOGE("I2cTestGetConfig: read buf fail!");
64         ret = HDF_ERR_IO;
65         goto EXIT;
66     }
67 
68     if (len != sizeof(*config)) {
69         ret = HDF_ERR_IO;
70         goto EXIT;
71     }
72 
73     if (memcpy_s(config, sizeof(*config), buf, sizeof(*config)) != EOK) {
74         HDF_LOGE("I2cTestGetConfig: memcpy buf fail!");
75         ret = HDF_ERR_IO;
76         goto EXIT;
77     }
78     ret = HDF_SUCCESS;
79 EXIT:
80     HdfSbufRecycle(reply);
81     HDF_LOGD("I2cTestGetConfig: exit!");
82     HdfIoServiceRecycle(service);
83     return ret;
84 }
85 
I2cTesterGet(void)86 static struct I2cTester *I2cTesterGet(void)
87 {
88     int32_t ret;
89     static struct I2cTester tester;
90     static bool hasInit = false;
91 
92     if (hasInit) {
93         return &tester;
94     }
95 
96     ret = I2cTestGetConfig(&tester.config);
97     if (ret != HDF_SUCCESS) {
98         HDF_LOGE("I2cTesterGet: read config fail:%d", ret);
99         return NULL;
100     }
101 
102     tester.handle = I2cOpen(tester.config.busNum);
103     if (tester.handle == NULL) {
104         HDF_LOGE("I2cTesterGet: open i2cBus:%u fail!", tester.config.busNum);
105         return NULL;
106     }
107 
108     hasInit = true;
109     return &tester;
110 }
111 
I2cTestMallocBuf(struct I2cTester * tester)112 static int32_t I2cTestMallocBuf(struct I2cTester *tester)
113 {
114     struct I2cTestConfig *config = &tester->config;
115 
116     if (g_buf == NULL) {
117         g_buf = OsalMemCalloc(config->bufSize);
118         if (g_buf == NULL) {
119             HDF_LOGE("I2cTestMallocBuf: malloc buf fail!");
120             return HDF_ERR_MALLOC_FAIL;
121         }
122     }
123 
124     g_regs[0] = (uint8_t)config->regAddr;
125     if (config->regLen > 1) {
126         g_regs[1] = g_regs[0];
127         g_regs[0] = (uint8_t)(config->regAddr >> I2C_TEST_8BIT);
128     }
129 
130     g_msgs[0].addr = config->devAddr;
131     g_msgs[0].flags = 0;
132     g_msgs[0].len = config->regLen;
133     g_msgs[0].buf = g_regs;
134 
135     g_msgs[1].addr = config->devAddr;
136     g_msgs[1].flags = I2C_FLAG_READ;
137     g_msgs[1].len = config->bufSize;
138     g_msgs[1].buf = g_buf;
139 
140     return HDF_SUCCESS;
141 }
142 
I2cTestSetUpAll(void)143 static int32_t I2cTestSetUpAll(void)
144 {
145     struct I2cTester *tester = NULL;
146     struct I2cTestConfig *cfg = NULL;
147 
148     HDF_LOGD("I2cTestSetUpAll: enter!");
149     tester = I2cTesterGet();
150     if (tester == NULL) {
151         HDF_LOGE("I2cTestSetUpAll: get tester fail!");
152         return HDF_ERR_INVALID_OBJECT;
153     }
154     tester->total = I2C_TEST_CMD_MAX;
155     tester->fails = 0;
156 
157     cfg = &tester->config;
158     HDF_LOGE("I2cTestSetUpAll: test on bus:0x%x, addr:0x%x, reg:0x%x, reglen:0x%x, size:0x%x",
159         cfg->busNum, cfg->devAddr, cfg->regAddr, cfg->regLen, cfg->bufSize);
160     if (I2cTestMallocBuf(tester) != HDF_SUCCESS) {
161         HDF_LOGE("I2cTestSetUpAll: set up test case fail!");
162     }
163     HDF_LOGD("I2cTestSetUpAll: exit!");
164     return HDF_SUCCESS;
165 }
166 
I2cTestTearDownAll(void)167 static int32_t I2cTestTearDownAll(void)
168 {
169     if (g_buf != NULL) {
170         OsalMemFree(g_buf);
171         g_buf = NULL;
172     }
173 
174     return HDF_SUCCESS;
175 }
176 
I2cTestSetUpSingle(void)177 static int32_t I2cTestSetUpSingle(void)
178 {
179     return HDF_SUCCESS;
180 }
181 
I2cTestTearDownSingle(void)182 static int32_t I2cTestTearDownSingle(void)
183 {
184     return HDF_SUCCESS;
185 }
186 
I2cTestTransfer(void)187 static int32_t I2cTestTransfer(void)
188 {
189     int32_t ret;
190     struct I2cTester *tester = NULL;
191 
192     tester = I2cTesterGet();
193     if (tester == NULL || tester->handle == NULL) {
194         return HDF_ERR_INVALID_OBJECT;
195     }
196 
197     /* transfer one write msg */
198     ret = I2cTransfer(tester->handle, g_msgs, 1);
199     if (ret != 1) {
200         HDF_LOGE("I2cTestTransfer: I2cTransfer(write) err:%d", ret);
201         return HDF_FAILURE;
202     }
203 
204     /* transfer one read msg */
205     ret = I2cTransfer(tester->handle, g_msgs + 1, 1);
206     if (ret != 1) {
207         HDF_LOGE("I2cTestTransfer: I2cTransfer(read) err:%d", ret);
208         return HDF_FAILURE;
209     }
210 
211     /* transfer two msgs including a read msg and a write msg */
212     ret = I2cTransfer(tester->handle, g_msgs, I2C_TEST_MSG_NUM);
213     if (ret != I2C_TEST_MSG_NUM) {
214         HDF_LOGE("I2cTestTransfer: I2cTransfer(mix) err:%d", ret);
215         return HDF_FAILURE;
216     }
217     return HDF_SUCCESS;
218 }
219 
I2cTestThreadFunc(void * param)220 static int I2cTestThreadFunc(void *param)
221 {
222     int32_t i;
223     int32_t ret;
224     struct I2cTester *tester = NULL;
225 
226     tester = I2cTesterGet();
227     if (tester == NULL || tester->handle == NULL) {
228         *((int32_t *)param) = 1;
229         return HDF_ERR_INVALID_OBJECT;
230     }
231 
232     for (i = 0; i < I2C_TEST_MLTTHD_TIMES; i++) {
233         ret = I2cTransfer(tester->handle, g_msgs, I2C_TEST_MSG_NUM);
234         if (ret != I2C_TEST_MSG_NUM) {
235 #ifdef __USER__
236             HDF_LOGE("I2cTestThreadFunc: I2cTransfer-user err in multithread test, ret: %d", ret);
237 #else
238             HDF_LOGE("I2cTestThreadFunc: I2cTransfer-kerl err in multithread test, ret: %d", ret);
239 #endif
240         }
241     }
242 
243     *((int32_t *)param) = 1;
244     return HDF_SUCCESS;
245 }
246 
I2cTestStartThread(struct OsalThread * thread1,struct OsalThread * thread2,const int32_t * count1,const int32_t * count2)247 static int32_t I2cTestStartThread(struct OsalThread *thread1, struct OsalThread *thread2,
248     const int32_t *count1, const int32_t *count2)
249 {
250     int32_t ret;
251     uint32_t time = 0;
252     struct OsalThreadParam cfg1;
253     struct OsalThreadParam cfg2;
254 
255     if (memset_s(&cfg1, sizeof(cfg1), 0, sizeof(cfg1)) != EOK ||
256         memset_s(&cfg2, sizeof(cfg2), 0, sizeof(cfg2)) != EOK) {
257         HDF_LOGE("I2cTestStartThread: memset_s fail!");
258         return HDF_ERR_IO;
259     }
260     cfg1.name = "I2cTestThread-1";
261     cfg2.name = "I2cTestThread-2";
262     cfg1.priority = cfg2.priority = OSAL_THREAD_PRI_DEFAULT;
263     cfg1.stackSize = cfg2.stackSize = I2C_TEST_STACK_SIZE;
264 
265     ret = OsalThreadStart(thread1, &cfg1);
266     if (ret != HDF_SUCCESS) {
267         HDF_LOGE("I2cTestStartThread: start test thread1 fail, ret: %d!", ret);
268         return ret;
269     }
270 
271     ret = OsalThreadStart(thread2, &cfg2);
272     if (ret != HDF_SUCCESS) {
273         HDF_LOGE("I2cTestStartThread: start test thread2 fail, ret: %d!", ret);
274     }
275 
276     while (*count1 == 0 || *count2 == 0) {
277         HDF_LOGD("I2cTestStartThread: waitting testing thread finish...");
278         OsalMSleep(I2C_TEST_WAIT_TIMES);
279         time++;
280         if (time > I2C_TEST_WAIT_TIMEOUT) {
281             break;
282         }
283     }
284     return ret;
285 }
286 
I2cTestMultiThread(void)287 static int32_t I2cTestMultiThread(void)
288 {
289     int32_t ret;
290     struct OsalThread thread1;
291     struct OsalThread thread2;
292     int32_t count1 = 0;
293     int32_t count2 = 0;
294 
295     ret = OsalThreadCreate(&thread1, (OsalThreadEntry)I2cTestThreadFunc, (void *)&count1);
296     if (ret != HDF_SUCCESS) {
297         HDF_LOGE("I2cTestMultiThread: create test thread1 fail, ret: %d!", ret);
298         return ret;
299     }
300 
301     ret = OsalThreadCreate(&thread2, (OsalThreadEntry)I2cTestThreadFunc, (void *)&count2);
302     if (ret != HDF_SUCCESS) {
303         (void)OsalThreadDestroy(&thread1);
304         HDF_LOGE("I2cTestMultiThread: create test thread2 fail, ret: %d!", ret);
305         return ret;
306     }
307 
308     ret = I2cTestStartThread(&thread1, &thread2, &count1, &count2);
309     if (ret != HDF_SUCCESS) {
310         HDF_LOGE("I2cTestMultiThread: test start thread fail, ret: %d!", ret);
311     }
312 
313     (void)OsalThreadDestroy(&thread1);
314     (void)OsalThreadDestroy(&thread2);
315     return ret;
316 }
317 
I2cTestReliability(void)318 static int32_t I2cTestReliability(void)
319 {
320     struct I2cTester *tester = NULL;
321 
322     HDF_LOGD("I2cTestReliability: test dfr for I2cTransfer ...");
323     tester = I2cTesterGet();
324     if (tester == NULL || tester->handle == NULL) {
325         return HDF_ERR_INVALID_OBJECT;
326     }
327     /* invalid device handle */
328     (void)I2cTransfer(NULL, g_msgs, I2C_TEST_MSG_NUM);
329     /* invalid device msgs */
330     (void)I2cTransfer(tester->handle, NULL, I2C_TEST_MSG_NUM);
331     /* invalid device msg number */
332     (void)I2cTransfer(tester->handle, g_msgs, -1);
333 
334     return HDF_SUCCESS;
335 }
336 
I2cTestPeformance(void)337 static int32_t I2cTestPeformance(void)
338 {
339 #ifdef __LITEOS__
340     // liteos the accuracy of the obtained time is too large and inaccurate.
341     return HDF_SUCCESS;
342 #endif
343     uint64_t startMs;
344     uint64_t endMs;
345     uint64_t useTime;    // ms
346     struct I2cTester *tester = NULL;
347     DevHandle handle = NULL;
348 
349     tester = I2cTesterGet();
350     if (tester == NULL || tester->handle == NULL) {
351         HDF_LOGE("I2cTestPeformance: get tester fail!");
352         return HDF_ERR_INVALID_OBJECT;
353     }
354 
355     startMs = OsalGetSysTimeMs();
356     handle = I2cOpen(tester->config.busNum);
357     endMs = OsalGetSysTimeMs();
358 
359     if (handle != NULL) {
360         useTime = endMs - startMs;
361         HDF_LOGI("I2cTestPeformance: ----->interface performance test:[start - end] < 1ms[%s]\r\n",
362             useTime < 1 ? "yes" : "no");
363         I2cClose(handle);
364         return HDF_SUCCESS;
365     }
366 
367     return HDF_FAILURE;
368 }
369 
I2cMiniWriteReadTest(void)370 static int32_t I2cMiniWriteReadTest(void)
371 {
372 #ifdef __KERNEL__
373     struct I2cTester *tester = NULL;
374     uint8_t buf;
375     int32_t ret;
376 
377     tester = I2cTesterGet();
378     if (tester == NULL || tester->handle == NULL) {
379         HDF_LOGE("I2cMiniWriteReadTest: get tester fail!");
380         return HDF_ERR_INVALID_OBJECT;
381     }
382 
383     ret = I2cWrite(tester->handle, &buf, sizeof(buf));
384     if (ret != HDF_SUCCESS) {
385         HDF_LOGE("I2cMiniWriteReadTest: i2c write fail, ret: %d!", ret);
386         return ret;
387     }
388 
389     HDF_LOGI("I2cMiniWriteReadTest: i2c write test done, then test i2c read!");
390     ret = I2cRead(tester->handle, &buf, sizeof(buf));
391     if (ret != HDF_SUCCESS) {
392         HDF_LOGE("I2cMiniWriteReadTest: i2c read fail, ret: %d!", ret);
393         return ret;
394     }
395 #endif
396     HDF_LOGI("I2cMiniWriteReadTest: all test done!");
397     return HDF_SUCCESS;
398 }
399 
400 struct I2cTestEntry {
401     int cmd;
402     int32_t (*func)(void);
403     const char *name;
404 };
405 
406 static struct I2cTestEntry g_entry[] = {
407     { I2C_TEST_CMD_TRANSFER, I2cTestTransfer, "I2cTestTransfer" },
408     { I2C_TEST_CMD_MULTI_THREAD, I2cTestMultiThread, "I2cTestMultiThread" },
409     { I2C_TEST_CMD_RELIABILITY, I2cTestReliability, "I2cTestReliability" },
410     { I2C_TEST_CMD_PERFORMANCE, I2cTestPeformance, "I2cTestPeformance" },
411     { I2C_TEST_CMD_SETUP_ALL, I2cTestSetUpAll, "I2cTestSetUpAll" },
412     { I2C_TEST_CMD_TEARDOWN_ALL, I2cTestTearDownAll, "I2cTestTearDownAll" },
413     { I2C_TEST_CMD_SETUP_SINGLE, I2cTestSetUpSingle, "I2cTestSetUpSingle" },
414     { I2C_TEST_CMD_TEARDOWN_SINGLE, I2cTestTearDownSingle, "I2cTestTearDownSingle" },
415     { I2C_MINI_WRITE_READ_TEST, I2cMiniWriteReadTest, "I2cMiniWriteReadTest" },
416 };
417 
I2cTestExecute(int cmd)418 int32_t I2cTestExecute(int cmd)
419 {
420     uint32_t i;
421     int32_t ret = HDF_ERR_NOT_SUPPORT;
422 
423     if (cmd > I2C_TEST_CMD_MAX) {
424         HDF_LOGE("I2cTestExecute: invalid cmd:%d", cmd);
425         ret = HDF_ERR_NOT_SUPPORT;
426         HDF_LOGE("[I2cTestExecute][======cmd:%d====ret:%d======]", cmd, ret);
427         return ret;
428     }
429 
430     for (i = 0; i < sizeof(g_entry) / sizeof(g_entry[0]); i++) {
431         if (g_entry[i].cmd != cmd || g_entry[i].func == NULL) {
432             continue;
433         }
434         ret = g_entry[i].func();
435         break;
436     }
437 
438     HDF_LOGE("[I2cTestExecute][======cmd:%d====ret:%d======]", cmd, ret);
439     return ret;
440 }
441 
I2cTestExecuteAll(void)442 void I2cTestExecuteAll(void)
443 {
444     int32_t i;
445     int32_t ret;
446     int32_t fails = 0;
447 
448     /* setup env for all test cases */
449     (void)I2cTestExecute(I2C_TEST_CMD_SETUP_ALL);
450 
451     for (i = 0; i <= I2C_TEST_CMD_RELIABILITY; i++) {
452         ret = I2cTestExecute(i);
453         fails += (ret != HDF_SUCCESS) ? 1 : 0;
454     }
455 
456     /* teardown env for all test cases */
457     (void)I2cTestExecute(I2C_TEST_CMD_TEARDOWN_ALL);
458 
459     HDF_LOGE("I2cTestExecuteALL: **********PASS:%d  FAIL:%d************\n\n",
460         I2C_TEST_CMD_RELIABILITY + 1 - fails, fails);
461 }
462