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
34static int32_t g_running = 1;
35static struct termios g_orgOpts, g_newOpts;
36static struct HdfSBuf *g_data;
37static struct HdfSBuf *g_reply;
38static struct HdfRemoteService *g_acmService;
39static struct OsalThread g_thread;
40
41static 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
57static 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
86static 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
96static 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
119static 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
128static 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
139static 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
152int32_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