Kangaroo Library for Arduino
Use reliable Packet Serial to communicate with your Kangaroo.
Kangaroo.h
Go to the documentation of this file.
1 /*
2 Arduino Library for Kangaroo
3 Copyright (c) 2013-2014 Dimension Engineering LLC
4 http://www.dimensionengineering.com/kangaroo
5 
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9 
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
14 RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
16 USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 
19 #ifndef Kangaroo_h
20 #define Kangaroo_h
21 
27 #if defined(ARDUINO) && ARDUINO < 100
28 #error "This library requires Arduino 1.0 or newer."
29 #endif
30 
31 #include <Arduino.h>
32 #define KANGAROO_BIT_PACKED_MAX_VALUE 536870911
33 #define KANGAROO_COMMAND_MAX_DATA_LENGTH 27
34 #define KANGAROO_COMMAND_MAX_BUFFER_LENGTH 32
35 #define KANGAROO_CRC_GOOD_VALUE 0x307e
36 #define KANGAROO_DEFAULT_ADDRESS 128
37 #define KANGAROO_DEFAULT_COMMAND_RETRY_INTERVAL 100
38 #define KANGAROO_DEFAULT_COMMAND_TIMEOUT KANGAROO_INFINITE_TIMEOUT
39 #define KANGAROO_INFINITE_TIMEOUT -1
40 #define KANGAROO_UNSPECIFIED_LIMIT -1
41 
42 class Kangaroo;
43 class KangarooChannel;
44 class KangarooMonitor;
45 
51 {
52  // Negative values are responses from the library, though they may *correspond* to remote states.
53  // Positive values are responses from the Kangaroo.
59  KANGAROO_UNRECOGNIZED_CODE = 0x05,
61  KANGAROO_INVALID_STATUS = -0x01,
63  KANGAROO_PORT_NOT_OPEN = -0x03 // The serial port is not open. (Not returned by the Arduino library at present.)
64 };
65 
71 {
72  KANGAROO_GETP = 0x01,
73  KANGAROO_GETPI = 0x41,
74  KANGAROO_GETS = 0x02,
75  KANGAROO_GETSI = 0x42,
76  KANGAROO_GETMIN = 0x08,
78 };
79 
85 {
87  KANGAROO_GET_ECHO_CODE = 0x10,
89  KANGAROO_GET_SEQUENCE_CODE = 0x40
90 };
91 
97 {
101  KANGAROO_MOVE_SEQUENCE_CODE = 0x40
102 };
103 
109 {
113  KANGAROO_STATUS_ECHO_CODE = 0x10,
115  KANGAROO_STATUS_SEQUENCE_CODE = 0x40
116 };
117 
118 enum KangarooCommand
119 {
120  KANGAROO_CMD_START = 0x20,
121  KANGAROO_CMD_UNITS = 0x21,
122  KANGAROO_CMD_HOME = 0x22,
123  KANGAROO_CMD_STATUS = 0x23,
124  KANGAROO_CMD_MOVE = 0x24,
125  KANGAROO_CMD_SYSTEM = 0x25
126 };
127 
133 {
162 };
163 
164 enum KangarooReplyCode
165 {
166  KANGAROO_RC_STATUS = 0x43
167 };
168 
169 class KangarooCRC
170 {
171 public:
172  void begin();
173  void write(byte data);
174  void write(const byte* data, size_t lengthOfData);
175  void end ();
176 
177 public:
178  inline uint16_t value() const { return _crc; }
179  void value(uint16_t crc) { _crc = crc; }
180 
181  static uint16_t value(const byte* data, size_t lengthOfData);
182 
183 private:
184  uint16_t _crc;
185 };
186 
187 class KangarooCommandWriter
188 {
189 public:
190  KangarooCommandWriter();
191 
192 public:
193  inline const byte* data () const { return _data; }
194  inline size_t length () const { return _length; }
195 
196 public:
197  void write ( byte data );
198  void write (const byte* data, size_t length);
199  void writeBitPackedNumber( int32_t number );
200 
201 public:
202  size_t writeToBuffer(byte* buffer, byte address, KangarooCommand command) const;
203  static size_t writeToBuffer(byte* buffer, byte address, KangarooCommand command, const byte* data, size_t lengthOfData);
204  void writeToStream(Stream& port, byte address, KangarooCommand command) const;
205  static void writeToStream(Stream& port, byte address, KangarooCommand command, const byte* data, size_t lengthOfData);
206 
207 private:
208  byte _address, _command; size_t _length;
209  byte _data[KANGAROO_COMMAND_MAX_DATA_LENGTH];
210 };
211 
212 class KangarooReplyReceiver
213 {
214 public:
215  KangarooReplyReceiver();
216 
217 public:
218  inline byte address() const { return _data[0]; }
219  inline KangarooReplyCode command() const { return (KangarooReplyCode)_data[1]; }
220  inline const byte* data () const { return &_data[3]; }
221  inline size_t length () const { return _length - 5; }
222 
223 public:
224  inline boolean ready() const { return _ready; }
225  void read (byte data);
226  void reset();
227 
228 private:
229  size_t _length; boolean _ready;
230  byte _data[KANGAROO_COMMAND_MAX_BUFFER_LENGTH];
231 };
232 
233 class KangarooReplyReader
234 {
235 public:
236  KangarooReplyReader(const byte* data, size_t length);
237 
238 public:
239  boolean canRead () const;
240  boolean tryRead (byte* value);
241  byte read ();
242  int32_t readBitPackedNumber();
243 
244 private:
245  const byte* _data;
246  const byte* _dataEnd;
247 };
248 
256 {
257 public:
258  KangarooStatus();
259  KangarooStatus(const byte* data, size_t length);
260 
261 public:
262  static KangarooStatus createInvalidStatus();
263  static KangarooStatus createTimedOut ();
264 
265 public:
270  inline char channel() const { return (char)_channel; }
271 
276  inline KangarooStatusFlags flags() const { return (KangarooStatusFlags)_flags; }
277 
282  inline KangarooGetType type() const { return (KangarooGetType)_type; }
283 
288  inline int32_t value() const { return _value; }
289 
290  inline byte echoCode () const { return _echoCode; }
291  inline byte sequenceCode() const { return _sequenceCode; }
292  inline boolean valid () const { return _valid; }
293 
294 public:
300  boolean busy() const { return 0 != (flags() & KANGAROO_STATUS_BUSY ); }
301 
306  KangarooError error() const { return (KangarooError)(0 != (flags() & KANGAROO_STATUS_ERROR) ? value() : 0); }
307 
313  boolean done() const { return !busy (); }
314 
319  boolean ok() const { return !error(); }
320 
325  boolean timedOut() const { return error() == KANGAROO_TIMED_OUT; }
326 
327 private:
328  static KangarooStatus createFromError(KangarooError error);
329 
330 private:
331  void init ();
332  boolean parse(const byte* data, size_t length);
333 
334 private:
335  boolean _valid;
336  byte _channel, _flags, _echoCode, _sequenceCode, _type;
337  int32_t _value;
338 };
339 
345 {
346  friend class KangarooChannel;
347 
348 public:
353  KangarooSerial(Stream& port);
354 
355 public:
360  inline Stream& port() { return _port; }
361 
362 private:
363  boolean tryReceivePacket();
364 
365 private:
366  KangarooSerial (KangarooSerial& serial); // no copy
367  void operator = (KangarooSerial& serial);
368 
369 private:
370  KangarooReplyReceiver _receiver;
371  Stream& _port;
372 };
373 
381 {
382 public:
387  KangarooTimeout(int32_t timeoutMS);
388 
389 public:
395  boolean canExpire() const;
396 
401  boolean expired() const;
402 
406  void expire();
407 
411  void reset();
412 
413 private:
414  uint32_t _start;
415  int32_t _timeoutMS;
416 };
417 
425 {
426  friend class Kangaroo;
427  friend class KangarooMonitor;
428 
429 public:
443  ~KangarooChannel();
444 
445 public:
450  inline char name() const { return _name; }
451 
456  inline byte address() const { return _address; }
457 
458 public:
465 
476  KangarooError units(int32_t desiredUnits, int32_t machineUnits);
477 
484 
493  KangarooMonitor p(int32_t position, int32_t speedLimit = KANGAROO_UNSPECIFIED_LIMIT, KangarooMoveFlags flags = KANGAROO_MOVE_DEFAULT);
494 
504  KangarooMonitor pi(int32_t positionIncrement, int32_t speedLimit = KANGAROO_UNSPECIFIED_LIMIT, KangarooMoveFlags flags = KANGAROO_MOVE_DEFAULT);
505 
513  KangarooMonitor s(int32_t velocity, int32_t rampLimit = KANGAROO_UNSPECIFIED_LIMIT, KangarooMoveFlags flags = KANGAROO_MOVE_DEFAULT);
514 
525  KangarooMonitor si(int32_t velocityIncrement, int32_t rampLimit = KANGAROO_UNSPECIFIED_LIMIT, KangarooMoveFlags flags = KANGAROO_MOVE_DEFAULT);
526 
527 public:
535 
542  {
543  return get(KANGAROO_GETP, flags);
544  }
545 
552  {
553  return get(KANGAROO_GETPI, flags);
554  }
555 
562  {
563  return get(KANGAROO_GETS, flags);
564  }
565 
572  {
573  return get(KANGAROO_GETSI, flags);
574  }
575 
582  {
583  return get(KANGAROO_GETMIN, flags);
584  }
585 
592  {
593  return get(KANGAROO_GETMAX, flags);
594  }
595 
596 public:
597  // While the following calls violate the standard Arduino casing, they sure are nicer to type.
598  // The contrast between 'p' and 'getP' may confuse as well, so we include these to make life easier for everyone.
599  inline KangarooStatus getp (KangarooGetFlags flags = KANGAROO_GET_DEFAULT) { return getP (flags); }
600  inline KangarooStatus getpi (KangarooGetFlags flags = KANGAROO_GET_DEFAULT) { return getPI (flags); }
601  inline KangarooStatus gets (KangarooGetFlags flags = KANGAROO_GET_DEFAULT) { return getS (flags); }
602  inline KangarooStatus getsi (KangarooGetFlags flags = KANGAROO_GET_DEFAULT) { return getSI (flags); }
603  inline KangarooStatus getmin(KangarooGetFlags flags = KANGAROO_GET_DEFAULT) { return getMin(flags); }
604  inline KangarooStatus getmax(KangarooGetFlags flags = KANGAROO_GET_DEFAULT) { return getMax(flags); }
605 
606 public:
610  inline int32_t commandRetryInterval() const { return _commandRetryInterval; }
611 
615  inline void commandRetryInterval(int32_t intervalMS) { _commandRetryInterval = intervalMS; }
616 
620  inline int32_t commandTimeout() const { return _commandTimeout; }
621 
625  inline void commandTimeout(int32_t timeoutMS) { _commandTimeout = timeoutMS; }
626 
630  inline boolean streaming() const { return _streaming; }
631 
644  inline void streaming(boolean enabled) { _streaming = enabled; }
645 
651  void baudRate(int32_t baudRate);
652 
658 
664 
671  KangarooError serialTimeout(int32_t milliseconds);
672 
683  KangarooError systemCommand(KangarooSystemCommand systemCommand, boolean expectReply, int32_t values[], size_t valueCount);
684 
685 private:
686  KangarooStatus getSpecial(KangarooGetType type, KangarooGetFlags flags, const KangarooTimeout& timeout);
687  KangarooMonitor motion (byte motionType, int32_t motionValue, byte limitType, int32_t limitValue, KangarooMoveFlags flags);
688  KangarooMonitor set (KangarooCommand command,
689  KangarooCommandWriter& contents,
691  KangarooGetType getType = KANGAROO_GETP);
692  void setNoReply(KangarooCommand command, KangarooCommandWriter& contents,
694 
695  boolean getInitialSequenceCodeIfNecessary(const KangarooTimeout& timeout, KangarooStatus& status);
696  boolean updateMonitoredResult(const KangarooTimeout& timeout, boolean acceptRepliesWithStartupSequenceCode);
697 
698 private:
699  KangarooChannel (KangarooChannel& channel); // no copy
700  void operator = (KangarooChannel& channel);
701 
702 private:
703  KangarooSerial& _serial;
704  char _name;
705  byte _address;
706  int32_t _commandRetryInterval;
707  int32_t _commandTimeout;
708  byte _echoCode;
709  uint32_t _monitorCode;
710  KangarooGetType _monitoredGetType;
711  KangarooGetFlags _monitoredGetFlags;
712  KangarooStatus _monitoredGetResult;
713  byte _monitoredSequenceCode;
714  boolean _monitoredSequenceCodeIsReady;
715  boolean _streaming;
716 };
717 
723 {
724  friend class KangarooChannel;
725 
726 public:
731  KangarooStatus status() const;
732 
738  boolean valid() const;
739 
745 
751  KangarooMonitor update(int32_t timeoutMS);
752 
758  KangarooMonitor update(const KangarooTimeout& timeout);
759 
765  KangarooMonitor wait(int32_t timeoutMS = KANGAROO_INFINITE_TIMEOUT);
766 
772  KangarooMonitor wait(const KangarooTimeout& timeout);
773 
774 private:
775  KangarooMonitor(KangarooChannel* channel, uint32_t monitorCode);
776 
777 private:
778  struct
779  {
780  KangarooChannel* channel;
781  uint32_t monitorCode;
782  } _state;
783 };
784 
793 boolean waitAll(size_t count, KangarooMonitor* monitors[], int32_t timeoutMS = KANGAROO_INFINITE_TIMEOUT);
794 
803 boolean waitAll(size_t count, KangarooMonitor* monitors[], const KangarooTimeout& timeout);
804 
813 int waitAny(size_t count, KangarooMonitor* monitors[], int32_t timeoutMS = KANGAROO_INFINITE_TIMEOUT);
814 
823 int waitAny(size_t count, KangarooMonitor* monitors[], const KangarooTimeout& timeout);
824 
825 #endif