Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: pixy2/TPixy2.h
- Revision:
- 10:b1bdc51e1c50
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pixy2/TPixy2.h Tue Nov 24 14:26:05 2020 +0000
@@ -0,0 +1,492 @@
+//
+// begin license header
+//
+// This file is part of Pixy CMUcam5 or "Pixy" for short
+//
+// All Pixy source code is provided under the terms of the
+// GNU General Public License v2 (http://www.gnu.org/licenses/gpl-2.0.html).
+// Those wishing to use Pixy source code, software and/or
+// technologies under different licensing terms should contact us at
+// cmucam@cs.cmu.edu. Such licensing terms are available for
+// all portions of the Pixy codebase presented here.
+//
+// end license header
+//
+// Main Pixy template class. This class takes a link class and uses
+// it to communicate with Pixy over I2C, SPI, UART or USB using the
+// Pixy packet protocol.
+
+#ifndef _TPIXY2_H
+#define _TPIXY2_H
+
+// uncomment to turn on debug prints to console
+#define PIXY_DEBUG
+
+#define PIXY_DEFAULT_ARGVAL 0x80000000
+#define PIXY_BUFFERSIZE 0x104
+#define PIXY_CHECKSUM_SYNC 0xc1af
+#define PIXY_NO_CHECKSUM_SYNC 0xc1ae
+#define PIXY_SEND_HEADER_SIZE 4
+#define PIXY_MAX_PROGNAME 33
+
+#define PIXY_TYPE_REQUEST_CHANGE_PROG 0x02
+#define PIXY_TYPE_REQUEST_RESOLUTION 0x0c
+#define PIXY_TYPE_RESPONSE_RESOLUTION 0x0d
+#define PIXY_TYPE_REQUEST_VERSION 0x0e
+#define PIXY_TYPE_RESPONSE_VERSION 0x0f
+#define PIXY_TYPE_RESPONSE_RESULT 0x01
+#define PIXY_TYPE_RESPONSE_ERROR 0x03
+#define PIXY_TYPE_REQUEST_BRIGHTNESS 0x10
+#define PIXY_TYPE_REQUEST_SERVO 0x12
+#define PIXY_TYPE_REQUEST_LED 0x14
+#define PIXY_TYPE_REQUEST_LAMP 0x16
+#define PIXY_TYPE_REQUEST_FPS 0x18
+
+#define PIXY_RESULT_OK 0
+#define PIXY_RESULT_ERROR -1
+#define PIXY_RESULT_BUSY -2
+#define PIXY_RESULT_CHECKSUM_ERROR -3
+#define PIXY_RESULT_TIMEOUT -4
+#define PIXY_RESULT_BUTTON_OVERRIDE -5
+#define PIXY_RESULT_PROG_CHANGING -6
+
+// RC-servo values
+#define PIXY_RCS_MIN_POS 0
+#define PIXY_RCS_MAX_POS 1000L
+#define PIXY_RCS_CENTER_POS ((PIXY_RCS_MAX_POS - PIXY_RCS_MIN_POS) / 2)
+
+#include "Pixy2CCC.h"
+#include "Pixy2Line.h"
+#include "Pixy2Video.h"
+#include "mbed.h"
+
+struct Version {
+ void print(Serial* serial)
+ {
+ if (serial) {
+ serial->printf("hardware ver: 0x%x firmware ver: %d.%d.%d %s\n", hardware, firmwareMajor, firmwareMinor, firmwareBuild, firmwareType);
+ }
+ }
+
+ // This variable contains the hardware version number.
+ uint16_t hardware;
+ // This variable contains the firmware major version number.
+ uint8_t firmwareMajor;
+ // This variable contains the firmware minor version number.
+ uint8_t firmwareMinor;
+ // This variable contains the firmware build version number.
+ uint16_t firmwareBuild;
+ // This variable contains the a string description of the firmware type.
+ char firmwareType[10];
+};
+
+template <class LinkType>
+class TPixy2 {
+public:
+ TPixy2();
+ TPixy2(SPI* spi);
+ ~TPixy2();
+
+ int8_t init(uint32_t arg = PIXY_DEFAULT_ARGVAL);
+
+ /**
+ * Queries and receives the firmware and hardware version of Pixy2.
+ * It is called automatically as part of init().
+ *
+ * @returns an error value (<0) if it fails and PIXY_RESULT_OK if it succeeds
+ */
+ int8_t getVersion();
+
+ /**
+ * Instructs Pixy2 to switch programs.
+ *
+ * @param prog string with the program name, Values: @TODO
+ * @returns an error value (<0) if it fails and PIXY_RESULT_OK if it succeeds
+ */
+ int8_t changeProg(const char* prog);
+
+ /**
+ * Sets the servo positions of servos plugged into Pixy2's two RC servo connectors.
+ *
+ * @returns an error value (<0) if it fails and PIXY_RESULT_OK if it succeeds
+ */
+ int8_t setServos(uint16_t s0, uint16_t s1);
+
+ /**
+ * Sets the relative exposure level of Pixy2's image sensor.
+ *
+ * @param brightness value between 0(lowest brightness) and 255(max brightness)
+ * @returns an error value (<0) if it fails and PIXY_RESULT_OK if it succeeds
+ */
+ int8_t setCameraBrightness(uint8_t brightness);
+
+ /**
+ * Sets Pixy2's RGB LED value.
+ *
+ * @param r red led brightness value between 0 and 255
+ * @param g green led brightness value between 0 and 255
+ * @param b blue led brighenss value between 0 and 255
+ * @returns an error value (<0) if it fails and PIXY_RESULT_OK if it succeeds
+ */
+ int8_t setLED(uint8_t r, uint8_t g, uint8_t b);
+
+ /**
+ * Turns on/off Pixy2's integrated light source.
+ *
+ * @param upper controls the two white LEDs along the top edge of Pixy2's PCB. Values: 0: off; 1: on
+ * @param lower controls the RGB LED, turning on/off all three color channel, Values: 0: off; 1: on
+ * @returns an error value (<0) if it fails and PIXY_RESULT_OK if it succeeds
+ */
+ int8_t setLamp(uint8_t upper, uint8_t lower);
+
+ /**
+ * Gets the width and height of the frames used by the current program.
+ * After calling this function, the width and height can be found in
+ * the frameWidth and frameHeight member variables
+ *
+ * @returns an error value (<0) if it fails and PIXY_RESULT_OK if it succeeds
+ */
+ int8_t getResolution();
+
+ /**
+ * Gets Pixy2's framerate.
+ *
+ * @returns a value in the range between 2 and 62 frames per second.
+ */
+ int8_t getFPS();
+
+ Version* version;
+ uint16_t frameWidth;
+ uint16_t frameHeight;
+
+ // Color connected components, color codes
+ Pixy2CCC<LinkType> ccc;
+ friend class Pixy2CCC<LinkType>;
+
+ // Line following
+ Pixy2Line<LinkType> line;
+ friend class Pixy2Line<LinkType>;
+
+ // Video
+ Pixy2Video<LinkType> video;
+ friend class Pixy2Video<LinkType>;
+
+ LinkType m_link;
+
+private:
+ void prepareBuffer();
+ int16_t getSync();
+ int16_t recvPacket();
+ int16_t sendPacket();
+
+ uint8_t* m_buf;
+ uint8_t* m_bufPayload;
+ uint8_t m_type;
+ uint8_t m_length;
+ bool m_cs;
+};
+
+template <class LinkType>
+TPixy2<LinkType>::TPixy2()
+ : ccc(this)
+ , line(this)
+ , video(this)
+{
+ prepareBuffer();
+}
+
+template <class LinkType>
+TPixy2<LinkType>::TPixy2(SPI* spi)
+ : ccc(this)
+ , line(this)
+ , video(this)
+{
+ prepareBuffer();
+}
+
+template <class LinkType>
+TPixy2<LinkType>::~TPixy2()
+{
+ m_link.close();
+ free(m_buf);
+}
+
+template <class LinkType>
+void TPixy2<LinkType>::prepareBuffer()
+{
+ // allocate buffer space for send/receive
+ m_buf = (uint8_t*)malloc(PIXY_BUFFERSIZE);
+ // shifted buffer is used for sending, so we have space to write header information
+ m_bufPayload = m_buf + PIXY_SEND_HEADER_SIZE;
+ frameWidth = frameHeight = 0;
+ version = NULL;
+}
+
+template <class LinkType>
+int8_t TPixy2<LinkType>::init(uint32_t arg)
+{
+ uint32_t t0;
+ int8_t res;
+ Timer timer;
+
+ res = m_link.open(arg);
+ if (res < 0)
+ return res;
+
+ timer.start();
+ // wait for pixy to be ready -- that is, Pixy takes a second or 2 boot up
+ // getVersion is an effective "ping". We timeout after 5s.
+ for (t0 = timer.read_ms(); timer.read_ms() - t0 < 5000;) {
+ if (getVersion() >= 0) // successful version get -> pixy is ready
+ {
+ getResolution(); // get resolution so we have it
+ return PIXY_RESULT_OK;
+ }
+ wait_ms(5000); // delay for sync
+ }
+ // timeout
+ return PIXY_RESULT_TIMEOUT;
+}
+
+template <class LinkType>
+int16_t TPixy2<LinkType>::getSync()
+{
+ uint8_t i, j, c, cprev;
+ int16_t res;
+ uint16_t start;
+
+ // parse bytes until we find sync
+ for (i = j = 0, cprev = 0; true; i++) {
+ res = m_link.recv(&c, 1);
+ if (res >= PIXY_RESULT_OK) {
+ // since we're using little endian, previous byte is least significant byte
+ start = cprev;
+ // current byte is most significant byte
+ start |= c << 8;
+ cprev = c;
+ if (start == PIXY_CHECKSUM_SYNC) {
+ m_cs = true;
+ return PIXY_RESULT_OK;
+ }
+ if (start == PIXY_NO_CHECKSUM_SYNC) {
+ m_cs = false;
+ return PIXY_RESULT_OK;
+ }
+ }
+ // If we've read some bytes and no sync, then wait and try again.
+ // And do that several more times before we give up.
+ // Pixy guarantees to respond within 100us.
+ if (i >= 4) {
+ if (j >= 4) {
+#ifdef PIXY_DEBUG
+ // Serial.println("error: no response");
+#endif
+ return PIXY_RESULT_ERROR;
+ }
+ wait_ms(25);
+ j++;
+ i = 0;
+ }
+ }
+}
+
+template <class LinkType>
+int16_t TPixy2<LinkType>::recvPacket()
+{
+ uint16_t csCalc, csSerial;
+ int16_t res;
+
+ res = getSync();
+ if (res < 0)
+ return res;
+
+ if (m_cs) {
+ res = m_link.recv(m_buf, 4);
+ if (res < 0)
+ return res;
+
+ m_type = m_buf[0];
+ m_length = m_buf[1];
+
+ csSerial = *(uint16_t*)&m_buf[2];
+
+ res = m_link.recv(m_buf, m_length, &csCalc);
+ if (res < 0)
+ return res;
+
+ if (csSerial != csCalc) {
+#ifdef PIXY_DEBUG
+ // Serial.println("error: checksum");
+#endif
+ return PIXY_RESULT_CHECKSUM_ERROR;
+ }
+ } else {
+ res = m_link.recv(m_buf, 2);
+ if (res < 0)
+ return res;
+
+ m_type = m_buf[0];
+ m_length = m_buf[1];
+
+ res = m_link.recv(m_buf, m_length);
+ if (res < 0)
+ return res;
+ }
+ return PIXY_RESULT_OK;
+}
+
+template <class LinkType>
+int16_t TPixy2<LinkType>::sendPacket()
+{
+ // write header info at beginnig of buffer
+ m_buf[0] = PIXY_NO_CHECKSUM_SYNC & 0xff;
+ m_buf[1] = PIXY_NO_CHECKSUM_SYNC >> 8;
+ m_buf[2] = m_type;
+ m_buf[3] = m_length;
+ // send whole thing -- header and data in one call
+ return m_link.send(m_buf, m_length + PIXY_SEND_HEADER_SIZE);
+}
+
+template <class LinkType>
+int8_t TPixy2<LinkType>::changeProg(const char* prog)
+{
+ int32_t res;
+
+ // poll for program to change
+ while (1) {
+ strncpy((char*)m_bufPayload, prog, PIXY_MAX_PROGNAME);
+ m_length = PIXY_MAX_PROGNAME;
+ m_type = PIXY_TYPE_REQUEST_CHANGE_PROG;
+ sendPacket();
+ if (recvPacket() == 0) {
+ res = *(uint32_t*)m_buf;
+ if (res > 0) {
+ getResolution(); // get resolution so we have it
+ return PIXY_RESULT_OK; // success
+ }
+ } else
+ return PIXY_RESULT_ERROR; // some kind of bitstream error
+ wait_ms(1000);
+ }
+}
+
+template <class LinkType>
+int8_t TPixy2<LinkType>::getVersion()
+{
+ m_length = 0;
+ m_type = PIXY_TYPE_REQUEST_VERSION;
+ sendPacket();
+ if (recvPacket() == 0) {
+ if (m_type == PIXY_TYPE_RESPONSE_VERSION) {
+ version = (Version*)m_buf;
+ return m_length;
+ } else if (m_type == PIXY_TYPE_RESPONSE_ERROR)
+ return PIXY_RESULT_BUSY;
+ }
+ return PIXY_RESULT_ERROR; // some kind of bitstream error
+}
+
+template <class LinkType>
+int8_t TPixy2<LinkType>::getResolution()
+{
+ m_length = 1;
+ m_bufPayload[0] = 0; // for future types of queries
+ m_type = PIXY_TYPE_REQUEST_RESOLUTION;
+ sendPacket();
+ if (recvPacket() == 0) {
+ if (m_type == PIXY_TYPE_RESPONSE_RESOLUTION) {
+ frameWidth = *(uint16_t*)m_buf;
+ frameHeight = *(uint16_t*)(m_buf + sizeof(uint16_t));
+ return PIXY_RESULT_OK; // success
+ } else
+ return PIXY_RESULT_ERROR;
+ } else
+ return PIXY_RESULT_ERROR; // some kind of bitstream error
+}
+
+template <class LinkType>
+int8_t TPixy2<LinkType>::setCameraBrightness(uint8_t brightness)
+{
+ uint32_t res;
+
+ m_bufPayload[0] = brightness;
+ m_length = 1;
+ m_type = PIXY_TYPE_REQUEST_BRIGHTNESS;
+ sendPacket();
+ if (recvPacket() == 0) // && m_type==PIXY_TYPE_RESPONSE_RESULT && m_length==4)
+ {
+ res = *(uint32_t*)m_buf;
+ return (int8_t)res;
+ } else
+ return PIXY_RESULT_ERROR; // some kind of bitstream error
+}
+
+template <class LinkType>
+int8_t TPixy2<LinkType>::setServos(uint16_t s0, uint16_t s1)
+{
+ uint32_t res;
+
+ *(int16_t*)(m_bufPayload + 0) = s0;
+ *(int16_t*)(m_bufPayload + 2) = s1;
+ m_length = 4;
+ m_type = PIXY_TYPE_REQUEST_SERVO;
+ sendPacket();
+ if (recvPacket() == 0 && m_type == PIXY_TYPE_RESPONSE_RESULT && m_length == 4) {
+ res = *(uint32_t*)m_buf;
+ return (int8_t)res;
+ } else
+ return PIXY_RESULT_ERROR; // some kind of bitstream error
+}
+
+template <class LinkType>
+int8_t TPixy2<LinkType>::setLED(uint8_t r, uint8_t g, uint8_t b)
+{
+ uint32_t res;
+
+ m_bufPayload[0] = r;
+ m_bufPayload[1] = g;
+ m_bufPayload[2] = b;
+ m_length = 3;
+ m_type = PIXY_TYPE_REQUEST_LED;
+ sendPacket();
+ if (recvPacket() == 0 && m_type == PIXY_TYPE_RESPONSE_RESULT && m_length == 4) {
+ res = *(uint32_t*)m_buf;
+ return (int8_t)res;
+ } else
+ return PIXY_RESULT_ERROR; // some kind of bitstream error
+}
+
+template <class LinkType>
+int8_t TPixy2<LinkType>::setLamp(uint8_t upper, uint8_t lower)
+{
+ uint32_t res;
+
+ m_bufPayload[0] = upper;
+ m_bufPayload[1] = lower;
+ m_length = 2;
+ m_type = PIXY_TYPE_REQUEST_LAMP;
+ sendPacket();
+ if (recvPacket() == 0 && m_type == PIXY_TYPE_RESPONSE_RESULT && m_length == 4) {
+ res = *(uint32_t*)m_buf;
+ return (int8_t)res;
+ } else
+ return PIXY_RESULT_ERROR; // some kind of bitstream error
+}
+
+template <class LinkType>
+int8_t TPixy2<LinkType>::getFPS()
+{
+ uint32_t res;
+
+ m_length = 0; // no args
+ m_type = PIXY_TYPE_REQUEST_FPS;
+ sendPacket();
+ if (recvPacket() == 0 && m_type == PIXY_TYPE_RESPONSE_RESULT && m_length == 4) {
+ res = *(uint32_t*)m_buf;
+ return (int8_t)res;
+ } else
+ return PIXY_RESULT_ERROR; // some kind of bitstream error
+}
+
+#endif
+