virtmem
virtual memory library for Arduino
serial_utils.hpp
1 #include <Arduino.h>
2 
3 #include "serial_utils.h"
4 
6 
7 namespace virtmem {
8 
9 namespace serram_utils {
10 
11 enum { CMD_START = 0xFF };
12 
13 template <typename IOStream> void purgeSerial(IOStream *stream)
14 {
15  uint32_t n;
16  while ((n = stream->available()))
17  {
18  for (; n; --n)
19  stream->read();
20  }
21 }
22 
23 template <typename IOStream> void writeUInt32(IOStream *stream, uint32_t i)
24 {
25  stream->write(i & 0xFF);
26  stream->write((i >> 8) & 0xFF);
27  stream->write((i >> 16) & 0xFF);
28  stream->write((i >> 24) & 0xFF);
29 }
30 
31 template <typename IOStream> void writeBlock(IOStream *stream, const uint8_t *data, uint32_t size)
32 {
33  stream->write(data, size);
34 }
35 
36 template <typename IOStream> uint32_t readUInt32(IOStream *stream)
37 {
38  uint8_t i = 0;
39  uint32_t ret = 0;
40  while (i < 4)
41  {
42  if (stream->available())
43  {
44  ret |= (stream->read() << (i * 8));
45  ++i;
46  }
47  }
48  return ret;
49 }
50 
51 template <typename IOStream> uint16_t readUInt16(IOStream *stream)
52 {
53  while (true)
54  {
55  if (stream->available() >= 2)
56  return stream->read() | (stream->read() << 8);
57  }
58 }
59 
60 template <typename IOStream> uint8_t readUInt8(IOStream *stream)
61 {
62  while (!stream->available())
63  ;
64  return stream->read();
65 }
66 
67 template <typename IOStream> void readBlock(IOStream *stream, char *data, uint32_t size)
68 {
69  while (size)
70  size -= stream->readBytes(data, size);
71 }
72 
73 template <typename IOStream> void sendWriteCommand(IOStream *stream, uint8_t cmd)
74 {
75  stream->write(CMD_START);
76  stream->write(cmd);
77 }
78 
79 template <typename IOStream> void sendReadCommand(IOStream *stream, uint8_t cmd)
80 {
81  purgeSerial(stream);
82  stream->write(CMD_START);
83  stream->write(cmd);
84 }
85 
86 template <typename IOStream> bool waitForCommand(IOStream *stream, uint8_t cmd, uint8_t timeout)
87 {
88  stream->flush();
89  const uint32_t endtime = millis() + timeout;
90 
91  bool gotinit = false;
92  while (millis() < endtime)
93  {
94  while (Serial.available())
95  {
96  const uint8_t b = stream->read();
97 
98  if (!gotinit && b == CMD_START)
99  gotinit = true;
100  else if (gotinit && b == cmd)
101  return true;
102  }
103  }
104 
105  return false;
106 }
107 
108 template <typename IOStream> void init(IOStream *stream, uint32_t baud, uint32_t poolsize)
109 {
110  stream->begin(baud);
111 
112  // handshake
113  while (true)
114  {
115  sendWriteCommand(stream, CMD_INIT);
116  if (waitForCommand(stream, CMD_INIT, 50))
117  break;
118  }
119 #if 0
120  waitForCommand(stream, CMD_INIT);
121  sendWriteCommand(stream, CMD_INIT); // reply
122 #endif
123 
124  // Purge any remaining handshake responses from serial script. For some reason,
125  // a simple delay and then purging is not enough, we have to actually use the serial
126  // during the wait period to really get everything out.
127  const uint32_t endtime = millis() + 75;
128  while (millis() < endtime)
129  purgeSerial(stream);
130 
131  sendWriteCommand(stream, CMD_INITPOOL);
132  writeUInt32(stream, poolsize);
133  stream->flush();
134 }
135 
136 
137 template <typename IOStream> uint32_t SerialInput<IOStream>::available()
138 {
139  sendReadCommand(stream, CMD_INPUTAVAILABLE);
140  stream->flush();
141  return readUInt32(stream);
142 }
143 
144 template <typename IOStream> uint32_t SerialInput<IOStream>::availableAtLeast()
145 {
146  if (availableMin == 0)
147  availableMin = available();
148  return availableMin;
149 }
150 
151 template <typename IOStream> int16_t SerialInput<IOStream>::read()
152 {
153  sendReadCommand(stream, CMD_INPUTREQUEST);
154  writeUInt32(stream, 1);
155  stream->flush();
156 
157  if (readUInt32(stream) == 0)
158  return -1; // no data
159 
160  if (availableMin)
161  --availableMin;
162  return readUInt8(stream);
163 }
164 
165 template <typename IOStream> uint32_t SerialInput<IOStream>::readBytes(char *buffer, uint32_t count)
166 {
167  sendReadCommand(stream, CMD_INPUTREQUEST);
168  writeUInt32(stream, count);
169  stream->flush();
170  count = readUInt32(stream);
171  for (uint32_t i=0; i<count; ++i, ++buffer)
172  *buffer = readUInt8(stream);
173  if (availableMin > count)
174  availableMin -= count;
175  else
176  availableMin = 0;
177  return count;
178 }
179 
180 template <typename IOStream> int16_t SerialInput<IOStream>::peek()
181 {
182  sendReadCommand(stream, CMD_INPUTPEEK);
183  stream->flush();
184  if (readUInt8(stream) == 0)
185  return -1; // nothing there
186  return readUInt8(stream);
187 }
188 
189 
190 }
191 
192 }
193 
contains all code from virtmem
Definition: base_alloc.cpp:22
int16_t read(void)
Read a byte from serial input.
This file contains utilities for the serial virtual memory allocator.
uint32_t availableAtLeast(void)
Returns the minimum number of bytes that can be read.
int16_t peek(void)
Reads a byte from serial input without removing it from the serial buffer.
uint32_t readBytes(char *buffer, uint32_t count)
Read multiple bytes from serial input.
uint32_t available(void)
Available bytes that can be read via serial.