1 /*
2 * Copyright (c) 2022 Trackunit Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "modem_backend_mock.h"
8
9 #include <string.h>
10
modem_backend_mock_open(void * data)11 static int modem_backend_mock_open(void *data)
12 {
13 struct modem_backend_mock *mock = (struct modem_backend_mock *)data;
14
15 modem_pipe_notify_opened(&mock->pipe);
16 return 0;
17 }
18
modem_backend_mock_update(struct modem_backend_mock * mock,const uint8_t * buf,size_t size)19 static bool modem_backend_mock_update(struct modem_backend_mock *mock, const uint8_t *buf,
20 size_t size)
21 {
22 if (mock->transaction == NULL) {
23 return false;
24 }
25
26 for (size_t i = 0; i < size; i++) {
27 __ASSERT(buf[i] == mock->transaction->get[mock->transaction_match_cnt],
28 "Unexpected transmit data");
29
30 mock->transaction_match_cnt++;
31 if (mock->transaction_match_cnt == mock->transaction->get_size) {
32 return true;
33 }
34 }
35
36 return false;
37 }
38
modem_backend_mock_transmit(void * data,const uint8_t * buf,size_t size)39 static int modem_backend_mock_transmit(void *data, const uint8_t *buf, size_t size)
40 {
41 struct modem_backend_mock *mock = (struct modem_backend_mock *)data;
42 int ret;
43
44 size = (mock->limit < size) ? mock->limit : size;
45
46 if (mock->bridge) {
47 struct modem_backend_mock *t_mock = mock->bridge;
48
49 ret = ring_buf_put(&t_mock->rx_rb, buf, size);
50 k_work_submit(&t_mock->receive_ready_work);
51 k_work_submit(&mock->transmit_idle_work);
52 return ret;
53 }
54
55 ret = ring_buf_put(&mock->tx_rb, buf, size);
56 if (modem_backend_mock_update(mock, buf, size)) {
57 modem_backend_mock_put(mock, mock->transaction->put,
58 mock->transaction->put_size);
59
60 mock->transaction = NULL;
61 }
62
63 k_work_submit(&mock->transmit_idle_work);
64 return ret;
65 }
66
modem_backend_mock_receive(void * data,uint8_t * buf,size_t size)67 static int modem_backend_mock_receive(void *data, uint8_t *buf, size_t size)
68 {
69 struct modem_backend_mock *mock = (struct modem_backend_mock *)data;
70
71 size = (mock->limit < size) ? mock->limit : size;
72 return ring_buf_get(&mock->rx_rb, buf, size);
73 }
74
modem_backend_mock_close(void * data)75 static int modem_backend_mock_close(void *data)
76 {
77 struct modem_backend_mock *mock = (struct modem_backend_mock *)data;
78
79 modem_pipe_notify_closed(&mock->pipe);
80 return 0;
81 }
82
83 struct modem_pipe_api modem_backend_mock_api = {
84 .open = modem_backend_mock_open,
85 .transmit = modem_backend_mock_transmit,
86 .receive = modem_backend_mock_receive,
87 .close = modem_backend_mock_close,
88 };
89
modem_backend_mock_receive_ready_handler(struct k_work * item)90 static void modem_backend_mock_receive_ready_handler(struct k_work *item)
91 {
92 struct modem_backend_mock *mock =
93 CONTAINER_OF(item, struct modem_backend_mock, receive_ready_work);
94
95 modem_pipe_notify_receive_ready(&mock->pipe);
96 }
97
modem_backend_mock_transmit_idle_handler(struct k_work * item)98 static void modem_backend_mock_transmit_idle_handler(struct k_work *item)
99 {
100 struct modem_backend_mock *mock =
101 CONTAINER_OF(item, struct modem_backend_mock, transmit_idle_work);
102
103 modem_pipe_notify_transmit_idle(&mock->pipe);
104 }
105
modem_backend_mock_init(struct modem_backend_mock * mock,const struct modem_backend_mock_config * config)106 struct modem_pipe *modem_backend_mock_init(struct modem_backend_mock *mock,
107 const struct modem_backend_mock_config *config)
108 {
109 memset(mock, 0, sizeof(*mock));
110
111 ring_buf_init(&mock->rx_rb, config->rx_buf_size, config->rx_buf);
112 ring_buf_init(&mock->tx_rb, config->tx_buf_size, config->tx_buf);
113 k_work_init(&mock->receive_ready_work, modem_backend_mock_receive_ready_handler);
114 k_work_init(&mock->transmit_idle_work, modem_backend_mock_transmit_idle_handler);
115 mock->limit = config->limit;
116 modem_pipe_init(&mock->pipe, mock, &modem_backend_mock_api);
117 return &mock->pipe;
118 }
119
modem_backend_mock_get_pipe(struct modem_backend_mock * mock)120 struct modem_pipe *modem_backend_mock_get_pipe(struct modem_backend_mock *mock)
121 {
122 return &mock->pipe;
123 }
124
modem_backend_mock_reset(struct modem_backend_mock * mock)125 void modem_backend_mock_reset(struct modem_backend_mock *mock)
126 {
127 ring_buf_reset(&mock->rx_rb);
128 ring_buf_reset(&mock->tx_rb);
129 mock->transaction = NULL;
130 mock->transaction_match_cnt = 0;
131 }
132
modem_backend_mock_get(struct modem_backend_mock * mock,uint8_t * buf,size_t size)133 int modem_backend_mock_get(struct modem_backend_mock *mock, uint8_t *buf, size_t size)
134 {
135 return ring_buf_get(&mock->tx_rb, buf, size);
136 }
137
modem_backend_mock_put(struct modem_backend_mock * mock,const uint8_t * buf,size_t size)138 void modem_backend_mock_put(struct modem_backend_mock *mock, const uint8_t *buf, size_t size)
139 {
140 __ASSERT(ring_buf_put(&mock->rx_rb, buf, size) == size,
141 "Mock buffer capacity exceeded");
142
143 k_work_submit(&mock->receive_ready_work);
144 }
145
modem_backend_mock_prime(struct modem_backend_mock * mock,const struct modem_backend_mock_transaction * transaction)146 void modem_backend_mock_prime(struct modem_backend_mock *mock,
147 const struct modem_backend_mock_transaction *transaction)
148 {
149 mock->transaction = transaction;
150 mock->transaction_match_cnt = 0;
151 }
152
modem_backend_mock_bridge(struct modem_backend_mock * mock_a,struct modem_backend_mock * mock_b)153 void modem_backend_mock_bridge(struct modem_backend_mock *mock_a, struct modem_backend_mock *mock_b)
154 {
155 mock_a->bridge = mock_b;
156 mock_b->bridge = mock_a;
157 }
158