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 "cdcacm.h"
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 
21 #include <signal.h>
22 #include <sys/time.h>
23 #include <termios.h>
24 
25 #include "hdf_log.h"
26 #include "hdf_remote_service.h"
27 #include "hdf_sbuf.h"
28 #include "osal_time.h"
29 #include "servmgr_hdi.h"
30 #include "usb_dev_test.h"
31 
32 #define HDF_LOG_TAG cdc_acm_test
33 
34 static int32_t g_running = 1;
35 static struct termios g_orgOpts, g_newOpts;
36 static struct HdfSBuf *g_data;
37 static struct HdfSBuf *g_reply;
38 static struct HdfRemoteService *g_acmService;
39 static struct OsalThread g_thread;
40 
TestWrite(char * buf)41 static void TestWrite(char *buf)
42 {
43     HdfSbufFlush(g_data);
44 
45     if (HdfRemoteServiceWriteInterfaceToken(g_acmService, g_data) == false) {
46         HDF_LOGE("%{public}s:%{public}d write interface token fail", __func__, __LINE__);
47         return;
48     }
49 
50     (void)HdfSbufWriteString(g_data, buf);
51     int32_t status = g_acmService->dispatcher->Dispatch(g_acmService, USB_SERIAL_WRITE, g_data, g_reply);
52     if (status != HDF_SUCCESS) {
53         HDF_LOGE("%{public}s: Dispatch USB_SERIAL_WRITE failed status = %{public}d", __func__, status);
54     }
55 }
56 
TestRead(void)57 static void TestRead(void)
58 {
59     HdfSbufFlush(g_reply);
60 
61     if (HdfRemoteServiceWriteInterfaceToken(g_acmService, g_data) == false) {
62         HDF_LOGE("%{public}s:%{public}d write interface token fail", __func__, __LINE__);
63         return;
64     }
65 
66     int32_t status = g_acmService->dispatcher->Dispatch(g_acmService, USB_SERIAL_READ, g_data, g_reply);
67     if (status != HDF_SUCCESS) {
68         printf("%s: Dispatch USB_SERIAL_READ failed status = %d", __func__, status);
69         return;
70     }
71     const char *tmp = HdfSbufReadString(g_reply);
72     if (tmp && strlen(tmp) > 0) {
73         size_t len = strlen(tmp);
74         for (size_t i = 0; i < len; i++) {
75             if (tmp[i] == 0x0A || tmp[i] == 0x0D) {
76                 printf("\r\n");
77             } else {
78                 putchar(tmp[i]);
79             }
80         }
81         fflush(stdout);
82     }
83 }
84 
85 #define SLEEP_100MS 100000
ReadThread(void * arg)86 static int32_t ReadThread(void *arg)
87 {
88     (void)arg;
89     while (g_running != 0) {
90         TestRead();
91         usleep(SLEEP_100MS);
92     }
93     return 0;
94 }
95 #define HDF_PROCESS_STACK_SIZE 100000
StartThreadRead(void)96 static int32_t StartThreadRead(void)
97 {
98     int32_t ret;
99     struct OsalThreadParam threadCfg;
100     memset_s(&threadCfg, sizeof(threadCfg), 0, sizeof(threadCfg));
101     threadCfg.name = "Read process";
102     threadCfg.priority = OSAL_THREAD_PRI_DEFAULT;
103     threadCfg.stackSize = HDF_PROCESS_STACK_SIZE;
104 
105     ret = OsalThreadCreate(&g_thread, (OsalThreadEntry)ReadThread, NULL);
106     if (HDF_SUCCESS != ret) {
107         HDF_LOGE("%{public}s:%{public}d OsalThreadCreate failed, ret=%{public}d ", __func__, __LINE__, ret);
108         return HDF_ERR_DEVICE_BUSY;
109     }
110 
111     ret = OsalThreadStart(&g_thread, &threadCfg);
112     if (HDF_SUCCESS != ret) {
113         HDF_LOGE("%{public}s:%{public}d OsalThreadStart failed, ret=%{public}d ", __func__, __LINE__, ret);
114         return HDF_ERR_DEVICE_BUSY;
115     }
116     return 0;
117 }
118 
SetTermios(void)119 static void SetTermios(void)
120 {
121     tcgetattr(STDIN_FILENO, &g_orgOpts);
122     tcgetattr(STDIN_FILENO, &g_newOpts);
123     g_newOpts.c_lflag &= ~(ICANON | ECHOE | ECHOK | ECHONL);
124     tcsetattr(STDIN_FILENO, TCSANOW, &g_newOpts);
125 }
126 
127 #define STR_LEN 256
WriteThread(void)128 static void WriteThread(void)
129 {
130     char str[STR_LEN] = {0};
131     while (g_running != 0) {
132         str[0] = (char)getchar();
133         if (g_running != 0) {
134             TestWrite(str);
135         }
136     }
137 }
138 
StopAcmTest(int32_t signo)139 static void StopAcmTest(int32_t signo)
140 {
141     (void)signo;
142     int32_t status;
143     g_running = 0;
144     status = g_acmService->dispatcher->Dispatch(g_acmService, USB_SERIAL_CLOSE, g_data, g_reply);
145     if (status != HDF_SUCCESS) {
146         HDF_LOGE("%{public}s: Dispatch USB_SERIAL_CLOSE err", __func__);
147     }
148     tcsetattr(STDIN_FILENO, TCSANOW, &g_orgOpts);
149     printf("AcmTest exit.\n");
150 }
151 
AcmTest(int32_t argc,const char * argv[])152 int32_t AcmTest(int32_t argc, const char *argv[])
153 {
154     (void)argc;
155     (void)argv;
156     int32_t status;
157     struct HDIServiceManager *servmgr = HDIServiceManagerGet();
158     if (servmgr == NULL) {
159         HDF_LOGE("%{public}s: HDIServiceManagerGet err", __func__);
160         return HDF_FAILURE;
161     }
162     g_acmService = servmgr->GetService(servmgr, "usbfn_cdcacm");
163     HDIServiceManagerRelease(servmgr);
164     if (g_acmService == NULL) {
165         HDF_LOGE("%{public}s: GetService err", __func__);
166         return HDF_FAILURE;
167     }
168 
169     if (HdfRemoteServiceSetInterfaceDesc(g_acmService, "hdf.usb.usbfn") == false) {
170         HDF_LOGE("%{public}s:%{public}d set desc fail", __func__, __LINE__);
171         return HDF_FAILURE;
172     }
173 
174     g_data = HdfSbufTypedObtain(SBUF_IPC);
175     g_reply = HdfSbufTypedObtain(SBUF_IPC);
176     if (g_data == NULL || g_reply == NULL) {
177         HDF_LOGE("%{public}s: GetService err", __func__);
178         return HDF_FAILURE;
179     }
180 
181     if (HdfRemoteServiceWriteInterfaceToken(g_acmService, g_data) == false) {
182         HDF_LOGE("%{public}s:%{public}d write interface token fail", __func__, __LINE__);
183         return HDF_FAILURE;
184     }
185 
186     status = g_acmService->dispatcher->Dispatch(g_acmService, USB_SERIAL_OPEN, g_data, g_reply);
187     if (status != HDF_SUCCESS) {
188         HDF_LOGE("%{public}s: Dispatch USB_SERIAL_OPEN err", __func__);
189         return HDF_FAILURE;
190     }
191     printf("Press any key to send.\n");
192     printf("Press CTRL-C to exit.\n");
193 
194     (void)signal(SIGINT, StopAcmTest);
195     StartThreadRead();
196     SetTermios();
197     WriteThread();
198     return 0;
199 }
200