Paparazzi UAS  v4.2.2_stable-4-gcc32f65
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
lisa_spistream.h
Go to the documentation of this file.
1 #ifndef SPISTREAM_PROTOCOL_H__
2 #define SPISTREAM_PROTOCOL_H__
3 
4 #include <string.h>
5 
6 #ifndef SPISTREAM_MAX_MESSAGE_LENGTH
7 #define SPISTREAM_MAX_MESSAGE_LENGTH 720
8 #endif
9 
10 #ifndef SPISTREAM_MAX_RX_MESSAGE_LENGTH
11 #define SPISTREAM_MAX_RX_MESSAGE_LENGTH SPISTREAM_MAX_MESSAGE_LENGTH
12 #endif
13 #ifndef SPISTREAM_RX_BUFFER_SIZE
14 #define SPISTREAM_RX_BUFFER_SIZE SPISTREAM_MAX_RX_MESSAGE_LENGTH
15 #endif
16 
17 #ifndef SPISTREAM_MAX_TX_MESSAGE_LENGTH
18 #define SPISTREAM_MAX_TX_MESSAGE_LENGTH SPISTREAM_MAX_MESSAGE_LENGTH
19 #endif
20 #ifndef SPISTREAM_MAX_TX_PARALLEL_TRANSACTIONS
21 #define SPISTREAM_MAX_TX_PARALLEL_TRANSACTIONS 4
22 #endif
23 #ifndef SPISTREAM_TX_MAX_BUFFER_PACKAGES
24 #define SPISTREAM_TX_MAX_BUFFER_PACKAGES ( \
25  (SPISTREAM_MAX_TX_MESSAGE_LENGTH / \
26  SPISTREAM_PACKAGE_SIZE) * \
27  SPISTREAM_MAX_TX_PARALLEL_TRANSACTIONS)
28 #endif
29 
30 #define SPISTREAM_INVALID_MESSAGE_ID 0
31 
33  uint8_t tx_message_cnt; // message cnt of next message to be sent
35 };
36 
40 };
41 
43  uint16_t rx_num_packages; // number of packages in buffer
44 
45  uint16_t tx_insert; // next index for package insertion
46  uint16_t tx_read; // next index to read package from
47  uint16_t tx_num_packages; // number of packages in buffer
48 
49 // RX stores data as array
51 // TX stores packages
52  struct AutopilotMessagePTStream tx[SPISTREAM_TX_MAX_BUFFER_PACKAGES];
53 };
54 
55 typedef void (*spistream_message_rx_handler_t)(uint8_t msg_id, uint8_t * data, uint16_t num_bytes);
56 typedef void (*spistream_message_tx_handler_t)(uint8_t msg_id);
58 // Handler to call for processing received message
60 // Handler to call after message transmission
62 };
63 
65 
66 /* Function declarations */
67 
68 static inline void spistream_init(spistream_message_rx_handler_t message_rx_handler,
69  spistream_message_tx_handler_t message_tx_handler);
70 static inline void spistream_read_pkg(struct AutopilotMessagePTStream * pkg_in);
71 static inline void spistream_write_pkg(struct AutopilotMessagePTStream * pkg_out);
72 static inline uint8_t spistream_send_msg(uint8_t * data, uint16_t num_bytes, enum spistream_flag);
73 
74 /* Definitions */
75 
79 
82 {
83  memset(&spistream_buffers, 0, sizeof(struct spistream_buffers_t));
84  memset(&spistream_state, 0, sizeof(struct spistream_state_t));
90 }
91 
99 static inline void spistream_read_pkg(struct AutopilotMessagePTStream * pkg_in)
100 {
101  uint8_t package_cntd;
102 
103  if(pkg_in->message_cnt == SPISTREAM_INVALID_MESSAGE_ID) {
104  return;
105  }
106 
107  // In the last package of every message, the package_cntd is expected to be
108  // negative or 0. It indicates the number of zero-bytes that are padded to
109  // the end of the message to fill a package.
110  if(pkg_in->package_cntd <= 0) { package_cntd = 1; }
111  else { package_cntd = pkg_in->package_cntd; }
112 
113  if(pkg_in->package_cntd >= spistream_buffers.rx_num_packages) {
114  spistream_buffers.rx_num_packages = pkg_in->package_cntd;
115  }
116 
117  if(spistream_state.rx_package_cntd == 0) { // Beginning of new message
118  // Message length is first value of package countdown:
119  spistream_buffers.rx_num_packages = package_cntd;
120  spistream_state.rx_package_cntd = package_cntd;
121  }
122  memcpy(spistream_buffers.rx +
123  ((spistream_buffers.rx_num_packages - package_cntd) *
124  SPISTREAM_PACKAGE_SIZE),
125  pkg_in->pkg_data,
126  SPISTREAM_PACKAGE_SIZE);
127 
128  if(pkg_in->package_cntd <= 0) {
129  // Message is ready, pass to handler:
130  spistream.message_rx_handler(pkg_in->message_cnt,
133  SPISTREAM_PACKAGE_SIZE) +
134  pkg_in->package_cntd);
136  }
137 }
138 
143 static inline void spistream_write_pkg(struct AutopilotMessagePTStream * pkg_out)
144 {
146  memset(pkg_out, 0, sizeof(struct AutopilotMessagePTStream));
147  pkg_out->message_cnt = SPISTREAM_INVALID_MESSAGE_ID;
148  return;
149  }
150 
151  memcpy(pkg_out,
153  sizeof(struct AutopilotMessagePTStream));
154  if(pkg_out->package_cntd <= 0) {
155  spistream.message_tx_handler(pkg_out->message_cnt);
156  }
157 
161  }
162 
164 }
165 
171 static inline uint8_t spistream_enqueue_msg(uint8_t * data,
172  uint16_t num_bytes,
173  enum spistream_flag wait_for_read)
174 {
175  uint16_t pkg_idx, num_packages, num_padding;
176  uint16_t idx;
177  // Enough space in buffer?
178 
179  if(wait_for_read == SPISTREAM_NO_WAIT ||
181  {
183  // Message id 0 is reserved for invalid packages:
186  }
187  // How many packages we need for this message:
188  num_packages = (num_bytes / SPISTREAM_PACKAGE_SIZE);
189  if(num_bytes % SPISTREAM_PACKAGE_SIZE != 0) {
190  num_packages++;
191  }
192  // How many zero-bytes we will have at the end of the last package:
193  if(num_bytes > SPISTREAM_PACKAGE_SIZE) {
194  num_padding = (num_packages * SPISTREAM_PACKAGE_SIZE) - num_bytes;
195  }
196  else {
197  num_padding = SPISTREAM_PACKAGE_SIZE - num_bytes;
198  }
199 
200  pkg_idx = spistream_buffers.tx_insert;
201 
202  // Convert data to packages and add them to TX buffer:
203  for(idx = 0; num_packages > 0; idx++) {
204  if(idx < num_bytes) {
205  spistream_buffers.tx[pkg_idx].pkg_data[idx % SPISTREAM_PACKAGE_SIZE] = data[idx];
206  }
207  else { // padding
208  spistream_buffers.tx[pkg_idx].pkg_data[idx % SPISTREAM_PACKAGE_SIZE] = 0;
209  }
210  // Last byte in current package:
211  if((idx % SPISTREAM_PACKAGE_SIZE) == SPISTREAM_PACKAGE_SIZE-1) {
212 
213  // Finish configuration of current package
214  // Last package uses field package_cntd to indicate the number
215  // of padding bytes it contains, as negative number:
216  if(num_packages == 1) {
217  spistream_buffers.tx[pkg_idx].package_cntd = -num_padding;
218  }
219  else {
220  spistream_buffers.tx[pkg_idx].package_cntd = num_packages;
221  }
222  spistream_buffers.tx[pkg_idx].message_cnt = spistream_state.tx_message_cnt;
223 
224  // Prepare next package:
225  num_packages--;
226  // Increment insert pointer with ring buffer overflow:
230  }
231  // Continue with next package:
232  pkg_idx = spistream_buffers.tx_insert;
234  }
235  }
236 #if 0
237 printf("Enqueue finished. Buffer: \n");
238  for(pkg_idx = 0; pkg_idx < spistream_buffers.tx_num_packages; pkg_idx++) {
239  printf("Package %2d | %3d |: ", pkg_idx, spistream_buffers.tx[pkg_idx].package_cntd);
240  for(idx = 0; idx < SPISTREAM_PACKAGE_SIZE; idx++) {
241  printf("%3d ", spistream_buffers.tx[pkg_idx].pkg_data[idx]);
242  }
243  printf("\n");
244  }
245 #endif
246 
247  return 1;
248  }
249  return 0;
250 }
251 
252 static inline void spistream_dequeue_msg(uint8_t message_id) {
253 }
254 
263 static inline uint8_t spistream_send_msg(uint8_t * data,
264  uint16_t num_bytes,
265  enum spistream_flag wait_for_read)
266 {
267  return spistream_enqueue_msg(data, num_bytes, wait_for_read);
268 }
269 
270 #endif /* SPISTREAM_PROTOCOL_H__ */
271 
unsigned short uint16_t
Definition: types.h:16
struct AutopilotMessagePTStream tx[SPISTREAM_TX_MAX_BUFFER_PACKAGES]
static uint8_t spistream_enqueue_msg(uint8_t *data, uint16_t num_bytes, enum spistream_flag wait_for_read)
Enqueue given message in TX buffer.
static uint8_t spistream_send_msg(uint8_t *data, uint16_t num_bytes, enum spistream_flag)
Used from userland: Send num_bytes bytes from buffer over spistream.
spistream_message_rx_handler_t message_rx_handler
#define SPISTREAM_INVALID_MESSAGE_ID
static void spistream_dequeue_msg(uint8_t message_id)
static struct spistream_state_t spistream_state
static struct spistream_buffers_t spistream_buffers
#define SPISTREAM_RX_BUFFER_SIZE
unsigned char uint8_t
Definition: types.h:14
void(* spistream_message_rx_handler_t)(uint8_t msg_id, uint8_t *data, uint16_t num_bytes)
static void spistream_init(spistream_message_rx_handler_t message_rx_handler, spistream_message_tx_handler_t message_tx_handler)
uint8_t rx[SPISTREAM_RX_BUFFER_SIZE]
spistream_flag
static void spistream_read_pkg(struct AutopilotMessagePTStream *pkg_in)
Read a single package into internal RX buffer.
#define SPISTREAM_TX_MAX_BUFFER_PACKAGES
void(* spistream_message_tx_handler_t)(uint8_t msg_id)
static void spistream_write_pkg(struct AutopilotMessagePTStream *pkg_out)
Fill given SPI package with next package from TX buffer.
spistream_message_tx_handler_t message_tx_handler
static struct spistream_config_t spistream