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