b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 1 | #include <stdio.h>
|
| 2 | #include <stdlib.h>
|
| 3 | #include <fcntl.h>
|
| 4 | #include <sys/types.h>
|
| 5 | #include <sys/stat.h>
|
| 6 | #include <string.h>
|
| 7 | #include <errno.h>
|
| 8 | #include <termios.h>
|
| 9 | #include <unistd.h>
|
| 10 | #include <stdint.h>
|
| 11 | #include <sys/ioctl.h>
|
| 12 | #include <dlfcn.h>
|
| 13 |
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 14 | #include "gsw_uart_interface.h"
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 15 |
|
hong.liu | d241707 | 2025-06-27 07:10:37 -0700 | [diff] [blame] | 16 | #define MODEM_CONNECT_MCU_PORT "/dev/ttyS1"
|
| 17 |
|
zw.wang | bd342b9 | 2025-07-21 11:24:16 +0800 | [diff] [blame] | 18 | #include "gsw_log_interface.h"
|
l.yang | 6a42e4d | 2025-05-28 01:04:20 -0700 | [diff] [blame] | 19 | #define GSW_UART "[HAL][GSW_UART]"
|
| 20 |
|
| 21 |
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 22 | typedef enum
|
| 23 | {
|
| 24 | GSW_HAL_BAUDRATE_1200=1200,
|
| 25 | GSW_HAL_BAUDRATE_1800=1800,
|
| 26 | GSW_HAL_BAUDRATE_4800=4800,
|
| 27 | GSW_HAL_BAUDRATE_9600=9600,
|
| 28 | GSW_HAL_BAUDRATE_19200=19200,
|
| 29 | GSW_HAL_BAUDRATE_38400=38400,
|
| 30 | GSW_HAL_BAUDRATE_57600=57600,
|
| 31 | GSW_HAL_BAUDRATE_115200=115200,
|
| 32 | GSW_HAL_BAUDRATE_230400=230400,
|
| 33 | GSW_HAL_BAUDRATE_460800=460800,
|
| 34 | GSW_HAL_BAUDRATE_500000=500000,
|
| 35 | GSW_HAL_BAUDRATE_576000=576000,
|
| 36 | GSW_HAL_BAUDRATE_921600=921600
|
| 37 | }gsw_hal_uart_baudrate;
|
| 38 |
|
zw.wang | bd342b9 | 2025-07-21 11:24:16 +0800 | [diff] [blame] | 39 | static inline int handle()
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 40 | {
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 41 | return GSW_HAL_SUCCESS;
|
| 42 | }
|
| 43 |
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 44 | int32_t gsw_uart_open_ex(int8_t *port, gsw_hal_uart_baudrate baudrate, uint32_t bits, int8_t parity, uint32_t stop)
|
| 45 | {
|
| 46 | if (handle())
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 47 | return GSW_HAL_NORMAL_FAIL;
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 48 | int fd = -1;
|
| 49 | if((fd = open((const char *)port, O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0)
|
| 50 | {
|
zw.wang | bd342b9 | 2025-07-21 11:24:16 +0800 | [diff] [blame] | 51 | LOGE(GSW_UART,"open %s failed - %d", port, errno);
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 52 | return -1;
|
| 53 | }
|
zw.wang | bd342b9 | 2025-07-21 11:24:16 +0800 | [diff] [blame] | 54 | LOGD(GSW_UART,"Open %s success.", port);
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 55 |
|
| 56 | /* set newtio */
|
| 57 | struct termios newtio;
|
| 58 | memset(&newtio, 0, sizeof(newtio));
|
| 59 | if (tcflush(fd, TCIOFLUSH) < 0) {
|
zw.wang | bd342b9 | 2025-07-21 11:24:16 +0800 | [diff] [blame] | 60 | LOGE(GSW_UART,"Could not flush uart port");
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 61 | return -1;
|
| 62 | }
|
| 63 |
|
| 64 | newtio.c_cc[VTIME] = 0; /* inter-character timer unused */
|
| 65 | newtio.c_cc[VMIN] = 0; /* blocking read until 5 chars received */
|
| 66 |
|
| 67 | /* c_iflag 输入模式 */
|
| 68 | newtio.c_iflag &= ~(ICRNL | INLCR);
|
| 69 | newtio.c_iflag &= ~(IXON | IXOFF | IXANY);
|
| 70 |
|
| 71 | // /* c_lflag 本地模式 */
|
| 72 | newtio.c_cflag &= ~ INPCK;
|
| 73 | newtio.c_cflag |= (CLOCAL | CREAD);
|
| 74 |
|
| 75 | // /* c_lflag 本地模式 */
|
| 76 | newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
|
| 77 | /* c_oflag 输出模式 */
|
| 78 | newtio.c_oflag &= ~ OPOST;
|
| 79 | newtio.c_oflag &= ~(ONLCR | OCRNL);
|
| 80 |
|
| 81 | /* c_cflag 控制模式 */
|
| 82 | newtio.c_cflag &= ~ CSIZE;
|
| 83 | newtio.c_cflag |= CS8;
|
| 84 | newtio.c_cflag &= ~ CSTOPB;
|
| 85 | newtio.c_cflag &= ~ PARENB;
|
| 86 |
|
| 87 |
|
| 88 | switch(baudrate)
|
| 89 | {
|
| 90 | case GSW_HAL_BAUDRATE_1200:
|
| 91 | cfsetospeed(&newtio, B1200);
|
| 92 | cfsetispeed(&newtio, B1200);
|
| 93 | break;
|
| 94 | case GSW_HAL_BAUDRATE_1800:
|
| 95 | cfsetospeed(&newtio, B1800);
|
| 96 | cfsetispeed(&newtio, B1800);
|
| 97 | break;
|
| 98 | case GSW_HAL_BAUDRATE_4800:
|
| 99 | cfsetospeed(&newtio, B4800);
|
| 100 | cfsetispeed(&newtio, B4800);
|
| 101 | break;
|
| 102 | case GSW_HAL_BAUDRATE_9600:
|
| 103 | cfsetospeed(&newtio, B9600);
|
| 104 | cfsetispeed(&newtio, B9600);
|
| 105 | break;
|
| 106 | case GSW_HAL_BAUDRATE_19200:
|
| 107 | cfsetospeed(&newtio, B19200);
|
| 108 | cfsetispeed(&newtio, B19200);
|
| 109 | break;
|
| 110 | case GSW_HAL_BAUDRATE_38400:
|
| 111 | cfsetospeed(&newtio, B38400);
|
| 112 | cfsetispeed(&newtio, B38400);
|
| 113 | break;
|
| 114 | case GSW_HAL_BAUDRATE_57600:
|
| 115 | cfsetospeed(&newtio, B57600);
|
| 116 | cfsetispeed(&newtio, B57600);
|
| 117 | break;
|
| 118 | case GSW_HAL_BAUDRATE_115200:
|
| 119 | cfsetospeed(&newtio, B115200);
|
| 120 | cfsetispeed(&newtio, B115200);
|
| 121 | break;
|
| 122 | case GSW_HAL_BAUDRATE_230400:
|
| 123 | cfsetospeed(&newtio, B230400);
|
| 124 | cfsetispeed(&newtio, B230400);
|
| 125 | break;
|
| 126 | case GSW_HAL_BAUDRATE_460800:
|
| 127 | cfsetospeed(&newtio, B460800);
|
| 128 | cfsetispeed(&newtio, B460800);
|
| 129 | break;
|
| 130 | case GSW_HAL_BAUDRATE_500000:
|
| 131 | cfsetospeed(&newtio, B500000);
|
| 132 | cfsetispeed(&newtio, B500000);
|
| 133 | break;
|
| 134 | case GSW_HAL_BAUDRATE_576000:
|
| 135 | cfsetospeed(&newtio, B576000);
|
| 136 | cfsetispeed(&newtio, B576000);
|
| 137 | break;
|
| 138 | case GSW_HAL_BAUDRATE_921600:
|
| 139 | cfsetospeed(&newtio, B921600);
|
| 140 | cfsetispeed(&newtio, B921600);
|
| 141 | break;
|
| 142 | default:
|
| 143 | cfsetospeed(&newtio, B115200);
|
| 144 | cfsetispeed(&newtio, B115200);
|
| 145 | break;
|
| 146 | }
|
| 147 |
|
| 148 | switch(bits)
|
| 149 | {
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 150 | case 5:
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 151 | newtio.c_cflag &= ~CSIZE;
|
| 152 | newtio.c_cflag |= CS5;
|
| 153 | break;
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 154 | case 6:
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 155 | newtio.c_cflag &= ~CSIZE;
|
| 156 | newtio.c_cflag |= CS6;
|
| 157 | break;
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 158 | case 7:
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 159 | newtio.c_cflag &= ~CSIZE;
|
| 160 | newtio.c_cflag |= CS7;
|
| 161 | break;
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 162 | case 8:
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 163 | newtio.c_cflag &= ~CSIZE;
|
| 164 | newtio.c_cflag |= CS8;
|
| 165 | break;
|
| 166 | default:
|
zw.wang | bd342b9 | 2025-07-21 11:24:16 +0800 | [diff] [blame] | 167 | LOGD(GSW_UART,"No set databit.");
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 168 | break;
|
| 169 | }
|
| 170 |
|
| 171 | if(stop == 2) {
|
| 172 | newtio.c_cflag |= CSTOPB;
|
| 173 | } else {
|
| 174 | newtio.c_cflag &= ~CSTOPB;
|
| 175 | }
|
| 176 |
|
| 177 | switch (parity)
|
| 178 | {
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 179 | case 'O':
|
| 180 | case 'o':// 奇校验
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 181 | newtio.c_cflag |= PARENB;
|
| 182 | newtio.c_cflag |= PARODD;
|
| 183 | break;
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 184 | case 'E':
|
| 185 | case 'e':// 偶校验
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 186 | newtio.c_cflag |= PARENB;
|
| 187 | newtio.c_cflag &= ~PARODD;
|
| 188 | break;
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 189 | case 'N':
|
| 190 | case 'n':// 无奇偶校验
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 191 | newtio.c_cflag &= ~PARENB;
|
| 192 | break;
|
| 193 | default:
|
zw.wang | bd342b9 | 2025-07-21 11:24:16 +0800 | [diff] [blame] | 194 | LOGD(GSW_UART,"No set parity.");
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 195 | break;
|
| 196 | }
|
| 197 |
|
| 198 | if (tcsetattr(fd, TCSANOW, &newtio) < 0) {
|
zw.wang | bd342b9 | 2025-07-21 11:24:16 +0800 | [diff] [blame] | 199 | LOGE(GSW_UART,"Can't set port setting");
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 200 | return -1;
|
| 201 | }
|
| 202 |
|
| 203 | return fd;
|
| 204 | }
|
| 205 |
|
hong.liu | d241707 | 2025-06-27 07:10:37 -0700 | [diff] [blame] | 206 | void gsw_uart_flush(int32_t fd)
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 207 | {
|
zw.wang | 10b141c | 2025-06-19 11:18:30 +0800 | [diff] [blame] | 208 | if (handle())
|
| 209 | return;
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 210 | if (tcflush(fd, TCIOFLUSH) < 0)
|
| 211 | {
|
zw.wang | bd342b9 | 2025-07-21 11:24:16 +0800 | [diff] [blame] | 212 | LOGE(GSW_UART,"flush fail\n");
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 213 | //return GSW_HAL_NORMAL_FAIL;
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 214 | }
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 215 | else
|
zw.wang | bd342b9 | 2025-07-21 11:24:16 +0800 | [diff] [blame] | 216 | LOGD(GSW_UART,"flush success\n");
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 217 | //return GSW_HAL_SUCCESS;
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 218 | }
|
| 219 |
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 220 | int gsw_uart_read(int fd, unsigned char *buffer, int len, int timeout_ms)
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 221 | {
|
| 222 | if (handle())
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 223 | return GSW_HAL_NORMAL_FAIL;
|
| 224 | if(len <= 0 || timeout_ms < -1)
|
| 225 | {
|
zw.wang | bd342b9 | 2025-07-21 11:24:16 +0800 | [diff] [blame] | 226 | LOGE(GSW_UART,"timeout_ms = %d, len = %d; timeout_ms needs to be greater than -1 and len needs to be greater than 0!\n",timeout_ms, len);
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 227 | return GSW_HAL_NORMAL_FAIL;
|
| 228 | }
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 229 | int flags = fcntl(fd, F_GETFL); // 获取当前状态标志
|
| 230 | if (flags == -1)
|
| 231 | {
|
| 232 | perror("fcntl get");
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 233 | return GSW_HAL_NORMAL_FAIL;
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 234 | }
|
| 235 |
|
| 236 | struct termios newtio;
|
| 237 | if (tcgetattr(fd, &newtio) < 0) {
|
| 238 | perror("tcgetattr failed");
|
| 239 | return -1;
|
| 240 | }
|
| 241 | if (timeout_ms == 0)
|
| 242 | {
|
| 243 | flags |= O_NONBLOCK; // 设置非阻塞标志
|
| 244 | fcntl(fd, F_SETFL, flags);
|
| 245 | newtio.c_cc[VMIN] = 0;
|
| 246 | newtio.c_cc[VTIME] = 0;
|
| 247 | }
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 248 | else if (timeout_ms == -1)
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 249 | {
|
| 250 | flags &= ~O_NONBLOCK; // 清除非阻塞标志
|
| 251 | fcntl(fd, F_SETFL, flags);
|
| 252 | newtio.c_cc[VMIN] = 1;
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 253 | newtio.c_cc[VTIME] = 0;
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 254 | }
|
| 255 | else
|
| 256 | {
|
| 257 | flags &= ~O_NONBLOCK; // 清除非阻塞标志
|
| 258 | fcntl(fd, F_SETFL, flags);
|
| 259 | newtio.c_cc[VMIN] = 0;
|
| 260 | newtio.c_cc[VTIME] = timeout_ms/100;
|
| 261 | }
|
| 262 | if(timeout_ms != 0)
|
zw.wang | bd342b9 | 2025-07-21 11:24:16 +0800 | [diff] [blame] | 263 | LOGI(GSW_UART,"%s :VMIN = %d ;VTIME = %d\n",__func__,newtio.c_cc[VMIN],newtio.c_cc[VTIME]);
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 264 | if (tcsetattr(fd, TCSANOW, &newtio) != 0)
|
| 265 | {
|
| 266 | perror("tcsetattr");
|
| 267 | return -1;
|
| 268 | }
|
| 269 | //gsw_uart_flush(fd);
|
| 270 | int data_len = read(fd, buffer, len);
|
| 271 | if (data_len < 0)
|
| 272 | {
|
| 273 | if(errno == EAGAIN || errno == EWOULDBLOCK)
|
| 274 | return 0;
|
| 275 | else
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 276 | return GSW_HAL_NORMAL_FAIL;
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 277 | }
|
| 278 | return data_len;
|
| 279 | }
|
| 280 |
|
| 281 |
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 282 | int gsw_uart_write(int fd, const unsigned char *buffer, int len)
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 283 | {
|
| 284 | //gsw_uart_flush(fd);
|
| 285 | if (write(fd, buffer, len) < 0)
|
| 286 | {
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 287 | return GSW_HAL_NORMAL_FAIL;
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 288 | }
|
| 289 | return GSW_HAL_SUCCESS;
|
| 290 | }
|
| 291 |
|
| 292 | int32_t gsw_uart_ioctl(int32_t fd, uint32_t cmd, void *pvalue)
|
| 293 | {
|
| 294 | if (handle())
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 295 | return GSW_HAL_NORMAL_FAIL;
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 296 | if (fd < 0 || pvalue == NULL)
|
| 297 | {
|
zw.wang | bd342b9 | 2025-07-21 11:24:16 +0800 | [diff] [blame] | 298 | LOGE(GSW_UART,"Invalid file descriptor");
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 299 | return GSW_HAL_NORMAL_FAIL;
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 300 | }
|
| 301 | if (ioctl(fd, cmd, pvalue) < 0)
|
| 302 | {
|
zw.wang | bd342b9 | 2025-07-21 11:24:16 +0800 | [diff] [blame] | 303 | LOGE(GSW_UART,"Could not set DCB,error:%d, %s\n",errno, strerror(errno));
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 304 | return GSW_HAL_NORMAL_FAIL;
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 305 | }
|
| 306 | return GSW_HAL_SUCCESS;
|
| 307 | }
|
| 308 |
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 309 | void gsw_uart_close(int fd)
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 310 | {
|
zw.wang | 10b141c | 2025-06-19 11:18:30 +0800 | [diff] [blame] | 311 | if (handle())
|
| 312 | return;
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 313 | if (fd <= 0)
|
zw.wang | bd342b9 | 2025-07-21 11:24:16 +0800 | [diff] [blame] | 314 | LOGE(GSW_UART,"fd = %d fail\n",fd);
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 315 | //return GSW_HAL_NORMAL_FAIL;
|
| 316 | else
|
| 317 | {
|
| 318 | //gsw_uart_flush(fd);
|
| 319 | int ret = close(fd);
|
| 320 | if(ret < 0)
|
| 321 | {
|
zw.wang | bd342b9 | 2025-07-21 11:24:16 +0800 | [diff] [blame] | 322 | LOGE(GSW_UART,"close fail ret = %d\n",ret);
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 323 | }
|
| 324 | else
|
| 325 | {
|
zw.wang | bd342b9 | 2025-07-21 11:24:16 +0800 | [diff] [blame] | 326 | LOGI(GSW_UART,"close success ret = %d\n",ret);
|
hong.liu | cd37079 | 2025-05-28 06:29:19 -0700 | [diff] [blame] | 327 | }
|
| 328 | }
|
| 329 |
|
| 330 | //return GSW_HAL_SUCCESS;
|
b.liu | 68a94c9 | 2025-05-24 12:53:41 +0800 | [diff] [blame] | 331 | }
|
| 332 |
|
hong.liu | d241707 | 2025-06-27 07:10:37 -0700 | [diff] [blame] | 333 | int gsw_uart_open(unsigned int baudrate, unsigned int bits, char parity, unsigned int stop)
|
| 334 | {
|
| 335 | return gsw_uart_open_ex((int8_t *)MODEM_CONNECT_MCU_PORT, (gsw_hal_uart_baudrate)baudrate, bits, parity, stop);
|
| 336 | }
|