1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-07-30 16:24:09 +03:00

Robot_Control library to the 1.5 fromat

This commit is contained in:
Fede85
2013-09-10 16:46:33 +02:00
parent 9df65fdfe5
commit a9cba03922
49 changed files with 11 additions and 1 deletions

View File

@ -0,0 +1,690 @@
/*
This is the core graphics library for all our displays, providing a common
set of graphics primitives (points, lines, circles, etc.). It needs to be
paired with a hardware-specific library for each display device we carry
(to handle the lower-level functions).
Adafruit invests time and resources providing this open source code, please
support Adafruit & open-source hardware by purchasing products from Adafruit!
Copyright (c) 2013 Adafruit Industries. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "Adafruit_GFX.h"
#include "glcdfont.c"
#ifdef __AVR__
#include <avr/pgmspace.h>
#else
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
#endif
Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h):
WIDTH(w), HEIGHT(h)
{
_width = WIDTH;
_height = HEIGHT;
rotation = 0;
cursor_y = cursor_x = 0;
textsize = 1;
textcolor = textbgcolor = 0xFFFF;
wrap = true;
}
// Draw a circle outline
void Adafruit_GFX::drawCircle(int16_t x0, int16_t y0, int16_t r,
uint16_t color) {
int16_t f = 1 - r;
int16_t ddF_x = 1;
int16_t ddF_y = -2 * r;
int16_t x = 0;
int16_t y = r;
drawPixel(x0 , y0+r, color);
drawPixel(x0 , y0-r, color);
drawPixel(x0+r, y0 , color);
drawPixel(x0-r, y0 , color);
while (x<y) {
if (f >= 0) {
y--;
ddF_y += 2;
f += ddF_y;
}
x++;
ddF_x += 2;
f += ddF_x;
drawPixel(x0 + x, y0 + y, color);
drawPixel(x0 - x, y0 + y, color);
drawPixel(x0 + x, y0 - y, color);
drawPixel(x0 - x, y0 - y, color);
drawPixel(x0 + y, y0 + x, color);
drawPixel(x0 - y, y0 + x, color);
drawPixel(x0 + y, y0 - x, color);
drawPixel(x0 - y, y0 - x, color);
}
}
void Adafruit_GFX::drawCircleHelper( int16_t x0, int16_t y0,
int16_t r, uint8_t cornername, uint16_t color) {
int16_t f = 1 - r;
int16_t ddF_x = 1;
int16_t ddF_y = -2 * r;
int16_t x = 0;
int16_t y = r;
while (x<y) {
if (f >= 0) {
y--;
ddF_y += 2;
f += ddF_y;
}
x++;
ddF_x += 2;
f += ddF_x;
if (cornername & 0x4) {
drawPixel(x0 + x, y0 + y, color);
drawPixel(x0 + y, y0 + x, color);
}
if (cornername & 0x2) {
drawPixel(x0 + x, y0 - y, color);
drawPixel(x0 + y, y0 - x, color);
}
if (cornername & 0x8) {
drawPixel(x0 - y, y0 + x, color);
drawPixel(x0 - x, y0 + y, color);
}
if (cornername & 0x1) {
drawPixel(x0 - y, y0 - x, color);
drawPixel(x0 - x, y0 - y, color);
}
}
}
void Adafruit_GFX::fillCircle(int16_t x0, int16_t y0, int16_t r,
uint16_t color) {
drawFastVLine(x0, y0-r, 2*r+1, color);
fillCircleHelper(x0, y0, r, 3, 0, color);
}
// Used to do circles and roundrects
void Adafruit_GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r,
uint8_t cornername, int16_t delta, uint16_t color) {
int16_t f = 1 - r;
int16_t ddF_x = 1;
int16_t ddF_y = -2 * r;
int16_t x = 0;
int16_t y = r;
while (x<y) {
if (f >= 0) {
y--;
ddF_y += 2;
f += ddF_y;
}
x++;
ddF_x += 2;
f += ddF_x;
if (cornername & 0x1) {
drawFastVLine(x0+x, y0-y, 2*y+1+delta, color);
drawFastVLine(x0+y, y0-x, 2*x+1+delta, color);
}
if (cornername & 0x2) {
drawFastVLine(x0-x, y0-y, 2*y+1+delta, color);
drawFastVLine(x0-y, y0-x, 2*x+1+delta, color);
}
}
}
// Bresenham's algorithm - thx wikpedia
void Adafruit_GFX::drawLine(int16_t x0, int16_t y0,
int16_t x1, int16_t y1,
uint16_t color) {
int16_t steep = abs(y1 - y0) > abs(x1 - x0);
if (steep) {
swap(x0, y0);
swap(x1, y1);
}
if (x0 > x1) {
swap(x0, x1);
swap(y0, y1);
}
int16_t dx, dy;
dx = x1 - x0;
dy = abs(y1 - y0);
int16_t err = dx / 2;
int16_t ystep;
if (y0 < y1) {
ystep = 1;
} else {
ystep = -1;
}
for (; x0<=x1; x0++) {
if (steep) {
drawPixel(y0, x0, color);
} else {
drawPixel(x0, y0, color);
}
err -= dy;
if (err < 0) {
y0 += ystep;
err += dx;
}
}
}
// Draw a rectangle
void Adafruit_GFX::drawRect(int16_t x, int16_t y,
int16_t w, int16_t h,
uint16_t color) {
drawFastHLine(x, y, w, color);
drawFastHLine(x, y+h-1, w, color);
drawFastVLine(x, y, h, color);
drawFastVLine(x+w-1, y, h, color);
}
void Adafruit_GFX::drawFastVLine(int16_t x, int16_t y,
int16_t h, uint16_t color) {
// Update in subclasses if desired!
drawLine(x, y, x, y+h-1, color);
}
void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y,
int16_t w, uint16_t color) {
// Update in subclasses if desired!
drawLine(x, y, x+w-1, y, color);
}
void Adafruit_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
uint16_t color) {
// Update in subclasses if desired!
for (int16_t i=x; i<x+w; i++) {
drawFastVLine(i, y, h, color);
}
}
void Adafruit_GFX::fillScreen(uint16_t color) {
fillRect(0, 0, _width, _height, color);
}
// Draw a rounded rectangle
void Adafruit_GFX::drawRoundRect(int16_t x, int16_t y, int16_t w,
int16_t h, int16_t r, uint16_t color) {
// smarter version
drawFastHLine(x+r , y , w-2*r, color); // Top
drawFastHLine(x+r , y+h-1, w-2*r, color); // Bottom
drawFastVLine(x , y+r , h-2*r, color); // Left
drawFastVLine(x+w-1, y+r , h-2*r, color); // Right
// draw four corners
drawCircleHelper(x+r , y+r , r, 1, color);
drawCircleHelper(x+w-r-1, y+r , r, 2, color);
drawCircleHelper(x+w-r-1, y+h-r-1, r, 4, color);
drawCircleHelper(x+r , y+h-r-1, r, 8, color);
}
// Fill a rounded rectangle
void Adafruit_GFX::fillRoundRect(int16_t x, int16_t y, int16_t w,
int16_t h, int16_t r, uint16_t color) {
// smarter version
fillRect(x+r, y, w-2*r, h, color);
// draw four corners
fillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, color);
fillCircleHelper(x+r , y+r, r, 2, h-2*r-1, color);
}
// Draw a triangle
void Adafruit_GFX::drawTriangle(int16_t x0, int16_t y0,
int16_t x1, int16_t y1,
int16_t x2, int16_t y2, uint16_t color) {
drawLine(x0, y0, x1, y1, color);
drawLine(x1, y1, x2, y2, color);
drawLine(x2, y2, x0, y0, color);
}
// Fill a triangle
void Adafruit_GFX::fillTriangle ( int16_t x0, int16_t y0,
int16_t x1, int16_t y1,
int16_t x2, int16_t y2, uint16_t color) {
int16_t a, b, y, last;
// Sort coordinates by Y order (y2 >= y1 >= y0)
if (y0 > y1) {
swap(y0, y1); swap(x0, x1);
}
if (y1 > y2) {
swap(y2, y1); swap(x2, x1);
}
if (y0 > y1) {
swap(y0, y1); swap(x0, x1);
}
if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing
a = b = x0;
if(x1 < a) a = x1;
else if(x1 > b) b = x1;
if(x2 < a) a = x2;
else if(x2 > b) b = x2;
drawFastHLine(a, y0, b-a+1, color);
return;
}
int16_t
dx01 = x1 - x0,
dy01 = y1 - y0,
dx02 = x2 - x0,
dy02 = y2 - y0,
dx12 = x2 - x1,
dy12 = y2 - y1,
sa = 0,
sb = 0;
// For upper part of triangle, find scanline crossings for segments
// 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1
// is included here (and second loop will be skipped, avoiding a /0
// error there), otherwise scanline y1 is skipped here and handled
// in the second loop...which also avoids a /0 error here if y0=y1
// (flat-topped triangle).
if(y1 == y2) last = y1; // Include y1 scanline
else last = y1-1; // Skip it
for(y=y0; y<=last; y++) {
a = x0 + sa / dy01;
b = x0 + sb / dy02;
sa += dx01;
sb += dx02;
/* longhand:
a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
*/
if(a > b) swap(a,b);
drawFastHLine(a, y, b-a+1, color);
}
// For lower part of triangle, find scanline crossings for segments
// 0-2 and 1-2. This loop is skipped if y1=y2.
sa = dx12 * (y - y1);
sb = dx02 * (y - y0);
for(; y<=y2; y++) {
a = x1 + sa / dy12;
b = x0 + sb / dy02;
sa += dx12;
sb += dx02;
/* longhand:
a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
*/
if(a > b) swap(a,b);
drawFastHLine(a, y, b-a+1, color);
}
}
void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
const uint8_t *bitmap, int16_t w, int16_t h,
uint16_t color) {
int16_t i, j, byteWidth = (w + 7) / 8;
for(j=0; j<h; j++) {
for(i=0; i<w; i++ ) {
if(pgm_read_byte(bitmap + j * byteWidth + i / 8) & (128 >> (i & 7))) {
drawPixel(x+i, y+j, color);
}
}
}
}
#if ARDUINO >= 100
size_t Adafruit_GFX::write(uint8_t c) {
#else
void Adafruit_GFX::write(uint8_t c) {
#endif
if (c == '\n') {
cursor_y += textsize*8;
cursor_x = 0;
} else if (c == '\r') {
// skip em
} else {
drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize);
cursor_x += textsize*6;
if (wrap && (cursor_x > (_width - textsize*6))) {
cursor_y += textsize*8;
cursor_x = 0;
}
}
#if ARDUINO >= 100
return 1;
#endif
}
// Draw a character
void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
uint16_t color, uint16_t bg, uint8_t size) {
if((x >= _width) || // Clip right
(y >= _height) || // Clip bottom
((x + 6 * size - 1) < 0) || // Clip left
((y + 8 * size - 1) < 0)) // Clip top
return;
for (int8_t i=0; i<6; i++ ) {
uint8_t line;
if (i == 5)
line = 0x0;
else
line = pgm_read_byte(font+(c*5)+i);
for (int8_t j = 0; j<8; j++) {
if (line & 0x1) {
if (size == 1) // default size
drawPixel(x+i, y+j, color);
else { // big size
fillRect(x+(i*size), y+(j*size), size, size, color);
}
} else if (bg != color) {
if (size == 1) // default size
drawPixel(x+i, y+j, bg);
else { // big size
fillRect(x+i*size, y+j*size, size, size, bg);
}
}
line >>= 1;
}
}
}
void Adafruit_GFX::setCursor(int16_t x, int16_t y) {
cursor_x = x;
cursor_y = y;
}
void Adafruit_GFX::setTextSize(uint8_t s) {
textsize = (s > 0) ? s : 1;
}
void Adafruit_GFX::setTextColor(uint16_t c) {
// For 'transparent' background, we'll set the bg
// to the same as fg instead of using a flag
textcolor = textbgcolor = c;
}
void Adafruit_GFX::setTextColor(uint16_t c, uint16_t b) {
textcolor = c;
textbgcolor = b;
}
void Adafruit_GFX::setTextWrap(boolean w) {
wrap = w;
}
uint8_t Adafruit_GFX::getRotation(void) {
return rotation;
}
void Adafruit_GFX::setRotation(uint8_t x) {
rotation = (x & 3);
switch(rotation) {
case 0:
case 2:
_width = WIDTH;
_height = HEIGHT;
break;
case 1:
case 3:
_width = HEIGHT;
_height = WIDTH;
break;
}
}
// Return the size of the display (per current rotation)
int16_t Adafruit_GFX::width(void) {
return _width;
}
int16_t Adafruit_GFX::height(void) {
return _height;
}
void Adafruit_GFX::invertDisplay(boolean i) {
// Do nothing, must be subclassed if supported
}
uint16_t Adafruit_GFX::newColor(uint8_t r, uint8_t g, uint8_t b) {
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}
void Adafruit_GFX::background(uint8_t red, uint8_t green, uint8_t blue) {
background(newColor(red, green, blue));
}
void Adafruit_GFX::background(color c) {
fillScreen(c);
}
void Adafruit_GFX::stroke(uint8_t red, uint8_t green, uint8_t blue) {
stroke(newColor(red, green, blue));
}
void Adafruit_GFX::stroke(color c) {
useStroke = true;
strokeColor = c;
setTextColor(c);
}
void Adafruit_GFX::noStroke() {
useStroke = false;
}
void Adafruit_GFX::noFill() {
useFill = false;
}
void Adafruit_GFX::fill(uint8_t red, uint8_t green, uint8_t blue) {
fill(newColor(red, green, blue));
}
void Adafruit_GFX::fill(color c) {
useFill = true;
fillColor = c;
}
void Adafruit_GFX::text(int value, uint8_t x, uint8_t y){
if (!useStroke)
return;
setTextWrap(false);
setTextColor(strokeColor);
setCursor(x, y);
print(value);
}
void Adafruit_GFX::text(long value, uint8_t x, uint8_t y){
if (!useStroke)
return;
setTextWrap(false);
setTextColor(strokeColor);
setCursor(x, y);
print(value);
}
void Adafruit_GFX::text(char value, uint8_t x, uint8_t y){
if (!useStroke)
return;
setTextWrap(false);
setTextColor(strokeColor);
setCursor(x, y);
print(value);
}
void Adafruit_GFX::text(const char * text, int16_t x, int16_t y) {
if (!useStroke)
return;
setTextWrap(false);
setTextColor(strokeColor);
setCursor(x, y);
print(text);
}
void Adafruit_GFX::textWrap(const char * text, int16_t x, int16_t y) {
if (!useStroke)
return;
setTextWrap(true);
setTextColor(strokeColor);
setCursor(x, y);
print(text);
}
void Adafruit_GFX::textSize(uint8_t size) {
setTextSize(size);
}
void Adafruit_GFX::point(int16_t x, int16_t y) {
if (!useStroke)
return;
drawPixel(x, y, strokeColor);
}
void Adafruit_GFX::line(int16_t x1, int16_t y1, int16_t x2, int16_t y2) {
if (!useStroke)
return;
if (x1 == x2) {
drawFastVLine(x1, y1, y2 - y1, strokeColor);
}
else if (y1 == y2) {
drawFastHLine(x1, y1, x2 - x1, strokeColor);
}
else {
drawLine(x1, y1, x2, y2, strokeColor);
}
}
void Adafruit_GFX::rect(int16_t x, int16_t y, int16_t width, int16_t height) {
if (useFill) {
fillRect(x, y, width, height, fillColor);
}
if (useStroke) {
drawRect(x, y, width, height, strokeColor);
}
}
void Adafruit_GFX::rect(int16_t x, int16_t y, int16_t width, int16_t height, int16_t radius) {
if (radius == 0) {
rect(x, y, width, height);
}
if (useFill) {
fillRoundRect(x, y, width, height, radius, fillColor);
}
if (useStroke) {
drawRoundRect(x, y, width, height, radius, strokeColor);
}
}
void Adafruit_GFX::circle(int16_t x, int16_t y, int16_t r) {
if (r == 0)
return;
if (useFill) {
fillCircle(x, y, r, fillColor);
}
if (useStroke) {
drawCircle(x, y, r, strokeColor);
}
}
void Adafruit_GFX::triangle(int16_t x1, int16_t y1, int16_t x2, int16_t y2, int16_t x3, int16_t y3) {
if (useFill) {
fillTriangle(x1, y1, x2, y2, x3, y3, fillColor);
}
if (useStroke) {
drawTriangle(x1, y1, x2, y2, x3, y3, strokeColor);
}
}
#define BUFFPIXEL 20
/*
void Adafruit_GFX::image(PImage & img, uint16_t x, uint16_t y) {
int w, h, row, col;
uint8_t r, g, b;
uint32_t pos = 0;
uint8_t sdbuffer[3*BUFFPIXEL]; // pixel buffer (R+G+B per pixel)
uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer
// Crop area to be loaded
w = img._bmpWidth;
h = img._bmpHeight;
if((x+w-1) >= width()) w = width() - x;
if((y+h-1) >= height()) h = height() - y;
// Set TFT address window to clipped image bounds
//setAddrWindow(x, y, x+w-1, y+h-1);
for (row=0; row<h; row++) { // For each scanline...
// Seek to start of scan line. It might seem labor-
// intensive to be doing this on every line, but this
// method covers a lot of gritty details like cropping
// and scanline padding. Also, the seek only takes
// place if the file position actually needs to change
// (avoids a lot of cluster math in SD library).
if(img._flip) // Bitmap is stored bottom-to-top order (normal BMP)
pos = img._bmpImageoffset + (img._bmpHeight - 1 - row) * img._rowSize;
else // Bitmap is stored top-to-bottom
pos = img._bmpImageoffset + row * img._rowSize;
if(img._bmpFile.position() != pos) { // Need seek?
img._bmpFile.seek(pos);
buffidx = sizeof(sdbuffer); // Force buffer reload
}
for (col=0; col<w; col++) { // For each pixel...
// Time to read more pixel data?
if (buffidx >= sizeof(sdbuffer)) { // Indeed
img._bmpFile.read(sdbuffer, sizeof(sdbuffer));
buffidx = 0; // Set index to beginning
}
// Convert pixel from BMP to TFT format, push to display
b = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
//pushColor(tft.Color565(r,g,b));
drawPixel(x + col, y + row, newColor(r, g, b));
} // end pixel
} // end scanline
}*/

View File

@ -0,0 +1,190 @@
/******************************************************************
This is the core graphics library for all our displays, providing
basic graphics primitives (points, lines, circles, etc.). It needs
to be paired with a hardware-specific library for each display
device we carry (handling the lower-level functions).
Adafruit invests time and resources providing this open
source code, please support Adafruit and open-source hardware
by purchasing products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, check license.txt for more information.
All text above must be included in any redistribution.
******************************************************************/
#ifndef _ADAFRUIT_GFX_H
#define _ADAFRUIT_GFX_H
#if ARDUINO >= 100
#include "Arduino.h"
#include "Print.h"
#else
#include "WProgram.h"
#endif
//#include "PImage.h"
#define swap(a, b) { int16_t t = a; a = b; b = t; }
/* TODO
enum RectMode {
CORNER,
CORNERS,
RADIUS,
CENTER
};
*/
typedef uint16_t color;
class Adafruit_GFX : public Print {
public:
Adafruit_GFX(int16_t w, int16_t h); // Constructor
// This MUST be defined by the subclass:
virtual void drawPixel(int16_t x, int16_t y, uint16_t color) = 0;
// These MAY be overridden by the subclass to provide device-specific
// optimized code. Otherwise 'generic' versions are used.
virtual void
drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color),
drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color),
drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color),
drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color),
fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color),
fillScreen(uint16_t color),
invertDisplay(boolean i);
// These exist only with Adafruit_GFX (no subclass overrides)
void
drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color),
drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,
uint16_t color),
fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color),
fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,
int16_t delta, uint16_t color),
drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
int16_t x2, int16_t y2, uint16_t color),
fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
int16_t x2, int16_t y2, uint16_t color),
drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h,
int16_t radius, uint16_t color),
fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h,
int16_t radius, uint16_t color),
drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap,
int16_t w, int16_t h, uint16_t color),
drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color,
uint16_t bg, uint8_t size),
setCursor(int16_t x, int16_t y),
setTextColor(uint16_t c),
setTextColor(uint16_t c, uint16_t bg),
setTextSize(uint8_t s),
setTextWrap(boolean w),
setRotation(uint8_t r);
#if ARDUINO >= 100
virtual size_t write(uint8_t);
#else
virtual void write(uint8_t);
#endif
int16_t
height(void),
width(void);
uint8_t getRotation(void);
/*
* Processing-like graphics primitives
*/
/// transforms a color in 16-bit form given the RGB components.
/// The default implementation makes a 5-bit red, a 6-bit
/// green and a 5-bit blue (MSB to LSB). Devices that use
/// different scheme should override this.
virtual uint16_t newColor(uint8_t red, uint8_t green, uint8_t blue);
// http://processing.org/reference/background_.html
void background(uint8_t red, uint8_t green, uint8_t blue);
void background(color c);
// http://processing.org/reference/fill_.html
void fill(uint8_t red, uint8_t green, uint8_t blue);
void fill(color c);
// http://processing.org/reference/noFill_.html
void noFill();
// http://processing.org/reference/stroke_.html
void stroke(uint8_t red, uint8_t green, uint8_t blue);
void stroke(color c);
// http://processing.org/reference/noStroke_.html
void noStroke();
void text(const char * text, int16_t x, int16_t y);
void text(int value, uint8_t posX, uint8_t posY);
void text(long value, uint8_t posX, uint8_t posY);
void text(char value, uint8_t posX, uint8_t posY);
void textWrap(const char * text, int16_t x, int16_t y);
void textSize(uint8_t size);
// similar to ellipse() in Processing, but with
// a single radius.
// http://processing.org/reference/ellipse_.html
void circle(int16_t x, int16_t y, int16_t r);
void point(int16_t x, int16_t y);
void line(int16_t x1, int16_t y1, int16_t x2, int16_t y2);
void quad(int16_t x1, int16_t y1, int16_t x2, int16_t y2, int16_t x3, int16_t y3, int16_t x4, int16_t y4);
void rect(int16_t x, int16_t y, int16_t width, int16_t height);
void rect(int16_t x, int16_t y, int16_t width, int16_t height, int16_t radius);
void triangle(int16_t x1, int16_t y1, int16_t x2, int16_t y2, int16_t x3, int16_t y3);
/* TODO
void rectMode(RectMode mode);
void pushStyle();
void popStyle();
*/
// PImage loadImage(const char * fileName) { return PImage::loadImage(fileName); }
// void image(PImage & img, uint16_t x, uint16_t y);
protected:
const int16_t
WIDTH, HEIGHT; // This is the 'raw' display w/h - never changes
int16_t
_width, _height, // Display w/h as modified by current rotation
cursor_x, cursor_y;
uint16_t
textcolor, textbgcolor;
uint8_t
textsize,
rotation;
boolean
wrap; // If set, 'wrap' text at right edge of display
/*
* Processing-style graphics state
*/
color strokeColor;
bool useStroke;
color fillColor;
bool useFill;
};
#endif // _ADAFRUIT_GFX_H

View File

@ -0,0 +1,192 @@
#include <avr/pgmspace.h>
#include <ArduinoRobot.h>
#include "VirtualKeyboard.h"
#include "RobotTextManager.h"
#include "scripts_Hello_User.h"
const int TextManager::lineHeight=10;
const int TextManager::charWidth=6;
void TextManager::setMargin(int margin_left,int margin_top){
this->margin_left=margin_left;
this->margin_top=margin_top;
}
int TextManager::getLin(int lineNum){
return lineNum*lineHeight+margin_top;
}
int TextManager::getCol(int colNum){
return colNum*charWidth+margin_left;
}
void TextManager::writeText(int lineNum, int colNum, char* txt, bool onOff){
if(!onOff)
Robot.setTextColor(WHITE);
Robot.setCursor(getCol(colNum),getLin(lineNum));
Robot.print(txt);
Robot.setTextColor(BLACK);
}
void TextManager::drawInput(bool onOff){
if(!onOff)
Robot.setTextColor(WHITE);
Robot.setCursor(getCol(inputCol),getLin(inputLin)+1);
Robot.print('_');
Robot.setTextColor(BLACK);
}
void TextManager::mvInput(int dire){
drawInput(0);
if(dire<0){
if(inputPos>0){
inputPos--;
inputCol--;
}
}else{
if(inputPos<16){
inputPos++;
inputCol++;
}
}
drawInput(1);
}
char TextManager::selectLetter(){
static int oldVal;
char val=map(Robot.knobRead(),0,1023,32,125);
if(val==oldVal){
return 0; //No changes
}else{
oldVal=val;
return val; //Current letter
}
}
void TextManager::refreshCurrentLetter(char letter){
if(letter){
writeText(inputLin,inputCol,inputPool+inputPos,false);//erase
inputPool[inputPos]=letter;
writeText(inputLin,inputCol,inputPool+inputPos,true);//write
}
}
void TextManager::getInput(int lin, int col){
writeText(lin,col,">"); //Input indicator
writeText(lin, col+1, inputPool);
inputLin=lin; //Ini input cursor
inputCol=col+1;
inputPos=0;
drawInput(true);
Vkey.display(100);//Vkey is a object of VirtualKeyboard class
while(true){
switch(Robot.keyboardRead()){
case BUTTON_LEFT:
//Robot.beep(BEEP_SIMPLE);
mvInput(-1);
break;
case BUTTON_RIGHT:
//Robot.beep(BEEP_SIMPLE);
mvInput(1);
break;
case BUTTON_MIDDLE:
//Robot.beep(BEEP_DOUBLE);
char selection=Vkey.getSelection();
if(selection!='\0'){
refreshCurrentLetter(selection);
mvInput(1);
}else{
drawInput(false);
return;
}
}
Vkey.run();
delay(10);
}
}
void TextManager::setInputPool(int code){
switch(code){
case USERNAME:
Robot.userNameRead(inputPool);
break;
case ROBOTNAME:
Robot.robotNameRead(inputPool);
break;
case CITYNAME:
Robot.cityNameRead(inputPool);
break;
case COUNTRYNAME:
Robot.countryNameRead(inputPool);
break;
}
for(int i=0;i<18;i++){
if(inputPool[i]=='\0'){
for(int j=i;j<18;j++){
inputPool[j]='\0';
}
break;
}
}
}
void TextManager::pushInput(int code){
switch(code){
case USERNAME:
Robot.userNameWrite(inputPool);
break;
case ROBOTNAME:
Robot.robotNameWrite(inputPool);
break;
case CITYNAME:
Robot.cityNameWrite(inputPool);
break;
case COUNTRYNAME:
Robot.countryNameWrite(inputPool);
break;
}
for(int i=0;i<18;i++){
inputPool[i]='\0';
}
}
void TextManager::input(int lin,int col, int code){
setInputPool(code);
getInput(lin,col);
pushInput(code);
}
void TextManager::showPicture(char * filename, int posX, int posY){
Robot.pause();
Robot._drawBMP(filename,posX,posY);
Robot.play();
}
void TextManager::getPGMtext(int seq){
//It takes a string from program space, and fill it
//in the buffer
//if(in hello user example){
if(true){
strcpy_P(PGMbuffer,(char*)pgm_read_word(&(::scripts_Hello_User[seq])));
}
}
void TextManager::writeScript(int seq, int line, int col){
//print a string from program space to a specific line,
//column on the LCD
//first fill the buffer with text from program space
getPGMtext(seq);
//then print it to the screen
textManager.writeText(line,col,PGMbuffer);
}
TextManager textManager=TextManager();

View File

@ -0,0 +1,77 @@
#ifndef ROBOTTEXTMANAGER_H
#define ROBOTTEXTMANAGER_H
#define USERNAME 0
#define ROBOTNAME 1
#define CITYNAME 2
#define COUNTRYNAME 3
#define EMPTY 4
class TextManager{
//The TextManager class is a collection of features specific for Hello
//User example.
//
//- It includes solution for setting text position based on
// line/column. The original Robot.text(), or the more low level
// print() function can only set text position on pixels from left,
// top.
//
//- The process of accepting input with the virtual keyboard, saving
// into or reading from EEPROM is delt with here.
//
//- A workflow for stop the music while displaying image. Trouble
// will happen otherwise.
public:
//add some margin to the text, left side only atm.
void setMargin(int margin_left,int margin_top);
//print text based on line, column.
void writeText(int lineNum, int colNum, char* txt, bool onOff=true);
//print a script from the scripts library
void writeScript(int seq, int line, int col);
//The whole process of getting input
void input(int lin,int col, int code);
//Print a cursor and virtual keyboard on screen, and save the user's input
void getInput(int lin, int col);
//Get user name, robot name, city name or country name from EEPROM
//and store in the input pool.
void setInputPool(int code);
//save user input to EEPROM
void pushInput(int code);
//Replaces Robot.drawPicture(), as this one solves collision between
//image and music
void showPicture(char * filename, int posX, int posY);
private:
int margin_left,margin_top;
int getLin(int lineNum); //Convert line to pixels from top
int getCol(int colNum); //Convert line to pixels from left
static const int lineHeight;//8+2=10
static const int charWidth;//5+1=6
int inputPos;
int inputLin;
int inputCol;
void drawInput(bool onOff);
void mvInput(int dire);
char selectLetter();
void refreshCurrentLetter(char letter);
void getPGMtext(int seq);
char PGMbuffer[85]; //the buffer for storing strings
char inputPool[18];
};
//a trick for removing the need of creating an object of TextManager.
//So you can call me.somefunction() directly in the sketch.
extern TextManager textManager;
#endif

View File

@ -0,0 +1,127 @@
#include "VirtualKeyboard.h"
int VirtualKeyboard::getColLin(int val){
uint8_t col,lin;
lin=val/10;
col=val%10; // saving 36 bytes :(
/*if(0<=val && 9>=val){
col=val;
lin=0;
}else if(10<=val && 19>=val){
col=val-10;
lin=1;
}else if(20<=val && 29>=val){
col=val-20;
lin=2;
}else if(30<=val && 39>=val){
col=val-30;
lin=3;
}*/
return (col<<8)+lin; //Put col and lin in one int
}
void VirtualKeyboard::run(){
/** visually select a letter on the keyboard
* The selection boarder is 1px higher than the character,
* 1px on the bottom, 2px to the left and 2px to the right.
*
*/
if(!onOff)return;
//Serial.println(onOff);
static int oldColLin=0;
uint8_t val=map(Robot.knobRead(),0,1023,0,38);
if(val==38)val=37; //The last value is jumpy when using batteries
int colLin=getColLin(val);
if(oldColLin!=colLin){
uint8_t x=(oldColLin>>8 & 0xFF)*11+10;//col*11+1+9
uint8_t y=(oldColLin & 0xFF)*11+1+top;//lin*11+1+top
uint8_t w=9;
if(oldColLin==1795) //last item "Enter", col=7 lin=3
w=33; //(5+1)*6-1+2+2 charWidth=5, charMargin=1, count("Enter")=6, lastItem_MarginRight=0, marginLeft==marginRight=2
Robot.drawRect(x,y,w,9,hideColor);
x=(colLin>>8 & 0xFF)*11+10;
y=(colLin & 0xFF)*11+1+top;
w=9;
if(colLin==1795) //last item "Enter", col=7 lin=3
w=33; //(5+1)*6-1+2+2 charWidth=5, charMargin=1, count("Enter")=6, lastItem_MarginRight=0, marginLeft==marginRight=2
Robot.drawRect(x,y,w,9,showColor);
oldColLin=colLin;
}
}
char VirtualKeyboard::getSelection(){
if(!onOff)return -1;
uint8_t val=map(Robot.knobRead(),0,1023,0,38);
if(0<=val && 9>=val)
val='0'+val;
else if(10<=val && 35>=val)
val='A'+val-10;
else if(val==36)
val=' ';
else if(val>=37)
val='\0';
return val;
}
void VirtualKeyboard::hide(){
onOff=false;
Robot.fillRect(0,top,128,44,hideColor);//11*4
}
void VirtualKeyboard::display(uint8_t top, uint16_t showColor, uint16_t hideColor){
/** Display the keyboard at y position of top
* formular:
* When text size is 1, one character is 5*7
* margin-left==margin-right==3,
* margin-top==margin-bottom==2,
* keyWidth=5+3+3==11,
* keyHeight=7+2+2==11,
* keyboard-margin-left=keyboard-margin-right==9
* so character-x=11*col+9+3=11*col+12
* character-y=11*lin+2+top
*
**/
this->top=top;
this->onOff=true;
this->showColor=showColor;
this->hideColor=hideColor;
for(uint8_t i=0;i<36;i++){
Robot.setCursor(i%10*11+12,2+top+i/10*11);
if(i<10)
Robot.print(char('0'+i));
else
Robot.print(char(55+i));//'A'-10=55
}//for saving 58 bytes :(
/*for(int i=0;i<10;i++){
Robot.setCursor(i*11+12,2+top);//11*0+2+top
Robot.print(char('0'+i));//line_1: 0-9
}
for(int i=0;i<10;i++){
Robot.setCursor(i*11+12,13+top);//11*1+2+top
Robot.print(char('A'+i));//line_2: A-J
}
for(int i=0;i<10;i++){
Robot.setCursor(i*11+12,24+top);//11*2+2+top
Robot.print(char('K'+i));//line_3: K-T
}
for(int i=0;i<6;i++){
Robot.setCursor(i*11+12,35+top);//11*3+2+top
Robot.print(char('U'+i));//line_4: U-Z
}*/
//space and enter at the end of the last line.
Robot.setCursor(78,35+top);//6*11+12=78
Robot.print('_');//_
Robot.setCursor(89,35+top);//7*11+12=89
Robot.print("Enter");//enter
}
VirtualKeyboard Vkey=VirtualKeyboard();

View File

@ -0,0 +1,28 @@
#ifndef VIRTUAL_KEYBOARD_H
#define VIRTUAL_KEYBOARD_H
#include <Arduino.h>
#include <ArduinoRobot.h>
class VirtualKeyboard{
public:
//void begin();
void display(uint8_t top, uint16_t showColor=BLACK, uint16_t hideColor=WHITE);
void hide();
char getSelection();
void run();
private:
uint8_t top;
bool onOff;
uint16_t showColor;
uint16_t hideColor;
int getColLin(int val);
};
extern VirtualKeyboard Vkey;
#endif

View File

@ -0,0 +1,51 @@
#include <avr/pgmspace.h>
//an advanced trick for storing strings inside the program space
//as the ram of Arduino is very tiny, keeping too many string in it
//can kill the program
prog_char hello_user_script1[] PROGMEM="What's your name?";
prog_char hello_user_script2[] PROGMEM="Give me a name!";
prog_char hello_user_script3[] PROGMEM="And the country?";
prog_char hello_user_script4[] PROGMEM="The city you're in?";
prog_char hello_user_script5[] PROGMEM=" Plug me to\n\n your computer\n\n and start coding!";
prog_char hello_user_script6[] PROGMEM=" Hello User!\n\n It's me, your robot\n\n I'm alive! <3";
prog_char hello_user_script7[] PROGMEM=" First I need some\n\n input from you!";
prog_char hello_user_script8[] PROGMEM=" Use the knob\n\n to select letters";
prog_char hello_user_script9[] PROGMEM=" Use L/R button\n\n to move the cursor,\n\n middle to confirm";
prog_char hello_user_script10[] PROGMEM=" Press middle key\n to continue...";
prog_char hello_user_script11[] PROGMEM=" Choose \"enter\" to\n\n finish the input";
PROGMEM const char *scripts_Hello_User[]={
hello_user_script1,
hello_user_script2,
hello_user_script3,
hello_user_script4,
hello_user_script5,
hello_user_script6,
hello_user_script7,
hello_user_script8,
hello_user_script9,
hello_user_script10,
hello_user_script11,
};
/*
void getPGMtext(int seq){
//It takes a string from program space, and fill it
//in the buffer
strcpy_P(buffer,(char*)pgm_read_word(&(scripts[seq])));
}
void writeScript(int seq, int line, int col){
//print a string from program space to a specific line,
//column on the LCD
//first fill the buffer with text from program space
getPGMtext(seq);
//then print it to the screen
textManager.writeText(line,col,buffer);
}
*/

View File

@ -0,0 +1,527 @@
/*
twi.c - TWI/I2C library for Wiring & Arduino
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts
*/
#include <math.h>
#include <stdlib.h>
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <compat/twi.h>
#include "Arduino.h" // for digitalWrite
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
#include "pins_arduino.h"
#include "twi.h"
static volatile uint8_t twi_state;
static volatile uint8_t twi_slarw;
static volatile uint8_t twi_sendStop; // should the transaction end with a stop
static volatile uint8_t twi_inRepStart; // in the middle of a repeated start
static void (*twi_onSlaveTransmit)(void);
static void (*twi_onSlaveReceive)(uint8_t*, int);
static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH];
static volatile uint8_t twi_masterBufferIndex;
static volatile uint8_t twi_masterBufferLength;
static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH];
static volatile uint8_t twi_txBufferIndex;
static volatile uint8_t twi_txBufferLength;
static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH];
static volatile uint8_t twi_rxBufferIndex;
static volatile uint8_t twi_error;
/*
* Function twi_init
* Desc readys twi pins and sets twi bitrate
* Input none
* Output none
*/
void twi_init(void)
{
// initialize state
twi_state = TWI_READY;
twi_sendStop = true; // default value
twi_inRepStart = false;
// activate internal pullups for twi.
digitalWrite(SDA, 1);
digitalWrite(SCL, 1);
// initialize twi prescaler and bit rate
cbi(TWSR, TWPS0);
cbi(TWSR, TWPS1);
TWBR = ((F_CPU / TWI_FREQ) - 16) / 2;
/* twi bit rate formula from atmega128 manual pg 204
SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR))
note: TWBR should be 10 or higher for master mode
It is 72 for a 16mhz Wiring board with 100kHz TWI */
// enable twi module, acks, and twi interrupt
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
}
/*
* Function twi_slaveInit
* Desc sets slave address and enables interrupt
* Input none
* Output none
*/
void twi_setAddress(uint8_t address)
{
// set twi slave address (skip over TWGCE bit)
TWAR = address << 1;
}
/*
* Function twi_readFrom
* Desc attempts to become twi bus master and read a
* series of bytes from a device on the bus
* Input address: 7bit i2c device address
* data: pointer to byte array
* length: number of bytes to read into array
* sendStop: Boolean indicating whether to send a stop at the end
* Output number of bytes read
*/
uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop)
{
uint8_t i;
// ensure data will fit into buffer
if(TWI_BUFFER_LENGTH < length){
return 0;
}
// wait until twi is ready, become master receiver
while(TWI_READY != twi_state){
continue;
}
twi_state = TWI_MRX;
twi_sendStop = sendStop;
// reset error state (0xFF.. no error occured)
twi_error = 0xFF;
// initialize buffer iteration vars
twi_masterBufferIndex = 0;
twi_masterBufferLength = length-1; // This is not intuitive, read on...
// On receive, the previously configured ACK/NACK setting is transmitted in
// response to the received byte before the interrupt is signalled.
// Therefor we must actually set NACK when the _next_ to last byte is
// received, causing that NACK to be sent in response to receiving the last
// expected byte of data.
// build sla+w, slave device address + w bit
twi_slarw = TW_READ;
twi_slarw |= address << 1;
if (true == twi_inRepStart) {
// if we're in the repeated start state, then we've already sent the start,
// (@@@ we hope), and the TWI statemachine is just waiting for the address byte.
// We need to remove ourselves from the repeated start state before we enable interrupts,
// since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning
// up. Also, don't enable the START interrupt. There may be one pending from the
// repeated start that we sent outselves, and that would really confuse things.
twi_inRepStart = false; // remember, we're dealing with an ASYNC ISR
TWDR = twi_slarw;
TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE); // enable INTs, but not START
}
else
// send start condition
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
// wait for read operation to complete
while(TWI_MRX == twi_state){
continue;
}
if (twi_masterBufferIndex < length)
length = twi_masterBufferIndex;
// copy twi buffer to data
for(i = 0; i < length; ++i){
data[i] = twi_masterBuffer[i];
}
return length;
}
/*
* Function twi_writeTo
* Desc attempts to become twi bus master and write a
* series of bytes to a device on the bus
* Input address: 7bit i2c device address
* data: pointer to byte array
* length: number of bytes in array
* wait: boolean indicating to wait for write or not
* sendStop: boolean indicating whether or not to send a stop at the end
* Output 0 .. success
* 1 .. length to long for buffer
* 2 .. address send, NACK received
* 3 .. data send, NACK received
* 4 .. other twi error (lost bus arbitration, bus error, ..)
*/
uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait, uint8_t sendStop)
{
uint8_t i;
// ensure data will fit into buffer
if(TWI_BUFFER_LENGTH < length){
return 1;
}
// wait until twi is ready, become master transmitter
while(TWI_READY != twi_state){
continue;
}
twi_state = TWI_MTX;
twi_sendStop = sendStop;
// reset error state (0xFF.. no error occured)
twi_error = 0xFF;
// initialize buffer iteration vars
twi_masterBufferIndex = 0;
twi_masterBufferLength = length;
// copy data to twi buffer
for(i = 0; i < length; ++i){
twi_masterBuffer[i] = data[i];
}
// build sla+w, slave device address + w bit
twi_slarw = TW_WRITE;
twi_slarw |= address << 1;
// if we're in a repeated start, then we've already sent the START
// in the ISR. Don't do it again.
//
if (true == twi_inRepStart) {
// if we're in the repeated start state, then we've already sent the start,
// (@@@ we hope), and the TWI statemachine is just waiting for the address byte.
// We need to remove ourselves from the repeated start state before we enable interrupts,
// since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning
// up. Also, don't enable the START interrupt. There may be one pending from the
// repeated start that we sent outselves, and that would really confuse things.
twi_inRepStart = false; // remember, we're dealing with an ASYNC ISR
TWDR = twi_slarw;
TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE); // enable INTs, but not START
}
else
// send start condition
TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTA); // enable INTs
// wait for write operation to complete
while(wait && (TWI_MTX == twi_state)){
continue;
}
if (twi_error == 0xFF)
return 0; // success
else if (twi_error == TW_MT_SLA_NACK)
return 2; // error: address send, nack received
else if (twi_error == TW_MT_DATA_NACK)
return 3; // error: data send, nack received
else
return 4; // other twi error
}
/*
* Function twi_transmit
* Desc fills slave tx buffer with data
* must be called in slave tx event callback
* Input data: pointer to byte array
* length: number of bytes in array
* Output 1 length too long for buffer
* 2 not slave transmitter
* 0 ok
*/
uint8_t twi_transmit(const uint8_t* data, uint8_t length)
{
uint8_t i;
// ensure data will fit into buffer
if(TWI_BUFFER_LENGTH < length){
return 1;
}
// ensure we are currently a slave transmitter
if(TWI_STX != twi_state){
return 2;
}
// set length and copy data into tx buffer
twi_txBufferLength = length;
for(i = 0; i < length; ++i){
twi_txBuffer[i] = data[i];
}
return 0;
}
/*
* Function twi_attachSlaveRxEvent
* Desc sets function called before a slave read operation
* Input function: callback function to use
* Output none
*/
void twi_attachSlaveRxEvent( void (*function)(uint8_t*, int) )
{
twi_onSlaveReceive = function;
}
/*
* Function twi_attachSlaveTxEvent
* Desc sets function called before a slave write operation
* Input function: callback function to use
* Output none
*/
void twi_attachSlaveTxEvent( void (*function)(void) )
{
twi_onSlaveTransmit = function;
}
/*
* Function twi_reply
* Desc sends byte or readys receive line
* Input ack: byte indicating to ack or to nack
* Output none
*/
void twi_reply(uint8_t ack)
{
// transmit master read ready signal, with or without ack
if(ack){
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);
}else{
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);
}
}
/*
* Function twi_stop
* Desc relinquishes bus master status
* Input none
* Output none
*/
void twi_stop(void)
{
// send stop condition
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO);
// wait for stop condition to be exectued on bus
// TWINT is not set after a stop condition!
while(TWCR & _BV(TWSTO)){
continue;
}
// update twi state
twi_state = TWI_READY;
}
/*
* Function twi_releaseBus
* Desc releases bus control
* Input none
* Output none
*/
void twi_releaseBus(void)
{
// release bus
TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT);
// update twi state
twi_state = TWI_READY;
}
SIGNAL(TWI_vect)
{
switch(TW_STATUS){
// All Master
case TW_START: // sent start condition
case TW_REP_START: // sent repeated start condition
// copy device address and r/w bit to output register and ack
TWDR = twi_slarw;
twi_reply(1);
break;
// Master Transmitter
case TW_MT_SLA_ACK: // slave receiver acked address
case TW_MT_DATA_ACK: // slave receiver acked data
// if there is data to send, send it, otherwise stop
if(twi_masterBufferIndex < twi_masterBufferLength){
// copy data to output register and ack
TWDR = twi_masterBuffer[twi_masterBufferIndex++];
twi_reply(1);
}else{
if (twi_sendStop)
twi_stop();
else {
twi_inRepStart = true; // we're gonna send the START
// don't enable the interrupt. We'll generate the start, but we
// avoid handling the interrupt until we're in the next transaction,
// at the point where we would normally issue the start.
TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ;
twi_state = TWI_READY;
}
}
break;
case TW_MT_SLA_NACK: // address sent, nack received
twi_error = TW_MT_SLA_NACK;
twi_stop();
break;
case TW_MT_DATA_NACK: // data sent, nack received
twi_error = TW_MT_DATA_NACK;
twi_stop();
break;
case TW_MT_ARB_LOST: // lost bus arbitration
twi_error = TW_MT_ARB_LOST;
twi_releaseBus();
break;
// Master Receiver
case TW_MR_DATA_ACK: // data received, ack sent
// put byte into buffer
twi_masterBuffer[twi_masterBufferIndex++] = TWDR;
case TW_MR_SLA_ACK: // address sent, ack received
// ack if more bytes are expected, otherwise nack
if(twi_masterBufferIndex < twi_masterBufferLength){
twi_reply(1);
}else{
twi_reply(0);
}
break;
case TW_MR_DATA_NACK: // data received, nack sent
// put final byte into buffer
twi_masterBuffer[twi_masterBufferIndex++] = TWDR;
if (twi_sendStop)
twi_stop();
else {
twi_inRepStart = true; // we're gonna send the START
// don't enable the interrupt. We'll generate the start, but we
// avoid handling the interrupt until we're in the next transaction,
// at the point where we would normally issue the start.
TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ;
twi_state = TWI_READY;
}
break;
case TW_MR_SLA_NACK: // address sent, nack received
twi_stop();
break;
// TW_MR_ARB_LOST handled by TW_MT_ARB_LOST case
// Slave Receiver
case TW_SR_SLA_ACK: // addressed, returned ack
case TW_SR_GCALL_ACK: // addressed generally, returned ack
case TW_SR_ARB_LOST_SLA_ACK: // lost arbitration, returned ack
case TW_SR_ARB_LOST_GCALL_ACK: // lost arbitration, returned ack
// enter slave receiver mode
twi_state = TWI_SRX;
// indicate that rx buffer can be overwritten and ack
twi_rxBufferIndex = 0;
twi_reply(1);
break;
case TW_SR_DATA_ACK: // data received, returned ack
case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack
// if there is still room in the rx buffer
if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){
// put byte in buffer and ack
twi_rxBuffer[twi_rxBufferIndex++] = TWDR;
twi_reply(1);
}else{
// otherwise nack
twi_reply(0);
}
break;
case TW_SR_STOP: // stop or repeated start condition received
// put a null char after data if there's room
if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){
twi_rxBuffer[twi_rxBufferIndex] = '\0';
}
// sends ack and stops interface for clock stretching
twi_stop();
// callback to user defined callback
twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex);
// since we submit rx buffer to "wire" library, we can reset it
twi_rxBufferIndex = 0;
// ack future responses and leave slave receiver state
twi_releaseBus();
break;
case TW_SR_DATA_NACK: // data received, returned nack
case TW_SR_GCALL_DATA_NACK: // data received generally, returned nack
// nack back at master
twi_reply(0);
break;
// Slave Transmitter
case TW_ST_SLA_ACK: // addressed, returned ack
case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack
// enter slave transmitter mode
twi_state = TWI_STX;
// ready the tx buffer index for iteration
twi_txBufferIndex = 0;
// set tx buffer length to be zero, to verify if user changes it
twi_txBufferLength = 0;
// request for txBuffer to be filled and length to be set
// note: user must call twi_transmit(bytes, length) to do this
twi_onSlaveTransmit();
// if they didn't change buffer & length, initialize it
if(0 == twi_txBufferLength){
twi_txBufferLength = 1;
twi_txBuffer[0] = 0x00;
}
// transmit first byte from buffer, fall
case TW_ST_DATA_ACK: // byte sent, ack returned
// copy data to output register
TWDR = twi_txBuffer[twi_txBufferIndex++];
// if there is more to send, ack, otherwise nack
if(twi_txBufferIndex < twi_txBufferLength){
twi_reply(1);
}else{
twi_reply(0);
}
break;
case TW_ST_DATA_NACK: // received nack, we are done
case TW_ST_LAST_DATA: // received ack, but we are done already!
// ack future responses
twi_reply(1);
// leave slave receiver state
twi_state = TWI_READY;
break;
// All
case TW_NO_INFO: // no state information
break;
case TW_BUS_ERROR: // bus error, illegal stop/start
twi_error = TW_BUS_ERROR;
twi_stop();
break;
}
}

View File

@ -0,0 +1,53 @@
/*
twi.h - TWI/I2C library for Wiring & Arduino
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef twi_h
#define twi_h
#include <inttypes.h>
//#define ATMEGA8
#ifndef TWI_FREQ
#define TWI_FREQ 100000L
#endif
#ifndef TWI_BUFFER_LENGTH
#define TWI_BUFFER_LENGTH 32
#endif
#define TWI_READY 0
#define TWI_MRX 1
#define TWI_MTX 2
#define TWI_SRX 3
#define TWI_STX 4
void twi_init(void);
void twi_setAddress(uint8_t);
uint8_t twi_readFrom(uint8_t, uint8_t*, uint8_t, uint8_t);
uint8_t twi_writeTo(uint8_t, uint8_t*, uint8_t, uint8_t, uint8_t);
uint8_t twi_transmit(const uint8_t*, uint8_t);
void twi_attachSlaveRxEvent( void (*)(uint8_t*, int) );
void twi_attachSlaveTxEvent( void (*)(void) );
void twi_reply(uint8_t);
void twi_stop(void);
void twi_releaseBus(void);
#endif