- Added minimal arduino files needed to compile - Build script will locate avr-gcc tools - Z offset fix for MINImaster
parent
ae6a79b0c9
commit
1932de77b4
@ -0,0 +1,266 @@
|
||||
/*
|
||||
Print.cpp - Base class that provides print() and println()
|
||||
Copyright (c) 2008 David A. Mellis. 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 23 November 2006 by David A. Mellis
|
||||
Modified 03 August 2015 by Chuck Todd
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "Arduino.h"
|
||||
|
||||
#include "Print.h"
|
||||
|
||||
// Public Methods //////////////////////////////////////////////////////////////
|
||||
|
||||
/* default implementation: may be overridden */
|
||||
size_t Print::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
size_t n = 0;
|
||||
while (size--) {
|
||||
if (write(*buffer++)) n++;
|
||||
else break;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::print(const __FlashStringHelper *ifsh)
|
||||
{
|
||||
PGM_P p = reinterpret_cast<PGM_P>(ifsh);
|
||||
size_t n = 0;
|
||||
while (1) {
|
||||
unsigned char c = pgm_read_byte(p++);
|
||||
if (c == 0) break;
|
||||
if (write(c)) n++;
|
||||
else break;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::print(const String &s)
|
||||
{
|
||||
return write(s.c_str(), s.length());
|
||||
}
|
||||
|
||||
size_t Print::print(const char str[])
|
||||
{
|
||||
return write(str);
|
||||
}
|
||||
|
||||
size_t Print::print(char c)
|
||||
{
|
||||
return write(c);
|
||||
}
|
||||
|
||||
size_t Print::print(unsigned char b, int base)
|
||||
{
|
||||
return print((unsigned long) b, base);
|
||||
}
|
||||
|
||||
size_t Print::print(int n, int base)
|
||||
{
|
||||
return print((long) n, base);
|
||||
}
|
||||
|
||||
size_t Print::print(unsigned int n, int base)
|
||||
{
|
||||
return print((unsigned long) n, base);
|
||||
}
|
||||
|
||||
size_t Print::print(long n, int base)
|
||||
{
|
||||
if (base == 0) {
|
||||
return write(n);
|
||||
} else if (base == 10) {
|
||||
if (n < 0) {
|
||||
int t = print('-');
|
||||
n = -n;
|
||||
return printNumber(n, 10) + t;
|
||||
}
|
||||
return printNumber(n, 10);
|
||||
} else {
|
||||
return printNumber(n, base);
|
||||
}
|
||||
}
|
||||
|
||||
size_t Print::print(unsigned long n, int base)
|
||||
{
|
||||
if (base == 0) return write(n);
|
||||
else return printNumber(n, base);
|
||||
}
|
||||
|
||||
size_t Print::print(double n, int digits)
|
||||
{
|
||||
return printFloat(n, digits);
|
||||
}
|
||||
|
||||
size_t Print::println(const __FlashStringHelper *ifsh)
|
||||
{
|
||||
size_t n = print(ifsh);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::print(const Printable& x)
|
||||
{
|
||||
return x.printTo(*this);
|
||||
}
|
||||
|
||||
size_t Print::println(void)
|
||||
{
|
||||
return write("\r\n");
|
||||
}
|
||||
|
||||
size_t Print::println(const String &s)
|
||||
{
|
||||
size_t n = print(s);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(const char c[])
|
||||
{
|
||||
size_t n = print(c);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(char c)
|
||||
{
|
||||
size_t n = print(c);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(unsigned char b, int base)
|
||||
{
|
||||
size_t n = print(b, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(int num, int base)
|
||||
{
|
||||
size_t n = print(num, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(unsigned int num, int base)
|
||||
{
|
||||
size_t n = print(num, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(long num, int base)
|
||||
{
|
||||
size_t n = print(num, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(unsigned long num, int base)
|
||||
{
|
||||
size_t n = print(num, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(double num, int digits)
|
||||
{
|
||||
size_t n = print(num, digits);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(const Printable& x)
|
||||
{
|
||||
size_t n = print(x);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
// Private Methods /////////////////////////////////////////////////////////////
|
||||
|
||||
size_t Print::printNumber(unsigned long n, uint8_t base)
|
||||
{
|
||||
char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
|
||||
char *str = &buf[sizeof(buf) - 1];
|
||||
|
||||
*str = '\0';
|
||||
|
||||
// prevent crash if called with base == 1
|
||||
if (base < 2) base = 10;
|
||||
|
||||
do {
|
||||
char c = n % base;
|
||||
n /= base;
|
||||
|
||||
*--str = c < 10 ? c + '0' : c + 'A' - 10;
|
||||
} while(n);
|
||||
|
||||
return write(str);
|
||||
}
|
||||
|
||||
size_t Print::printFloat(double number, uint8_t digits)
|
||||
{
|
||||
size_t n = 0;
|
||||
|
||||
if (isnan(number)) return print("nan");
|
||||
if (isinf(number)) return print("inf");
|
||||
if (number > 4294967040.0) return print ("ovf"); // constant determined empirically
|
||||
if (number <-4294967040.0) return print ("ovf"); // constant determined empirically
|
||||
|
||||
// Handle negative numbers
|
||||
if (number < 0.0)
|
||||
{
|
||||
n += print('-');
|
||||
number = -number;
|
||||
}
|
||||
|
||||
// Round correctly so that print(1.999, 2) prints as "2.00"
|
||||
double rounding = 0.5;
|
||||
for (uint8_t i=0; i<digits; ++i)
|
||||
rounding /= 10.0;
|
||||
|
||||
number += rounding;
|
||||
|
||||
// Extract the integer part of the number and print it
|
||||
unsigned long int_part = (unsigned long)number;
|
||||
double remainder = number - (double)int_part;
|
||||
n += print(int_part);
|
||||
|
||||
// Print the decimal point, but only if there are digits beyond
|
||||
if (digits > 0) {
|
||||
n += print('.');
|
||||
}
|
||||
|
||||
// Extract digits from the remainder one at a time
|
||||
while (digits-- > 0)
|
||||
{
|
||||
remainder *= 10.0;
|
||||
unsigned int toPrint = (unsigned int)(remainder);
|
||||
n += print(toPrint);
|
||||
remainder -= toPrint;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
@ -0,0 +1,619 @@
|
||||
/* Tone.cpp
|
||||
|
||||
A Tone Generator Library
|
||||
|
||||
Written by Brett Hagman
|
||||
|
||||
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
|
||||
|
||||
Version Modified By Date Comments
|
||||
------- ----------- -------- --------
|
||||
0001 B Hagman 09/08/02 Initial coding
|
||||
0002 B Hagman 09/08/18 Multiple pins
|
||||
0003 B Hagman 09/08/18 Moved initialization from constructor to begin()
|
||||
0004 B Hagman 09/09/26 Fixed problems with ATmega8
|
||||
0005 B Hagman 09/11/23 Scanned prescalars for best fit on 8 bit timers
|
||||
09/11/25 Changed pin toggle method to XOR
|
||||
09/11/25 Fixed timer0 from being excluded
|
||||
0006 D Mellis 09/12/29 Replaced objects with functions
|
||||
0007 M Sproul 10/08/29 Changed #ifdefs from cpu to register
|
||||
0008 S Kanemoto 12/06/22 Fixed for Leonardo by @maris_HY
|
||||
0009 J Reucker 15/04/10 Issue #292 Fixed problems with ATmega8 (thanks to Pete62)
|
||||
0010 jipp 15/04/13 added additional define check #2923
|
||||
*************************************************/
|
||||
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include "Arduino.h"
|
||||
#include "pins_arduino.h"
|
||||
|
||||
#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega128__)
|
||||
#define TCCR2A TCCR2
|
||||
#define TCCR2B TCCR2
|
||||
#define COM2A1 COM21
|
||||
#define COM2A0 COM20
|
||||
#define OCR2A OCR2
|
||||
#define TIMSK2 TIMSK
|
||||
#define OCIE2A OCIE2
|
||||
#define TIMER2_COMPA_vect TIMER2_COMP_vect
|
||||
#define TIMSK1 TIMSK
|
||||
#endif
|
||||
|
||||
// timerx_toggle_count:
|
||||
// > 0 - duration specified
|
||||
// = 0 - stopped
|
||||
// < 0 - infinitely (until stop() method called, or new play() called)
|
||||
|
||||
#if !defined(__AVR_ATmega8__)
|
||||
volatile long timer0_toggle_count;
|
||||
volatile uint8_t *timer0_pin_port;
|
||||
volatile uint8_t timer0_pin_mask;
|
||||
#endif
|
||||
|
||||
volatile long timer1_toggle_count;
|
||||
volatile uint8_t *timer1_pin_port;
|
||||
volatile uint8_t timer1_pin_mask;
|
||||
volatile long timer2_toggle_count;
|
||||
volatile uint8_t *timer2_pin_port;
|
||||
volatile uint8_t timer2_pin_mask;
|
||||
|
||||
#if defined(TIMSK3)
|
||||
volatile long timer3_toggle_count;
|
||||
volatile uint8_t *timer3_pin_port;
|
||||
volatile uint8_t timer3_pin_mask;
|
||||
#endif
|
||||
|
||||
#if defined(TIMSK4)
|
||||
volatile long timer4_toggle_count;
|
||||
volatile uint8_t *timer4_pin_port;
|
||||
volatile uint8_t timer4_pin_mask;
|
||||
#endif
|
||||
|
||||
#if defined(TIMSK5)
|
||||
volatile long timer5_toggle_count;
|
||||
volatile uint8_t *timer5_pin_port;
|
||||
volatile uint8_t timer5_pin_mask;
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
|
||||
#define AVAILABLE_TONE_PINS 1
|
||||
#define USE_TIMER2
|
||||
|
||||
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 3, 4, 5, 1, 0 */ };
|
||||
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255, 255, 255, 255 */ };
|
||||
|
||||
#elif defined(__AVR_ATmega8__)
|
||||
|
||||
#define AVAILABLE_TONE_PINS 1
|
||||
#define USE_TIMER2
|
||||
|
||||
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1 */ };
|
||||
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255 */ };
|
||||
|
||||
#elif defined(__AVR_ATmega32U4__)
|
||||
|
||||
#define AVAILABLE_TONE_PINS 1
|
||||
#define USE_TIMER3
|
||||
|
||||
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 3 /*, 1 */ };
|
||||
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255 */ };
|
||||
|
||||
#else
|
||||
|
||||
#define AVAILABLE_TONE_PINS 1
|
||||
#define USE_TIMER2
|
||||
|
||||
// Leave timer 0 to last.
|
||||
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1, 0 */ };
|
||||
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255 */ };
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
static int8_t toneBegin(uint8_t _pin)
|
||||
{
|
||||
int8_t _timer = -1;
|
||||
|
||||
// if we're already using the pin, the timer should be configured.
|
||||
for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
|
||||
if (tone_pins[i] == _pin) {
|
||||
return pgm_read_byte(tone_pin_to_timer_PGM + i);
|
||||
}
|
||||
}
|
||||
|
||||
// search for an unused timer.
|
||||
for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
|
||||
if (tone_pins[i] == 255) {
|
||||
tone_pins[i] = _pin;
|
||||
_timer = pgm_read_byte(tone_pin_to_timer_PGM + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_timer != -1)
|
||||
{
|
||||
// Set timer specific stuff
|
||||
// All timers in CTC mode
|
||||
// 8 bit timers will require changing prescalar values,
|
||||
// whereas 16 bit timers are set to either ck/1 or ck/64 prescalar
|
||||
switch (_timer)
|
||||
{
|
||||
#if defined(TCCR0A) && defined(TCCR0B) && defined(WGM01)
|
||||
case 0:
|
||||
// 8 bit timer
|
||||
TCCR0A = 0;
|
||||
TCCR0B = 0;
|
||||
bitWrite(TCCR0A, WGM01, 1);
|
||||
bitWrite(TCCR0B, CS00, 1);
|
||||
timer0_pin_port = portOutputRegister(digitalPinToPort(_pin));
|
||||
timer0_pin_mask = digitalPinToBitMask(_pin);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR1A) && defined(TCCR1B) && defined(WGM12)
|
||||
case 1:
|
||||
// 16 bit timer
|
||||
TCCR1A = 0;
|
||||
TCCR1B = 0;
|
||||
bitWrite(TCCR1B, WGM12, 1);
|
||||
bitWrite(TCCR1B, CS10, 1);
|
||||
timer1_pin_port = portOutputRegister(digitalPinToPort(_pin));
|
||||
timer1_pin_mask = digitalPinToBitMask(_pin);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR2A) && defined(TCCR2B)
|
||||
case 2:
|
||||
// 8 bit timer
|
||||
TCCR2A = 0;
|
||||
TCCR2B = 0;
|
||||
bitWrite(TCCR2A, WGM21, 1);
|
||||
bitWrite(TCCR2B, CS20, 1);
|
||||
timer2_pin_port = portOutputRegister(digitalPinToPort(_pin));
|
||||
timer2_pin_mask = digitalPinToBitMask(_pin);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR3A) && defined(TCCR3B) && defined(TIMSK3)
|
||||
case 3:
|
||||
// 16 bit timer
|
||||
TCCR3A = 0;
|
||||
TCCR3B = 0;
|
||||
bitWrite(TCCR3B, WGM32, 1);
|
||||
bitWrite(TCCR3B, CS30, 1);
|
||||
timer3_pin_port = portOutputRegister(digitalPinToPort(_pin));
|
||||
timer3_pin_mask = digitalPinToBitMask(_pin);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR4A) && defined(TCCR4B) && defined(TIMSK4)
|
||||
case 4:
|
||||
// 16 bit timer
|
||||
TCCR4A = 0;
|
||||
TCCR4B = 0;
|
||||
#if defined(WGM42)
|
||||
bitWrite(TCCR4B, WGM42, 1);
|
||||
#elif defined(CS43)
|
||||
// TODO this may not be correct
|
||||
// atmega32u4
|
||||
bitWrite(TCCR4B, CS43, 1);
|
||||
#endif
|
||||
bitWrite(TCCR4B, CS40, 1);
|
||||
timer4_pin_port = portOutputRegister(digitalPinToPort(_pin));
|
||||
timer4_pin_mask = digitalPinToBitMask(_pin);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR5A) && defined(TCCR5B) && defined(TIMSK5)
|
||||
case 5:
|
||||
// 16 bit timer
|
||||
TCCR5A = 0;
|
||||
TCCR5B = 0;
|
||||
bitWrite(TCCR5B, WGM52, 1);
|
||||
bitWrite(TCCR5B, CS50, 1);
|
||||
timer5_pin_port = portOutputRegister(digitalPinToPort(_pin));
|
||||
timer5_pin_mask = digitalPinToBitMask(_pin);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return _timer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// frequency (in hertz) and duration (in milliseconds).
|
||||
|
||||
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration)
|
||||
{
|
||||
uint8_t prescalarbits = 0b001;
|
||||
long toggle_count = 0;
|
||||
uint32_t ocr = 0;
|
||||
int8_t _timer;
|
||||
|
||||
_timer = toneBegin(_pin);
|
||||
|
||||
if (_timer >= 0)
|
||||
{
|
||||
// Set the pinMode as OUTPUT
|
||||
pinMode(_pin, OUTPUT);
|
||||
|
||||
// if we are using an 8 bit timer, scan through prescalars to find the best fit
|
||||
if (_timer == 0 || _timer == 2)
|
||||
{
|
||||
ocr = F_CPU / frequency / 2 - 1;
|
||||
prescalarbits = 0b001; // ck/1: same for both timers
|
||||
if (ocr > 255)
|
||||
{
|
||||
ocr = F_CPU / frequency / 2 / 8 - 1;
|
||||
prescalarbits = 0b010; // ck/8: same for both timers
|
||||
|
||||
if (_timer == 2 && ocr > 255)
|
||||
{
|
||||
ocr = F_CPU / frequency / 2 / 32 - 1;
|
||||
prescalarbits = 0b011;
|
||||
}
|
||||
|
||||
if (ocr > 255)
|
||||
{
|
||||
ocr = F_CPU / frequency / 2 / 64 - 1;
|
||||
prescalarbits = _timer == 0 ? 0b011 : 0b100;
|
||||
|
||||
if (_timer == 2 && ocr > 255)
|
||||
{
|
||||
ocr = F_CPU / frequency / 2 / 128 - 1;
|
||||
prescalarbits = 0b101;
|
||||
}
|
||||
|
||||
if (ocr > 255)
|
||||
{
|
||||
ocr = F_CPU / frequency / 2 / 256 - 1;
|
||||
prescalarbits = _timer == 0 ? 0b100 : 0b110;
|
||||
if (ocr > 255)
|
||||
{
|
||||
// can't do any better than /1024
|
||||
ocr = F_CPU / frequency / 2 / 1024 - 1;
|
||||
prescalarbits = _timer == 0 ? 0b101 : 0b111;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(TCCR0B)
|
||||
if (_timer == 0)
|
||||
{
|
||||
TCCR0B = (TCCR0B & 0b11111000) | prescalarbits;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#if defined(TCCR2B)
|
||||
{
|
||||
TCCR2B = (TCCR2B & 0b11111000) | prescalarbits;
|
||||
}
|
||||
#else
|
||||
{
|
||||
// dummy place holder to make the above ifdefs work
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// two choices for the 16 bit timers: ck/1 or ck/64
|
||||
ocr = F_CPU / frequency / 2 - 1;
|
||||
|
||||
prescalarbits = 0b001;
|
||||
if (ocr > 0xffff)
|
||||
{
|
||||
ocr = F_CPU / frequency / 2 / 64 - 1;
|
||||
prescalarbits = 0b011;
|
||||
}
|
||||
|
||||
if (_timer == 1)
|
||||
{
|
||||
#if defined(TCCR1B)
|
||||
TCCR1B = (TCCR1B & 0b11111000) | prescalarbits;
|
||||
#endif
|
||||
}
|
||||
#if defined(TCCR3B)
|
||||
else if (_timer == 3)
|
||||
TCCR3B = (TCCR3B & 0b11111000) | prescalarbits;
|
||||
#endif
|
||||
#if defined(TCCR4B)
|
||||
else if (_timer == 4)
|
||||
TCCR4B = (TCCR4B & 0b11111000) | prescalarbits;
|
||||
#endif
|
||||
#if defined(TCCR5B)
|
||||
else if (_timer == 5)
|
||||
TCCR5B = (TCCR5B & 0b11111000) | prescalarbits;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Calculate the toggle count
|
||||
if (duration > 0)
|
||||
{
|
||||
toggle_count = 2 * frequency * duration / 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
toggle_count = -1;
|
||||
}
|
||||
|
||||
// Set the OCR for the given timer,
|
||||
// set the toggle count,
|
||||
// then turn on the interrupts
|
||||
switch (_timer)
|
||||
{
|
||||
|
||||
#if defined(OCR0A) && defined(TIMSK0) && defined(OCIE0A)
|
||||
case 0:
|
||||
OCR0A = ocr;
|
||||
timer0_toggle_count = toggle_count;
|
||||
bitWrite(TIMSK0, OCIE0A, 1);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 1:
|
||||
#if defined(OCR1A) && defined(TIMSK1) && defined(OCIE1A)
|
||||
OCR1A = ocr;
|
||||
timer1_toggle_count = toggle_count;
|
||||
bitWrite(TIMSK1, OCIE1A, 1);
|
||||
#elif defined(OCR1A) && defined(TIMSK) && defined(OCIE1A)
|
||||
// this combination is for at least the ATmega32
|
||||
OCR1A = ocr;
|
||||
timer1_toggle_count = toggle_count;
|
||||
bitWrite(TIMSK, OCIE1A, 1);
|
||||
#endif
|
||||
break;
|
||||
|
||||
#if defined(OCR2A) && defined(TIMSK2) && defined(OCIE2A)
|
||||
case 2:
|
||||
OCR2A = ocr;
|
||||
timer2_toggle_count = toggle_count;
|
||||
bitWrite(TIMSK2, OCIE2A, 1);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(OCR3A) && defined(TIMSK3) && defined(OCIE3A)
|
||||
case 3:
|
||||
OCR3A = ocr;
|
||||
timer3_toggle_count = toggle_count;
|
||||
bitWrite(TIMSK3, OCIE3A, 1);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(OCR4A) && defined(TIMSK4) && defined(OCIE4A)
|
||||
case 4:
|
||||
OCR4A = ocr;
|
||||
timer4_toggle_count = toggle_count;
|
||||
bitWrite(TIMSK4, OCIE4A, 1);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(OCR5A) && defined(TIMSK5) && defined(OCIE5A)
|
||||
case 5:
|
||||
OCR5A = ocr;
|
||||
timer5_toggle_count = toggle_count;
|
||||
bitWrite(TIMSK5, OCIE5A, 1);
|
||||
break;
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// XXX: this function only works properly for timer 2 (the only one we use
|
||||
// currently). for the others, it should end the tone, but won't restore
|
||||
// proper PWM functionality for the timer.
|
||||
void disableTimer(uint8_t _timer)
|
||||
{
|
||||
switch (_timer)
|
||||
{
|
||||
case 0:
|
||||
#if defined(TIMSK0)
|
||||
TIMSK0 = 0;
|
||||
#elif defined(TIMSK)
|
||||
TIMSK = 0; // atmega32
|
||||
#endif
|
||||
break;
|
||||
|
||||
#if defined(TIMSK1) && defined(OCIE1A)
|
||||
case 1:
|
||||
bitWrite(TIMSK1, OCIE1A, 0);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 2:
|
||||
#if defined(TIMSK2) && defined(OCIE2A)
|
||||
bitWrite(TIMSK2, OCIE2A, 0); // disable interrupt
|
||||
#endif
|
||||
#if defined(TCCR2A) && defined(WGM20)
|
||||
TCCR2A = (1 << WGM20);
|
||||
#endif
|
||||
#if defined(TCCR2B) && defined(CS22)
|
||||
TCCR2B = (TCCR2B & 0b11111000) | (1 << CS22);
|
||||
#endif
|
||||
#if defined(OCR2A)
|
||||
OCR2A = 0;
|
||||
#endif
|
||||
break;
|
||||
|
||||
#if defined(TIMSK3) && defined(OCIE3A)
|
||||
case 3:
|
||||
bitWrite(TIMSK3, OCIE3A, 0);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TIMSK4) && defined(OCIE4A)
|
||||
case 4:
|
||||
bitWrite(TIMSK4, OCIE4A, 0);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TIMSK5) && defined(OCIE5A)
|
||||
case 5:
|
||||
bitWrite(TIMSK5, OCIE5A, 0);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void noTone(uint8_t _pin)
|
||||
{
|
||||
int8_t _timer = -1;
|
||||
|
||||
for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
|
||||
if (tone_pins[i] == _pin) {
|
||||
_timer = pgm_read_byte(tone_pin_to_timer_PGM + i);
|
||||
tone_pins[i] = 255;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
disableTimer(_timer);
|
||||
|
||||
digitalWrite(_pin, 0);
|
||||
}
|
||||
|
||||
#ifdef USE_TIMER0
|
||||
ISR(TIMER0_COMPA_vect)
|
||||
{
|
||||
if (timer0_toggle_count != 0)
|
||||
{
|
||||
// toggle the pin
|
||||
*timer0_pin_port ^= timer0_pin_mask;
|
||||
|
||||
if (timer0_toggle_count > 0)
|
||||
timer0_toggle_count--;
|
||||
}
|
||||
else
|
||||
{
|
||||
disableTimer(0);
|
||||
*timer0_pin_port &= ~(timer0_pin_mask); // keep pin low after stop
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USE_TIMER1
|
||||
ISR(TIMER1_COMPA_vect)
|
||||
{
|
||||
if (timer1_toggle_count != 0)
|
||||
{
|
||||
// toggle the pin
|
||||
*timer1_pin_port ^= timer1_pin_mask;
|
||||
|
||||
if (timer1_toggle_count > 0)
|
||||
timer1_toggle_count--;
|
||||
}
|
||||
else
|
||||
{
|
||||
disableTimer(1);
|
||||
*timer1_pin_port &= ~(timer1_pin_mask); // keep pin low after stop
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USE_TIMER2
|
||||
ISR(TIMER2_COMPA_vect)
|
||||
{
|
||||
|
||||
if (timer2_toggle_count != 0)
|
||||
{
|
||||
// toggle the pin
|
||||
*timer2_pin_port ^= timer2_pin_mask;
|
||||
|
||||
if (timer2_toggle_count > 0)
|
||||
timer2_toggle_count--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// need to call noTone() so that the tone_pins[] entry is reset, so the
|
||||
// timer gets initialized next time we call tone().
|
||||
// XXX: this assumes timer 2 is always the first one used.
|
||||
noTone(tone_pins[0]);
|
||||
// disableTimer(2);
|
||||
// *timer2_pin_port &= ~(timer2_pin_mask); // keep pin low after stop
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USE_TIMER3
|
||||
ISR(TIMER3_COMPA_vect)
|
||||
{
|
||||
if (timer3_toggle_count != 0)
|
||||
{
|
||||
// toggle the pin
|
||||
*timer3_pin_port ^= timer3_pin_mask;
|
||||
|
||||
if (timer3_toggle_count > 0)
|
||||
timer3_toggle_count--;
|
||||
}
|
||||
else
|
||||
{
|
||||
disableTimer(3);
|
||||
*timer3_pin_port &= ~(timer3_pin_mask); // keep pin low after stop
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USE_TIMER4
|
||||
ISR(TIMER4_COMPA_vect)
|
||||
{
|
||||
if (timer4_toggle_count != 0)
|
||||
{
|
||||
// toggle the pin
|
||||
*timer4_pin_port ^= timer4_pin_mask;
|
||||
|
||||
if (timer4_toggle_count > 0)
|
||||
timer4_toggle_count--;
|
||||
}
|
||||
else
|
||||
{
|
||||
disableTimer(4);
|
||||
*timer4_pin_port &= ~(timer4_pin_mask); // keep pin low after stop
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USE_TIMER5
|
||||
ISR(TIMER5_COMPA_vect)
|
||||
{
|
||||
if (timer5_toggle_count != 0)
|
||||
{
|
||||
// toggle the pin
|
||||
*timer5_pin_port ^= timer5_pin_mask;
|
||||
|
||||
if (timer5_toggle_count > 0)
|
||||
timer5_toggle_count--;
|
||||
}
|
||||
else
|
||||
{
|
||||
disableTimer(5);
|
||||
*timer5_pin_port &= ~(timer5_pin_mask); // keep pin low after stop
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,324 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Wiring project - http://wiring.uniandes.edu.co
|
||||
|
||||
Copyright (c) 2004-05 Hernando Barragan
|
||||
|
||||
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., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
Modified 24 November 2006 by David A. Mellis
|
||||
Modified 1 August 2010 by Mark Sproul
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "wiring_private.h"
|
||||
|
||||
static void nothing(void) {
|
||||
}
|
||||
|
||||
static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS] = {
|
||||
#if EXTERNAL_NUM_INTERRUPTS > 8
|
||||
#warning There are more than 8 external interrupts. Some callbacks may not be initialized.
|
||||
nothing,
|
||||
#endif
|
||||
#if EXTERNAL_NUM_INTERRUPTS > 7
|
||||
nothing,
|
||||
#endif
|
||||
#if EXTERNAL_NUM_INTERRUPTS > 6
|
||||
nothing,
|
||||
#endif
|
||||
#if EXTERNAL_NUM_INTERRUPTS > 5
|
||||
nothing,
|
||||
#endif
|
||||
#if EXTERNAL_NUM_INTERRUPTS > 4
|
||||
nothing,
|
||||
#endif
|
||||
#if EXTERNAL_NUM_INTERRUPTS > 3
|
||||
nothing,
|
||||
#endif
|
||||
#if EXTERNAL_NUM_INTERRUPTS > 2
|
||||
nothing,
|
||||
#endif
|
||||
#if EXTERNAL_NUM_INTERRUPTS > 1
|
||||
nothing,
|
||||
#endif
|
||||
#if EXTERNAL_NUM_INTERRUPTS > 0
|
||||
nothing,
|
||||
#endif
|
||||
};
|
||||
// volatile static voidFuncPtr twiIntFunc;
|
||||
|
||||
void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) {
|
||||
if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
|
||||
intFunc[interruptNum] = userFunc;
|
||||
|
||||
// Configure the interrupt mode (trigger on low input, any change, rising
|
||||
// edge, or falling edge). The mode constants were chosen to correspond
|
||||
// to the configuration bits in the hardware register, so we simply shift
|
||||
// the mode into place.
|
||||
|
||||
// Enable the interrupt.
|
||||
|
||||
switch (interruptNum) {
|
||||
#if defined(__AVR_ATmega32U4__)
|
||||
// I hate doing this, but the register assignment differs between the 1280/2560
|
||||
// and the 32U4. Since avrlib defines registers PCMSK1 and PCMSK2 that aren't
|
||||
// even present on the 32U4 this is the only way to distinguish between them.
|
||||
case 0:
|
||||
EICRA = (EICRA & ~((1<<ISC00) | (1<<ISC01))) | (mode << ISC00);
|
||||
EIMSK |= (1<<INT0);
|
||||
break;
|
||||
case 1:
|
||||
EICRA = (EICRA & ~((1<<ISC10) | (1<<ISC11))) | (mode << ISC10);
|
||||
EIMSK |= (1<<INT1);
|
||||
break;
|
||||
case 2:
|
||||
EICRA = (EICRA & ~((1<<ISC20) | (1<<ISC21))) | (mode << ISC20);
|
||||
EIMSK |= (1<<INT2);
|
||||
break;
|
||||
case 3:
|
||||
EICRA = (EICRA & ~((1<<ISC30) | (1<<ISC31))) | (mode << ISC30);
|
||||
EIMSK |= (1<<INT3);
|
||||
break;
|
||||
case 4:
|
||||
EICRB = (EICRB & ~((1<<ISC60) | (1<<ISC61))) | (mode << ISC60);
|
||||
EIMSK |= (1<<INT6);
|
||||
break;
|
||||
#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
|
||||
case 2:
|
||||
EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
|
||||
EIMSK |= (1 << INT0);
|
||||
break;
|
||||
case 3:
|
||||
EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
|
||||
EIMSK |= (1 << INT1);
|
||||
break;
|
||||
case 4:
|
||||
EICRA = (EICRA & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
|
||||
EIMSK |= (1 << INT2);
|
||||
break;
|
||||
case 5:
|
||||
EICRA = (EICRA & ~((1 << ISC30) | (1 << ISC31))) | (mode << ISC30);
|
||||
EIMSK |= (1 << INT3);
|
||||
break;
|
||||
case 0:
|
||||
EICRB = (EICRB & ~((1 << ISC40) | (1 << ISC41))) | (mode << ISC40);
|
||||
EIMSK |= (1 << INT4);
|
||||
break;
|
||||
case 1:
|
||||
EICRB = (EICRB & ~((1 << ISC50) | (1 << ISC51))) | (mode << ISC50);
|
||||
EIMSK |= (1 << INT5);
|
||||
break;
|
||||
case 6:
|
||||
EICRB = (EICRB & ~((1 << ISC60) | (1 << ISC61))) | (mode << ISC60);
|
||||
EIMSK |= (1 << INT6);
|
||||
break;
|
||||
case 7:
|
||||
EICRB = (EICRB & ~((1 << ISC70) | (1 << ISC71))) | (mode << ISC70);
|
||||
EIMSK |= (1 << INT7);
|
||||
break;
|
||||
#else
|
||||
case 0:
|
||||
#if defined(EICRA) && defined(ISC00) && defined(EIMSK)
|
||||
EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
|
||||
EIMSK |= (1 << INT0);
|
||||
#elif defined(MCUCR) && defined(ISC00) && defined(GICR)
|
||||
MCUCR = (MCUCR & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
|
||||
GICR |= (1 << INT0);
|
||||
#elif defined(MCUCR) && defined(ISC00) && defined(GIMSK)
|
||||
MCUCR = (MCUCR & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
|
||||
GIMSK |= (1 << INT0);
|
||||
#else
|
||||
#error attachInterrupt not finished for this CPU (case 0)
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 1:
|
||||
#if defined(EICRA) && defined(ISC10) && defined(ISC11) && defined(EIMSK)
|
||||
EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
|
||||
EIMSK |= (1 << INT1);
|
||||
#elif defined(MCUCR) && defined(ISC10) && defined(ISC11) && defined(GICR)
|
||||
MCUCR = (MCUCR & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
|
||||
GICR |= (1 << INT1);
|
||||
#elif defined(MCUCR) && defined(ISC10) && defined(GIMSK) && defined(GIMSK)
|
||||
MCUCR = (MCUCR & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
|
||||
GIMSK |= (1 << INT1);
|
||||
#else
|
||||
#warning attachInterrupt may need some more work for this cpu (case 1)
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 2:
|
||||
#if defined(EICRA) && defined(ISC20) && defined(ISC21) && defined(EIMSK)
|
||||
EICRA = (EICRA & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
|
||||
EIMSK |= (1 << INT2);
|
||||
#elif defined(MCUCR) && defined(ISC20) && defined(ISC21) && defined(GICR)
|
||||
MCUCR = (MCUCR & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
|
||||
GICR |= (1 << INT2);
|
||||
#elif defined(MCUCR) && defined(ISC20) && defined(GIMSK) && defined(GIMSK)
|
||||
MCUCR = (MCUCR & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
|
||||
GIMSK |= (1 << INT2);
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void detachInterrupt(uint8_t interruptNum) {
|
||||
if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
|
||||
// Disable the interrupt. (We can't assume that interruptNum is equal
|
||||
// to the number of the EIMSK bit to clear, as this isn't true on the
|
||||
// ATmega8. There, INT0 is 6 and INT1 is 7.)
|
||||
switch (interruptNum) {
|
||||
#if defined(__AVR_ATmega32U4__)
|
||||
case 0:
|
||||
EIMSK &= ~(1<<INT0);
|
||||
break;
|
||||
case 1:
|
||||
EIMSK &= ~(1<<INT1);
|
||||
break;
|
||||
case 2:
|
||||
EIMSK &= ~(1<<INT2);
|
||||
break;
|
||||
case 3:
|
||||
EIMSK &= ~(1<<INT3);
|
||||
break;
|
||||
case 4:
|
||||
EIMSK &= ~(1<<INT6);
|
||||
break;
|
||||
#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
|
||||
case 2:
|
||||
EIMSK &= ~(1 << INT0);
|
||||
break;
|
||||
case 3:
|
||||
EIMSK &= ~(1 << INT1);
|
||||
break;
|
||||
case 4:
|
||||
EIMSK &= ~(1 << INT2);
|
||||
break;
|
||||
case 5:
|
||||
EIMSK &= ~(1 << INT3);
|
||||
break;
|
||||
case 0:
|
||||
EIMSK &= ~(1 << INT4);
|
||||
break;
|
||||
case 1:
|
||||
EIMSK &= ~(1 << INT5);
|
||||
break;
|
||||
case 6:
|
||||
EIMSK &= ~(1 << INT6);
|
||||
break;
|
||||
case 7:
|
||||
EIMSK &= ~(1 << INT7);
|
||||
break;
|
||||
#else
|
||||
case 0:
|
||||
#if defined(EIMSK) && defined(INT0)
|
||||
EIMSK &= ~(1 << INT0);
|
||||
#elif defined(GICR) && defined(ISC00)
|
||||
GICR &= ~(1 << INT0); // atmega32
|
||||
#elif defined(GIMSK) && defined(INT0)
|
||||
GIMSK &= ~(1 << INT0);
|
||||
#else
|
||||
#error detachInterrupt not finished for this cpu
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 1:
|
||||
#if defined(EIMSK) && defined(INT1)
|
||||
EIMSK &= ~(1 << INT1);
|
||||
#elif defined(GICR) && defined(INT1)
|
||||
GICR &= ~(1 << INT1); // atmega32
|
||||
#elif defined(GIMSK) && defined(INT1)
|
||||
GIMSK &= ~(1 << INT1);
|
||||
#else
|
||||
#warning detachInterrupt may need some more work for this cpu (case 1)
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 2:
|
||||
#if defined(EIMSK) && defined(INT2)
|
||||
EIMSK &= ~(1 << INT2);
|
||||
#elif defined(GICR) && defined(INT2)
|
||||
GICR &= ~(1 << INT2); // atmega32
|
||||
#elif defined(GIMSK) && defined(INT2)
|
||||
GIMSK &= ~(1 << INT2);
|
||||
#elif defined(INT2)
|
||||
#warning detachInterrupt may need some more work for this cpu (case 2)
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
intFunc[interruptNum] = nothing;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void attachInterruptTwi(void (*userFunc)(void) ) {
|
||||
twiIntFunc = userFunc;
|
||||
}
|
||||
*/
|
||||
|
||||
#define IMPLEMENT_ISR(vect, interrupt) \
|
||||
ISR(vect) { \
|
||||
intFunc[interrupt](); \
|
||||
}
|
||||
|
||||
#if defined(__AVR_ATmega32U4__)
|
||||
|
||||
IMPLEMENT_ISR(INT0_vect, EXTERNAL_INT_0)
|
||||
IMPLEMENT_ISR(INT1_vect, EXTERNAL_INT_1)
|
||||
IMPLEMENT_ISR(INT2_vect, EXTERNAL_INT_2)
|
||||
IMPLEMENT_ISR(INT3_vect, EXTERNAL_INT_3)
|
||||
IMPLEMENT_ISR(INT6_vect, EXTERNAL_INT_4)
|
||||
|
||||
#elif defined(EICRA) && defined(EICRB)
|
||||
|
||||
IMPLEMENT_ISR(INT0_vect, EXTERNAL_INT_2)
|
||||
IMPLEMENT_ISR(INT1_vect, EXTERNAL_INT_3)
|
||||
IMPLEMENT_ISR(INT2_vect, EXTERNAL_INT_4)
|
||||
IMPLEMENT_ISR(INT3_vect, EXTERNAL_INT_5)
|
||||
IMPLEMENT_ISR(INT4_vect, EXTERNAL_INT_0)
|
||||
IMPLEMENT_ISR(INT5_vect, EXTERNAL_INT_1)
|
||||
IMPLEMENT_ISR(INT6_vect, EXTERNAL_INT_6)
|
||||
IMPLEMENT_ISR(INT7_vect, EXTERNAL_INT_7)
|
||||
|
||||
#else
|
||||
|
||||
IMPLEMENT_ISR(INT0_vect, EXTERNAL_INT_0)
|
||||
IMPLEMENT_ISR(INT1_vect, EXTERNAL_INT_1)
|
||||
|
||||
#if defined(EICRA) && defined(ISC20)
|
||||
IMPLEMENT_ISR(INT2_vect, EXTERNAL_INT_2)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
ISR(TWI_vect) {
|
||||
if(twiIntFunc)
|
||||
twiIntFunc();
|
||||
}
|
||||
*/
|
||||
|
@ -0,0 +1,58 @@
|
||||
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Wiring project - http://wiring.org.co
|
||||
Copyright (c) 2004-06 Hernando Barragan
|
||||
Modified 13 August 2006, David A. Mellis for Arduino - http://www.arduino.cc/
|
||||
|
||||
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., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
#include "stdlib.h"
|
||||
}
|
||||
|
||||
void randomSeed(unsigned long seed)
|
||||
{
|
||||
if (seed != 0) {
|
||||
srandom(seed);
|
||||
}
|
||||
}
|
||||
|
||||
long random(long howbig)
|
||||
{
|
||||
if (howbig == 0) {
|
||||
return 0;
|
||||
}
|
||||
return random() % howbig;
|
||||
}
|
||||
|
||||
long random(long howsmall, long howbig)
|
||||
{
|
||||
if (howsmall >= howbig) {
|
||||
return howsmall;
|
||||
}
|
||||
long diff = howbig - howsmall;
|
||||
return random(diff) + howsmall;
|
||||
}
|
||||
|
||||
long map(long x, long in_min, long in_max, long out_min, long out_max)
|
||||
{
|
||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
}
|
||||
|
||||
unsigned int makeWord(unsigned int w) { return w; }
|
||||
unsigned int makeWord(unsigned char h, unsigned char l) { return (h << 8) | l; }
|
@ -0,0 +1,750 @@
|
||||
/*
|
||||
WString.cpp - String library for Wiring & Arduino
|
||||
...mostly rewritten by Paul Stoffregen...
|
||||
Copyright (c) 2009-10 Hernando Barragan. All rights reserved.
|
||||
Copyright 2011, Paul Stoffregen, paul@pjrc.com
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
#include "WString.h"
|
||||
|
||||
/*********************************************/
|
||||
/* Constructors */
|
||||
/*********************************************/
|
||||
|
||||
String::String(const char *cstr)
|
||||
{
|
||||
init();
|
||||
if (cstr) copy(cstr, strlen(cstr));
|
||||
}
|
||||
|
||||
String::String(const String &value)
|
||||
{
|
||||
init();
|
||||
*this = value;
|
||||
}
|
||||
|
||||
String::String(const __FlashStringHelper *pstr)
|
||||
{
|
||||
init();
|
||||
*this = pstr;
|
||||
}
|
||||
|
||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
String::String(String &&rval)
|
||||
{
|
||||
init();
|
||||
move(rval);
|
||||
}
|
||||
String::String(StringSumHelper &&rval)
|
||||
{
|
||||
init();
|
||||
move(rval);
|
||||
}
|
||||
#endif
|
||||
|
||||
String::String(char c)
|
||||
{
|
||||
init();
|
||||
char buf[2];
|
||||
buf[0] = c;
|
||||
buf[1] = 0;
|
||||
*this = buf;
|
||||
}
|
||||
|
||||
String::String(unsigned char value, unsigned char base)
|
||||
{
|
||||
init();
|
||||
char buf[1 + 8 * sizeof(unsigned char)];
|
||||
utoa(value, buf, base);
|
||||
*this = buf;
|
||||
}
|
||||
|
||||
String::String(int value, unsigned char base)
|
||||
{
|
||||
init();
|
||||
char buf[2 + 8 * sizeof(int)];
|
||||
itoa(value, buf, base);
|
||||
*this = buf;
|
||||
}
|
||||
|
||||
String::String(unsigned int value, unsigned char base)
|
||||
{
|
||||
init();
|
||||
char buf[1 + 8 * sizeof(unsigned int)];
|
||||
utoa(value, buf, base);
|
||||
*this = buf;
|
||||
}
|
||||
|
||||
String::String(long value, unsigned char base)
|
||||
{
|
||||
init();
|
||||
char buf[2 + 8 * sizeof(long)];
|
||||
ltoa(value, buf, base);
|
||||
*this = buf;
|
||||
}
|
||||
|
||||
String::String(unsigned long value, unsigned char base)
|
||||
{
|
||||
init();
|
||||
char buf[1 + 8 * sizeof(unsigned long)];
|
||||
ultoa(value, buf, base);
|
||||
*this = buf;
|
||||
}
|
||||
|
||||
String::String(float value, unsigned char decimalPlaces)
|
||||
{
|
||||
init();
|
||||
char buf[33];
|
||||
*this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);
|
||||
}
|
||||
|
||||
String::String(double value, unsigned char decimalPlaces)
|
||||
{
|
||||
init();
|
||||
char buf[33];
|
||||
*this = dtostrf(value, (decimalPlaces + 2), decimalPlaces, buf);
|
||||
}
|
||||
|
||||
String::~String()
|
||||
{
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
/* Memory Management */
|
||||
/*********************************************/
|
||||
|
||||
inline void String::init(void)
|
||||
{
|
||||
buffer = NULL;
|
||||
capacity = 0;
|
||||
len = 0;
|
||||
}
|
||||
|
||||
void String::invalidate(void)
|
||||
{
|
||||
if (buffer) free(buffer);
|
||||
buffer = NULL;
|
||||
capacity = len = 0;
|
||||
}
|
||||
|
||||
unsigned char String::reserve(unsigned int size)
|
||||
{
|
||||
if (buffer && capacity >= size) return 1;
|
||||
if (changeBuffer(size)) {
|
||||
if (len == 0) buffer[0] = 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char String::changeBuffer(unsigned int maxStrLen)
|
||||
{
|
||||
char *newbuffer = (char *)realloc(buffer, maxStrLen + 1);
|
||||
if (newbuffer) {
|
||||
buffer = newbuffer;
|
||||
capacity = maxStrLen;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
/* Copy and Move */
|
||||
/*********************************************/
|
||||
|
||||
String & String::copy(const char *cstr, unsigned int length)
|
||||
{
|
||||
if (!reserve(length)) {
|
||||
invalidate();
|
||||
return *this;
|
||||
}
|
||||
len = length;
|
||||
strcpy(buffer, cstr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
String & String::copy(const __FlashStringHelper *pstr, unsigned int length)
|
||||
{
|
||||
if (!reserve(length)) {
|
||||
invalidate();
|
||||
return *this;
|
||||
}
|
||||
len = length;
|
||||
strcpy_P(buffer, (PGM_P)pstr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
void String::move(String &rhs)
|
||||
{
|
||||
if (buffer) {
|
||||
if (rhs && capacity >= rhs.len) {
|
||||
strcpy(buffer, rhs.buffer);
|
||||
len = rhs.len;
|
||||
rhs.len = 0;
|
||||
return;
|
||||
} else {
|
||||
free(buffer);
|
||||
}
|
||||
}
|
||||
buffer = rhs.buffer;
|
||||
capacity = rhs.capacity;
|
||||
len = rhs.len;
|
||||
rhs.buffer = NULL;
|
||||
rhs.capacity = 0;
|
||||
rhs.len = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
String & String::operator = (const String &rhs)
|
||||
{
|
||||
if (this == &rhs) return *this;
|
||||
|
||||
if (rhs.buffer) copy(rhs.buffer, rhs.len);
|
||||
else invalidate();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
String & String::operator = (String &&rval)
|
||||
{
|
||||
if (this != &rval) move(rval);
|
||||
return *this;
|
||||
}
|
||||
|
||||
String & String::operator = (StringSumHelper &&rval)
|
||||
{
|
||||
if (this != &rval) move(rval);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
String & String::operator = (const char *cstr)
|
||||
{
|
||||
if (cstr) copy(cstr, strlen(cstr));
|
||||
else invalidate();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
String & String::operator = (const __FlashStringHelper *pstr)
|
||||
{
|
||||
if (pstr) copy(pstr, strlen_P((PGM_P)pstr));
|
||||
else invalidate();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
/* concat */
|
||||
/*********************************************/
|
||||
|
||||
unsigned char String::concat(const String &s)
|
||||
{
|
||||
return concat(s.buffer, s.len);
|
||||
}
|
||||
|
||||
unsigned char String::concat(const char *cstr, unsigned int length)
|
||||
{
|
||||
unsigned int newlen = len + length;
|
||||
if (!cstr) return 0;
|
||||
if (length == 0) return 1;
|
||||
if (!reserve(newlen)) return 0;
|
||||
strcpy(buffer + len, cstr);
|
||||
len = newlen;
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned char String::concat(const char *cstr)
|
||||
{
|
||||
if (!cstr) return 0;
|
||||
return concat(cstr, strlen(cstr));
|
||||
}
|
||||
|
||||
unsigned char String::concat(char c)
|
||||
{
|
||||
char buf[2];
|
||||
buf[0] = c;
|
||||
buf[1] = 0;
|
||||
return concat(buf, 1);
|
||||
}
|
||||
|
||||
unsigned char String::concat(unsigned char num)
|
||||
{
|
||||
char buf[1 + 3 * sizeof(unsigned char)];
|
||||
itoa(num, buf, 10);
|
||||
return concat(buf, strlen(buf));
|
||||
}
|
||||
|
||||
unsigned char String::concat(int num)
|
||||
{
|
||||
char buf[2 + 3 * sizeof(int)];
|
||||
itoa(num, buf, 10);
|
||||
return concat(buf, strlen(buf));
|
||||
}
|
||||
|
||||
unsigned char String::concat(unsigned int num)
|
||||
{
|
||||
char buf[1 + 3 * sizeof(unsigned int)];
|
||||
utoa(num, buf, 10);
|
||||
return concat(buf, strlen(buf));
|
||||
}
|
||||
|
||||
unsigned char String::concat(long num)
|
||||
{
|
||||
char buf[2 + 3 * sizeof(long)];
|
||||
ltoa(num, buf, 10);
|
||||
return concat(buf, strlen(buf));
|
||||
}
|
||||
|
||||
unsigned char String::concat(unsigned long num)
|
||||
{
|
||||
char buf[1 + 3 * sizeof(unsigned long)];
|
||||
ultoa(num, buf, 10);
|
||||
return concat(buf, strlen(buf));
|
||||
}
|
||||
|
||||
unsigned char String::concat(float num)
|
||||
{
|
||||
char buf[20];
|
||||
char* string = dtostrf(num, 4, 2, buf);
|
||||
return concat(string, strlen(string));
|
||||
}
|
||||
|
||||
unsigned char String::concat(double num)
|
||||
{
|
||||
char buf[20];
|
||||
char* string = dtostrf(num, 4, 2, buf);
|
||||
return concat(string, strlen(string));
|
||||
}
|
||||
|
||||
unsigned char String::concat(const __FlashStringHelper * str)
|
||||
{
|
||||
if (!str) return 0;
|
||||
int length = strlen_P((const char *) str);
|
||||
if (length == 0) return 1;
|
||||
unsigned int newlen = len + length;
|
||||
if (!reserve(newlen)) return 0;
|
||||
strcpy_P(buffer + len, (const char *) str);
|
||||
len = newlen;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
/* Concatenate */
|
||||
/*********************************************/
|
||||
|
||||
StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs)
|
||||
{
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
if (!a.concat(rhs.buffer, rhs.len)) a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr)
|
||||
{
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
if (!cstr || !a.concat(cstr, strlen(cstr))) a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator + (const StringSumHelper &lhs, char c)
|
||||
{
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
if (!a.concat(c)) a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num)
|
||||
{
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
if (!a.concat(num)) a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator + (const StringSumHelper &lhs, int num)
|
||||
{
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
if (!a.concat(num)) a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num)
|
||||
{
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
if (!a.concat(num)) a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator + (const StringSumHelper &lhs, long num)
|
||||
{
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
if (!a.concat(num)) a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num)
|
||||
{
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
if (!a.concat(num)) a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator + (const StringSumHelper &lhs, float num)
|
||||
{
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
if (!a.concat(num)) a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator + (const StringSumHelper &lhs, double num)
|
||||
{
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
if (!a.concat(num)) a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *rhs)
|
||||
{
|
||||
StringSumHelper &a = const_cast<StringSumHelper&>(lhs);
|
||||
if (!a.concat(rhs)) a.invalidate();
|
||||
return a;
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
/* Comparison */
|
||||
/*********************************************/
|
||||
|
||||
int String::compareTo(const String &s) const
|
||||
{
|
||||
if (!buffer || !s.buffer) {
|
||||
if (s.buffer && s.len > 0) return 0 - *(unsigned char *)s.buffer;
|
||||
if (buffer && len > 0) return *(unsigned char *)buffer;
|
||||
return 0;
|
||||
}
|
||||
return strcmp(buffer, s.buffer);
|
||||
}
|
||||
|
||||
unsigned char String::equals(const String &s2) const
|
||||
{
|
||||
return (len == s2.len && compareTo(s2) == 0);
|
||||
}
|
||||
|
||||
unsigned char String::equals(const char *cstr) const
|
||||
{
|
||||
if (len == 0) return (cstr == NULL || *cstr == 0);
|
||||
if (cstr == NULL) return buffer[0] == 0;
|
||||
return strcmp(buffer, cstr) == 0;
|
||||
}
|
||||
|
||||
unsigned char String::operator<(const String &rhs) const
|
||||
{
|
||||
return compareTo(rhs) < 0;
|
||||
}
|
||||
|
||||
unsigned char String::operator>(const String &rhs) const
|
||||
{
|
||||
return compareTo(rhs) > 0;
|
||||
}
|
||||
|
||||
unsigned char String::operator<=(const String &rhs) const
|
||||
{
|
||||
return compareTo(rhs) <= 0;
|
||||
}
|
||||
|
||||
unsigned char String::operator>=(const String &rhs) const
|
||||
{
|
||||
return compareTo(rhs) >= 0;
|
||||
}
|
||||
|
||||
unsigned char String::equalsIgnoreCase( const String &s2 ) const
|
||||
{
|
||||
if (this == &s2) return 1;
|
||||
if (len != s2.len) return 0;
|
||||
if (len == 0) return 1;
|
||||
const char *p1 = buffer;
|
||||
const char *p2 = s2.buffer;
|
||||
while (*p1) {
|
||||
if (tolower(*p1++) != tolower(*p2++)) return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned char String::startsWith( const String &s2 ) const
|
||||
{
|
||||
if (len < s2.len) return 0;
|
||||
return startsWith(s2, 0);
|
||||
}
|
||||
|
||||
unsigned char String::startsWith( const String &s2, unsigned int offset ) const
|
||||
{
|
||||
if (offset > len - s2.len || !buffer || !s2.buffer) return 0;
|
||||
return strncmp( &buffer[offset], s2.buffer, s2.len ) == 0;
|
||||
}
|
||||
|
||||
unsigned char String::endsWith( const String &s2 ) const
|
||||
{
|
||||
if ( len < s2.len || !buffer || !s2.buffer) return 0;
|
||||
return strcmp(&buffer[len - s2.len], s2.buffer) == 0;
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
/* Character Access */
|
||||
/*********************************************/
|
||||
|
||||
char String::charAt(unsigned int loc) const
|
||||
{
|
||||
return operator[](loc);
|
||||
}
|
||||
|
||||
void String::setCharAt(unsigned int loc, char c)
|
||||
{
|
||||
if (loc < len) buffer[loc] = c;
|
||||
}
|
||||
|
||||
char & String::operator[](unsigned int index)
|
||||
{
|
||||
static char dummy_writable_char;
|
||||
if (index >= len || !buffer) {
|
||||
dummy_writable_char = 0;
|
||||
return dummy_writable_char;
|
||||
}
|
||||
return buffer[index];
|
||||
}
|
||||
|
||||
char String::operator[]( unsigned int index ) const
|
||||
{
|
||||
if (index >= len || !buffer) return 0;
|
||||
return buffer[index];
|
||||
}
|
||||
|
||||
void String::getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index) const
|
||||
{
|
||||
if (!bufsize || !buf) return;
|
||||
if (index >= len) {
|
||||
buf[0] = 0;
|
||||
return;
|
||||
}
|
||||
unsigned int n = bufsize - 1;
|
||||
if (n > len - index) n = len - index;
|
||||
strncpy((char *)buf, buffer + index, n);
|
||||
buf[n] = 0;
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
/* Search */
|
||||
/*********************************************/
|
||||
|
||||
int String::indexOf(char c) const
|
||||
{
|
||||
return indexOf(c, 0);
|
||||
}
|
||||
|
||||
int String::indexOf( char ch, unsigned int fromIndex ) const
|
||||
{
|
||||
if (fromIndex >= len) return -1;
|
||||
const char* temp = strchr(buffer + fromIndex, ch);
|
||||
if (temp == NULL) return -1;
|
||||
return temp - buffer;
|
||||
}
|
||||
|
||||
int String::indexOf(const String &s2) const
|
||||
{
|
||||
return indexOf(s2, 0);
|
||||
}
|
||||
|
||||
int String::indexOf(const String &s2, unsigned int fromIndex) const
|
||||
{
|
||||
if (fromIndex >= len) return -1;
|
||||
const char *found = strstr(buffer + fromIndex, s2.buffer);
|
||||
if (found == NULL) return -1;
|
||||
return found - buffer;
|
||||
}
|
||||
|
||||
int String::lastIndexOf( char theChar ) const
|
||||
{
|
||||
return lastIndexOf(theChar, len - 1);
|
||||
}
|
||||
|
||||
int String::lastIndexOf(char ch, unsigned int fromIndex) const
|
||||
{
|
||||
if (fromIndex >= len) return -1;
|
||||
char tempchar = buffer[fromIndex + 1];
|
||||
buffer[fromIndex + 1] = '\0';
|
||||
char* temp = strrchr( buffer, ch );
|
||||
buffer[fromIndex + 1] = tempchar;
|
||||
if (temp == NULL) return -1;
|
||||
return temp - buffer;
|
||||
}
|
||||
|
||||
int String::lastIndexOf(const String &s2) const
|
||||
{
|
||||
return lastIndexOf(s2, len - s2.len);
|
||||
}
|
||||
|
||||
int String::lastIndexOf(const String &s2, unsigned int fromIndex) const
|
||||
{
|
||||
if (s2.len == 0 || len == 0 || s2.len > len) return -1;
|
||||
if (fromIndex >= len) fromIndex = len - 1;
|
||||
int found = -1;
|
||||
for (char *p = buffer; p <= buffer + fromIndex; p++) {
|
||||
p = strstr(p, s2.buffer);
|
||||
if (!p) break;
|
||||
if ((unsigned int)(p - buffer) <= fromIndex) found = p - buffer;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
String String::substring(unsigned int left, unsigned int right) const
|
||||
{
|
||||
if (left > right) {
|
||||
unsigned int temp = right;
|
||||
right = left;
|
||||
left = temp;
|
||||
}
|
||||
String out;
|
||||
if (left >= len) return out;
|
||||
if (right > len) right = len;
|
||||
char temp = buffer[right]; // save the replaced character
|
||||
buffer[right] = '\0';
|
||||
out = buffer + left; // pointer arithmetic
|
||||
buffer[right] = temp; //restore character
|
||||
return out;
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
/* Modification */
|
||||
/*********************************************/
|
||||
|
||||
void String::replace(char find, char replace)
|
||||
{
|
||||
if (!buffer) return;
|
||||
for (char *p = buffer; *p; p++) {
|
||||
if (*p == find) *p = replace;
|
||||
}
|
||||
}
|
||||
|
||||
void String::replace(const String& find, const String& replace)
|
||||
{
|
||||
if (len == 0 || find.len == 0) return;
|
||||
int diff = replace.len - find.len;
|
||||
char *readFrom = buffer;
|
||||
char *foundAt;
|
||||
if (diff == 0) {
|
||||
while ((foundAt = strstr(readFrom, find.buffer)) != NULL) {
|
||||
memcpy(foundAt, replace.buffer, replace.len);
|
||||
readFrom = foundAt + replace.len;
|
||||
}
|
||||
} else if (diff < 0) {
|
||||
char *writeTo = buffer;
|
||||
while ((foundAt = strstr(readFrom, find.buffer)) != NULL) {
|
||||
unsigned int n = foundAt - readFrom;
|
||||
memcpy(writeTo, readFrom, n);
|
||||
writeTo += n;
|
||||
memcpy(writeTo, replace.buffer, replace.len);
|
||||
writeTo += replace.len;
|
||||
readFrom = foundAt + find.len;
|
||||
len += diff;
|
||||
}
|
||||
strcpy(writeTo, readFrom);
|
||||
} else {
|
||||
unsigned int size = len; // compute size needed for result
|
||||
while ((foundAt = strstr(readFrom, find.buffer)) != NULL) {
|
||||
readFrom = foundAt + find.len;
|
||||
size += diff;
|
||||
}
|
||||
if (size == len) return;
|
||||
if (size > capacity && !changeBuffer(size)) return; // XXX: tell user!
|
||||
int index = len - 1;
|
||||
while (index >= 0 && (index = lastIndexOf(find, index)) >= 0) {
|
||||
readFrom = buffer + index + find.len;
|
||||
memmove(readFrom + diff, readFrom, len - (readFrom - buffer));
|
||||
len += diff;
|
||||
buffer[len] = 0;
|
||||
memcpy(buffer + index, replace.buffer, replace.len);
|
||||
index--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void String::remove(unsigned int index){
|
||||
// Pass the biggest integer as the count. The remove method
|
||||
// below will take care of truncating it at the end of the
|
||||
// string.
|
||||
remove(index, (unsigned int)-1);
|
||||
}
|
||||
|
||||
void String::remove(unsigned int index, unsigned int count){
|
||||
if (index >= len) { return; }
|
||||
if (count <= 0) { return; }
|
||||
if (count > len - index) { count = len - index; }
|
||||
char *writeTo = buffer + index;
|
||||
len = len - count;
|
||||
strncpy(writeTo, buffer + index + count,len - index);
|
||||
buffer[len] = 0;
|
||||
}
|
||||
|
||||
void String::toLowerCase(void)
|
||||
{
|
||||
if (!buffer) return;
|
||||
for (char *p = buffer; *p; p++) {
|
||||
*p = tolower(*p);
|
||||
}
|
||||
}
|
||||
|
||||
void String::toUpperCase(void)
|
||||
{
|
||||
if (!buffer) return;
|
||||
for (char *p = buffer; *p; p++) {
|
||||
*p = toupper(*p);
|
||||
}
|
||||
}
|
||||
|
||||
void String::trim(void)
|
||||
{
|
||||
if (!buffer || len == 0) return;
|
||||
char *begin = buffer;
|
||||
while (isspace(*begin)) begin++;
|
||||
char *end = buffer + len - 1;
|
||||
while (isspace(*end) && end >= begin) end--;
|
||||
len = end + 1 - begin;
|
||||
if (begin > buffer) memcpy(buffer, begin, len);
|
||||
buffer[len] = 0;
|
||||
}
|
||||
|
||||
/*********************************************/
|
||||
/* Parsing / Conversion */
|
||||
/*********************************************/
|
||||
|
||||
long String::toInt(void) const
|
||||
{
|
||||
if (buffer) return atol(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
float String::toFloat(void) const
|
||||
{
|
||||
return float(toDouble());
|
||||
}
|
||||
|
||||
double String::toDouble(void) const
|
||||
{
|
||||
if (buffer) return atof(buffer);
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
Copyright (c) 2012 Arduino. 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
|
||||
*/
|
||||
|
||||
/**
|
||||
* Empty yield() hook.
|
||||
*
|
||||
* This function is intended to be used by library writers to build
|
||||
* libraries or sketches that supports cooperative threads.
|
||||
*
|
||||
* Its defined as a weak symbol and it can be redefined to implement a
|
||||
* real cooperative scheduler.
|
||||
*/
|
||||
static void __empty() {
|
||||
// Empty
|
||||
}
|
||||
void yield(void) __attribute__ ((weak, alias("__empty")));
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
main.cpp - Main loop for Arduino sketches
|
||||
Copyright (c) 2005-2013 Arduino Team. 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
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
// Declared weak in Arduino.h to allow user redefinitions.
|
||||
int atexit(void (* /*func*/ )()) { return 0; }
|
||||
|
||||
// Weak empty variant initialization function.
|
||||
// May be redefined by variant files.
|
||||
void initVariant() __attribute__((weak));
|
||||
void initVariant() { }
|
||||
|
||||
void setupUSB() __attribute__((weak));
|
||||
void setupUSB() { }
|
||||
|
||||
int main(void)
|
||||
{
|
||||
init();
|
||||
|
||||
initVariant();
|
||||
|
||||
#if defined(USBCON)
|
||||
USBDevice.attach();
|
||||
#endif
|
||||
|
||||
setup();
|
||||
|
||||
for (;;) {
|
||||
loop();
|
||||
if (serialEventRun) serialEventRun();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,392 @@
|
||||
/*
|
||||
wiring.c - Partial implementation of the Wiring API for the ATmega8.
|
||||
Part of Arduino - http://www.arduino.cc/
|
||||
|
||||
Copyright (c) 2005-2006 David A. Mellis
|
||||
|
||||
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., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "wiring_private.h"
|
||||
|
||||
// the prescaler is set so that timer0 ticks every 64 clock cycles, and the
|
||||
// the overflow handler is called every 256 ticks.
|
||||
#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256))
|
||||
|
||||
// the whole number of milliseconds per timer0 overflow
|
||||
#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000)
|
||||
|
||||
// the fractional number of milliseconds per timer0 overflow. we shift right
|
||||
// by three to fit these numbers into a byte. (for the clock speeds we care
|
||||
// about - 8 and 16 MHz - this doesn't lose precision.)
|
||||
#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3)
|
||||
#define FRACT_MAX (1000 >> 3)
|
||||
|
||||
volatile unsigned long timer0_overflow_count = 0;
|
||||
volatile unsigned long timer0_millis = 0;
|
||||
static unsigned char timer0_fract = 0;
|
||||
|
||||
#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
|
||||
ISR(TIM0_OVF_vect)
|
||||
#else
|
||||
ISR(TIMER0_OVF_vect)
|
||||
#endif
|
||||
{
|
||||
// copy these to local variables so they can be stored in registers
|
||||
// (volatile variables must be read from memory on every access)
|
||||
unsigned long m = timer0_millis;
|
||||
unsigned char f = timer0_fract;
|
||||
|
||||
m += MILLIS_INC;
|
||||
f += FRACT_INC;
|
||||
if (f >= FRACT_MAX) {
|
||||
f -= FRACT_MAX;
|
||||
m += 1;
|
||||
}
|
||||
|
||||
timer0_fract = f;
|
||||
timer0_millis = m;
|
||||
timer0_overflow_count++;
|
||||
}
|
||||
|
||||
unsigned long millis()
|
||||
{
|
||||
unsigned long m;
|
||||
uint8_t oldSREG = SREG;
|
||||
|
||||
// disable interrupts while we read timer0_millis or we might get an
|
||||
// inconsistent value (e.g. in the middle of a write to timer0_millis)
|
||||
cli();
|
||||
m = timer0_millis;
|
||||
SREG = oldSREG;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
unsigned long micros() {
|
||||
unsigned long m;
|
||||
uint8_t oldSREG = SREG, t;
|
||||
|
||||
cli();
|
||||
m = timer0_overflow_count;
|
||||
#if defined(TCNT0)
|
||||
t = TCNT0;
|
||||
#elif defined(TCNT0L)
|
||||
t = TCNT0L;
|
||||
#else
|
||||
#error TIMER 0 not defined
|
||||
#endif
|
||||
|
||||
#ifdef TIFR0
|
||||
if ((TIFR0 & _BV(TOV0)) && (t < 255))
|
||||
m++;
|
||||
#else
|
||||
if ((TIFR & _BV(TOV0)) && (t < 255))
|
||||
m++;
|
||||
#endif
|
||||
|
||||
SREG = oldSREG;
|
||||
|
||||
return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
|
||||
}
|
||||
|
||||
void delay(unsigned long ms)
|
||||
{
|
||||
uint32_t start = micros();
|
||||
|
||||
while (ms > 0) {
|
||||
yield();
|
||||
while ( ms > 0 && (micros() - start) >= 1000) {
|
||||
ms--;
|
||||
start += 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Delay for the given number of microseconds. Assumes a 1, 8, 12, 16, 20 or 24 MHz clock. */
|
||||
void delayMicroseconds(unsigned int us)
|
||||
{
|
||||
// call = 4 cycles + 2 to 4 cycles to init us(2 for constant delay, 4 for variable)
|
||||
|
||||
// calling avrlib's delay_us() function with low values (e.g. 1 or
|
||||
// 2 microseconds) gives delays longer than desired.
|
||||
//delay_us(us);
|
||||
#if F_CPU >= 24000000L
|
||||
// for the 24 MHz clock for the aventurous ones, trying to overclock
|
||||
|
||||
// zero delay fix
|
||||
if (!us) return; // = 3 cycles, (4 when true)
|
||||
|
||||
// the following loop takes a 1/6 of a microsecond (4 cycles)
|
||||
// per iteration, so execute it six times for each microsecond of
|
||||
// delay requested.
|
||||
us *= 6; // x6 us, = 7 cycles
|
||||
|
||||
// account for the time taken in the preceeding commands.
|
||||
// we just burned 22 (24) cycles above, remove 5, (5*4=20)
|
||||
// us is at least 6 so we can substract 5
|
||||
us -= 5; //=2 cycles
|
||||
|
||||
#elif F_CPU >= 20000000L
|
||||
// for the 20 MHz clock on rare Arduino boards
|
||||
|
||||
// for a one-microsecond delay, simply return. the overhead
|
||||
// of the function call takes 18 (20) cycles, which is 1us
|
||||
__asm__ __volatile__ (
|
||||
"nop" "\n\t"
|
||||
"nop" "\n\t"
|
||||
"nop" "\n\t"
|
||||
"nop"); //just waiting 4 cycles
|
||||
if (us <= 1) return; // = 3 cycles, (4 when true)
|
||||
|
||||
// the following loop takes a 1/5 of a microsecond (4 cycles)
|
||||
// per iteration, so execute it five times for each microsecond of
|
||||
// delay requested.
|
||||
us = (us << 2) + us; // x5 us, = 7 cycles
|
||||
|
||||
// account for the time taken in the preceeding commands.
|
||||
// we just burned 26 (28) cycles above, remove 7, (7*4=28)
|
||||
// us is at least 10 so we can substract 7
|
||||
us -= 7; // 2 cycles
|
||||
|
||||
#elif F_CPU >= 16000000L
|
||||
// for the 16 MHz clock on most Arduino boards
|
||||
|
||||
// for a one-microsecond delay, simply return. the overhead
|
||||
// of the function call takes 14 (16) cycles, which is 1us
|
||||
if (us <= 1) return; // = 3 cycles, (4 when true)
|
||||
|
||||
// the following loop takes 1/4 of a microsecond (4 cycles)
|
||||
// per iteration, so execute it four times for each microsecond of
|
||||
// delay requested.
|
||||
us <<= 2; // x4 us, = 4 cycles
|
||||
|
||||
// account for the time taken in the preceeding commands.
|
||||
// we just burned 19 (21) cycles above, remove 5, (5*4=20)
|
||||
// us is at least 8 so we can substract 5
|
||||
us -= 5; // = 2 cycles,
|
||||
|
||||
#elif F_CPU >= 12000000L
|
||||
// for the 12 MHz clock if somebody is working with USB
|
||||
|
||||
// for a 1 microsecond delay, simply return. the overhead
|
||||
// of the function call takes 14 (16) cycles, which is 1.5us
|
||||
if (us <= 1) return; // = 3 cycles, (4 when true)
|
||||
|
||||
// the following loop takes 1/3 of a microsecond (4 cycles)
|
||||
// per iteration, so execute it three times for each microsecond of
|
||||
// delay requested.
|
||||
us = (us << 1) + us; // x3 us, = 5 cycles
|
||||
|
||||
// account for the time taken in the preceeding commands.
|
||||
// we just burned 20 (22) cycles above, remove 5, (5*4=20)
|
||||
// us is at least 6 so we can substract 5
|
||||
us -= 5; //2 cycles
|
||||
|
||||
#elif F_CPU >= 8000000L
|
||||
// for the 8 MHz internal clock
|
||||
|
||||
// for a 1 and 2 microsecond delay, simply return. the overhead
|
||||
// of the function call takes 14 (16) cycles, which is 2us
|
||||
if (us <= 2) return; // = 3 cycles, (4 when true)
|
||||
|
||||
// the following loop takes 1/2 of a microsecond (4 cycles)
|
||||
// per iteration, so execute it twice for each microsecond of
|
||||
// delay requested.
|
||||
us <<= 1; //x2 us, = 2 cycles
|
||||
|
||||
// account for the time taken in the preceeding commands.
|
||||
// we just burned 17 (19) cycles above, remove 4, (4*4=16)
|
||||
// us is at least 6 so we can substract 4
|
||||
us -= 4; // = 2 cycles
|
||||
|
||||
#else
|
||||
// for the 1 MHz internal clock (default settings for common Atmega microcontrollers)
|
||||
|
||||
// the overhead of the function calls is 14 (16) cycles
|
||||
if (us <= 16) return; //= 3 cycles, (4 when true)
|
||||
if (us <= 25) return; //= 3 cycles, (4 when true), (must be at least 25 if we want to substract 22)
|
||||
|
||||
// compensate for the time taken by the preceeding and next commands (about 22 cycles)
|
||||
us -= 22; // = 2 cycles
|
||||
// the following loop takes 4 microseconds (4 cycles)
|
||||
// per iteration, so execute it us/4 times
|
||||
// us is at least 4, divided by 4 gives us 1 (no zero delay bug)
|
||||
us >>= 2; // us div 4, = 4 cycles
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
// busy wait
|
||||
__asm__ __volatile__ (
|
||||
"1: sbiw %0,1" "\n\t" // 2 cycles
|
||||
"brne 1b" : "=w" (us) : "0" (us) // 2 cycles
|
||||
);
|
||||
// return = 4 cycles
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
// this needs to be called before setup() or some functions won't
|
||||
// work there
|
||||
sei();
|
||||
|
||||
// on the ATmega168, timer 0 is also used for fast hardware pwm
|
||||
// (using phase-correct PWM would mean that timer 0 overflowed half as often
|
||||
// resulting in different millis() behavior on the ATmega8 and ATmega168)
|
||||
#if defined(TCCR0A) && defined(WGM01)
|
||||
sbi(TCCR0A, WGM01);
|
||||
sbi(TCCR0A, WGM00);
|
||||
#endif
|
||||
|
||||
// set timer 0 prescale factor to 64
|
||||
#if defined(__AVR_ATmega128__)
|
||||
// CPU specific: different values for the ATmega128
|
||||
sbi(TCCR0, CS02);
|
||||
#elif defined(TCCR0) && defined(CS01) && defined(CS00)
|
||||
// this combination is for the standard atmega8
|
||||
sbi(TCCR0, CS01);
|
||||
sbi(TCCR0, CS00);
|
||||
#elif defined(TCCR0B) && defined(CS01) && defined(CS00)
|
||||
// this combination is for the standard 168/328/1280/2560
|
||||
sbi(TCCR0B, CS01);
|
||||
sbi(TCCR0B, CS00);
|
||||
#elif defined(TCCR0A) && defined(CS01) && defined(CS00)
|
||||
// this combination is for the __AVR_ATmega645__ series
|
||||
sbi(TCCR0A, CS01);
|
||||
sbi(TCCR0A, CS00);
|
||||
#else
|
||||
#error Timer 0 prescale factor 64 not set correctly
|
||||
#endif
|
||||
|
||||
// enable timer 0 overflow interrupt
|
||||
#if defined(TIMSK) && defined(TOIE0)
|
||||
sbi(TIMSK, TOIE0);
|
||||
#elif defined(TIMSK0) && defined(TOIE0)
|
||||
sbi(TIMSK0, TOIE0);
|
||||
#else
|
||||
#error Timer 0 overflow interrupt not set correctly
|
||||
#endif
|
||||
|
||||
// timers 1 and 2 are used for phase-correct hardware pwm
|
||||
// this is better for motors as it ensures an even waveform
|
||||
// note, however, that fast pwm mode can achieve a frequency of up
|
||||
// 8 MHz (with a 16 MHz clock) at 50% duty cycle
|
||||
|
||||
#if defined(TCCR1B) && defined(CS11) && defined(CS10)
|
||||
TCCR1B = 0;
|
||||
|
||||
// set timer 1 prescale factor to 64
|
||||
sbi(TCCR1B, CS11);
|
||||
#if F_CPU >= 8000000L
|
||||
sbi(TCCR1B, CS10);
|
||||
#endif
|
||||
#elif defined(TCCR1) && defined(CS11) && defined(CS10)
|
||||
sbi(TCCR1, CS11);
|
||||
#if F_CPU >= 8000000L
|
||||
sbi(TCCR1, CS10);
|
||||
#endif
|
||||
#endif
|
||||
// put timer 1 in 8-bit phase correct pwm mode
|
||||
#if defined(TCCR1A) && defined(WGM10)
|
||||
sbi(TCCR1A, WGM10);
|
||||
#endif
|
||||
|
||||
// set timer 2 prescale factor to 64
|
||||
#if defined(TCCR2) && defined(CS22)
|
||||
sbi(TCCR2, CS22);
|
||||
#elif defined(TCCR2B) && defined(CS22)
|
||||
sbi(TCCR2B, CS22);
|
||||
//#else
|
||||
// Timer 2 not finished (may not be present on this CPU)
|
||||
#endif
|
||||
|
||||
// configure timer 2 for phase correct pwm (8-bit)
|
||||
#if defined(TCCR2) && defined(WGM20)
|
||||
sbi(TCCR2, WGM20);
|
||||
#elif defined(TCCR2A) && defined(WGM20)
|
||||
sbi(TCCR2A, WGM20);
|
||||
//#else
|
||||
// Timer 2 not finished (may not be present on this CPU)
|
||||
#endif
|
||||
|
||||
#if defined(TCCR3B) && defined(CS31) && defined(WGM30)
|
||||
sbi(TCCR3B, CS31); // set timer 3 prescale factor to 64
|
||||
sbi(TCCR3B, CS30);
|
||||
sbi(TCCR3A, WGM30); // put timer 3 in 8-bit phase correct pwm mode
|
||||
#endif
|
||||
|
||||
#if defined(TCCR4A) && defined(TCCR4B) && defined(TCCR4D) /* beginning of timer4 block for 32U4 and similar */
|
||||
sbi(TCCR4B, CS42); // set timer4 prescale factor to 64
|
||||
sbi(TCCR4B, CS41);
|
||||
sbi(TCCR4B, CS40);
|
||||
sbi(TCCR4D, WGM40); // put timer 4 in phase- and frequency-correct PWM mode
|
||||
sbi(TCCR4A, PWM4A); // enable PWM mode for comparator OCR4A
|
||||
sbi(TCCR4C, PWM4D); // enable PWM mode for comparator OCR4D
|
||||
#else /* beginning of timer4 block for ATMEGA1280 and ATMEGA2560 */
|
||||
#if defined(TCCR4B) && defined(CS41) && defined(WGM40)
|
||||
sbi(TCCR4B, CS41); // set timer 4 prescale factor to 64
|
||||
sbi(TCCR4B, CS40);
|
||||
sbi(TCCR4A, WGM40); // put timer 4 in 8-bit phase correct pwm mode
|
||||
#endif
|
||||
#endif /* end timer4 block for ATMEGA1280/2560 and similar */
|
||||
|
||||
#if defined(TCCR5B) && defined(CS51) && defined(WGM50)
|
||||
sbi(TCCR5B, CS51); // set timer 5 prescale factor to 64
|
||||
sbi(TCCR5B, CS50);
|
||||
sbi(TCCR5A, WGM50); // put timer 5 in 8-bit phase correct pwm mode
|
||||
#endif
|
||||
|
||||
#if defined(ADCSRA)
|
||||
// set a2d prescaler so we are inside the desired 50-200 KHz range.
|
||||
#if F_CPU >= 16000000 // 16 MHz / 128 = 125 KHz
|
||||
sbi(ADCSRA, ADPS2);
|
||||
sbi(ADCSRA, ADPS1);
|
||||
sbi(ADCSRA, ADPS0);
|
||||
#elif F_CPU >= 8000000 // 8 MHz / 64 = 125 KHz
|
||||
sbi(ADCSRA, ADPS2);
|
||||
sbi(ADCSRA, ADPS1);
|
||||
cbi(ADCSRA, ADPS0);
|
||||
#elif F_CPU >= 4000000 // 4 MHz / 32 = 125 KHz
|
||||
sbi(ADCSRA, ADPS2);
|
||||
cbi(ADCSRA, ADPS1);
|
||||
sbi(ADCSRA, ADPS0);
|
||||
#elif F_CPU >= 2000000 // 2 MHz / 16 = 125 KHz
|
||||
sbi(ADCSRA, ADPS2);
|
||||
cbi(ADCSRA, ADPS1);
|
||||
cbi(ADCSRA, ADPS0);
|
||||
#elif F_CPU >= 1000000 // 1 MHz / 8 = 125 KHz
|
||||
cbi(ADCSRA, ADPS2);
|
||||
sbi(ADCSRA, ADPS1);
|
||||
sbi(ADCSRA, ADPS0);
|
||||
#else // 128 kHz / 2 = 64 KHz -> This is the closest you can get, the prescaler is 2
|
||||
cbi(ADCSRA, ADPS2);
|
||||
cbi(ADCSRA, ADPS1);
|
||||
sbi(ADCSRA, ADPS0);
|
||||
#endif
|
||||
// enable a2d conversions
|
||||
sbi(ADCSRA, ADEN);
|
||||
#endif
|
||||
|
||||
// the bootloader connects pins 0 and 1 to the USART; disconnect them
|
||||
// here so they can be used as normal digital i/o; they will be
|
||||
// reconnected in Serial.begin()
|
||||
#if defined(UCSRB)
|
||||
UCSRB = 0;
|
||||
#elif defined(UCSR0B)
|
||||
UCSR0B = 0;
|
||||
#endif
|
||||
}
|
@ -0,0 +1,294 @@
|
||||
/*
|
||||
wiring_analog.c - analog input and output
|
||||
Part of Arduino - http://www.arduino.cc/
|
||||
|
||||
Copyright (c) 2005-2006 David A. Mellis
|
||||
|
||||
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., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
Modified 28 September 2010 by Mark Sproul
|
||||
*/
|
||||
|
||||
#include "wiring_private.h"
|
||||
#include "pins_arduino.h"
|
||||
|
||||
uint8_t analog_reference = DEFAULT;
|
||||
|
||||
void analogReference(uint8_t mode)
|
||||
{
|
||||
// can't actually set the register here because the default setting
|
||||
// will connect AVCC and the AREF pin, which would cause a short if
|
||||
// there's something connected to AREF.
|
||||
analog_reference = mode;
|
||||
}
|
||||
|
||||
int analogRead(uint8_t pin)
|
||||
{
|
||||
uint8_t low, high;
|
||||
|
||||
#if defined(analogPinToChannel)
|
||||
#if defined(__AVR_ATmega32U4__)
|
||||
if (pin >= 18) pin -= 18; // allow for channel or pin numbers
|
||||
#endif
|
||||
pin = analogPinToChannel(pin);
|
||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
if (pin >= 54) pin -= 54; // allow for channel or pin numbers
|
||||
#elif defined(__AVR_ATmega32U4__)
|
||||
if (pin >= 18) pin -= 18; // allow for channel or pin numbers
|
||||
#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__)
|
||||
if (pin >= 24) pin -= 24; // allow for channel or pin numbers
|
||||
#else
|
||||
if (pin >= 14) pin -= 14; // allow for channel or pin numbers
|
||||
#endif
|
||||
|
||||
#if defined(ADCSRB) && defined(MUX5)
|
||||
// the MUX5 bit of ADCSRB selects whether we're reading from channels
|
||||
// 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
|
||||
ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);
|
||||
#endif
|
||||
|
||||
// set the analog reference (high two bits of ADMUX) and select the
|
||||
// channel (low 4 bits). this also sets ADLAR (left-adjust result)
|
||||
// to 0 (the default).
|
||||
#if defined(ADMUX)
|
||||
#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
|
||||
ADMUX = (analog_reference << 4) | (pin & 0x07);
|
||||
#else
|
||||
ADMUX = (analog_reference << 6) | (pin & 0x07);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// without a delay, we seem to read from the wrong channel
|
||||
//delay(1);
|
||||
|
||||
#if defined(ADCSRA) && defined(ADCL)
|
||||
// start the conversion
|
||||
sbi(ADCSRA, ADSC);
|
||||
|
||||
// ADSC is cleared when the conversion finishes
|
||||
while (bit_is_set(ADCSRA, ADSC));
|
||||
|
||||
// we have to read ADCL first; doing so locks both ADCL
|
||||
// and ADCH until ADCH is read. reading ADCL second would
|
||||
// cause the results of each conversion to be discarded,
|
||||
// as ADCL and ADCH would be locked when it completed.
|
||||
low = ADCL;
|
||||
high = ADCH;
|
||||
#else
|
||||
// we dont have an ADC, return 0
|
||||
low = 0;
|
||||
high = 0;
|
||||
#endif
|
||||
|
||||
// combine the two bytes
|
||||
return (high << 8) | low;
|
||||
}
|
||||
|
||||
// Right now, PWM output only works on the pins with
|
||||
// hardware support. These are defined in the appropriate
|
||||
// pins_*.c file. For the rest of the pins, we default
|
||||
// to digital output.
|
||||
void analogWrite(uint8_t pin, int val)
|
||||
{
|
||||
// We need to make sure the PWM output is enabled for those pins
|
||||
// that support it, as we turn it off when digitally reading or
|
||||
// writing with them. Also, make sure the pin is in output mode
|
||||
// for consistenty with Wiring, which doesn't require a pinMode
|
||||
// call for the analog output pins.
|
||||
pinMode(pin, OUTPUT);
|
||||
if (val == 0)
|
||||
{
|
||||
digitalWrite(pin, LOW);
|
||||
}
|
||||
else if (val == 255)
|
||||
{
|
||||
digitalWrite(pin, HIGH);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(digitalPinToTimer(pin))
|
||||
{
|
||||
// XXX fix needed for atmega8
|
||||
#if defined(TCCR0) && defined(COM00) && !defined(__AVR_ATmega8__)
|
||||
case TIMER0A:
|
||||
// connect pwm to pin on timer 0
|
||||
sbi(TCCR0, COM00);
|
||||
OCR0 = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR0A) && defined(COM0A1)
|
||||
case TIMER0A:
|
||||
// connect pwm to pin on timer 0, channel A
|
||||
sbi(TCCR0A, COM0A1);
|
||||
OCR0A = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR0A) && defined(COM0B1)
|
||||
case TIMER0B:
|
||||
// connect pwm to pin on timer 0, channel B
|
||||
sbi(TCCR0A, COM0B1);
|
||||
OCR0B = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR1A) && defined(COM1A1)
|
||||
case TIMER1A:
|
||||
// connect pwm to pin on timer 1, channel A
|
||||
sbi(TCCR1A, COM1A1);
|
||||
OCR1A = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR1A) && defined(COM1B1)
|
||||
case TIMER1B:
|
||||
// connect pwm to pin on timer 1, channel B
|
||||
sbi(TCCR1A, COM1B1);
|
||||
OCR1B = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR1A) && defined(COM1C1)
|
||||
case TIMER1C:
|
||||
// connect pwm to pin on timer 1, channel B
|
||||
sbi(TCCR1A, COM1C1);
|
||||
OCR1C = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR2) && defined(COM21)
|
||||
case TIMER2:
|
||||
// connect pwm to pin on timer 2
|
||||
sbi(TCCR2, COM21);
|
||||
OCR2 = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR2A) && defined(COM2A1)
|
||||
case TIMER2A:
|
||||
// connect pwm to pin on timer 2, channel A
|
||||
sbi(TCCR2A, COM2A1);
|
||||
OCR2A = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR2A) && defined(COM2B1)
|
||||
case TIMER2B:
|
||||
// connect pwm to pin on timer 2, channel B
|
||||
sbi(TCCR2A, COM2B1);
|
||||
OCR2B = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR3A) && defined(COM3A1)
|
||||
case TIMER3A:
|
||||
// connect pwm to pin on timer 3, channel A
|
||||
sbi(TCCR3A, COM3A1);
|
||||
OCR3A = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR3A) && defined(COM3B1)
|
||||
case TIMER3B:
|
||||
// connect pwm to pin on timer 3, channel B
|
||||
sbi(TCCR3A, COM3B1);
|
||||
OCR3B = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR3A) && defined(COM3C1)
|
||||
case TIMER3C:
|
||||
// connect pwm to pin on timer 3, channel C
|
||||
sbi(TCCR3A, COM3C1);
|
||||
OCR3C = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR4A)
|
||||
case TIMER4A:
|
||||
//connect pwm to pin on timer 4, channel A
|
||||
sbi(TCCR4A, COM4A1);
|
||||
#if defined(COM4A0) // only used on 32U4
|
||||
cbi(TCCR4A, COM4A0);
|
||||
#endif
|
||||
OCR4A = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR4A) && defined(COM4B1)
|
||||
case TIMER4B:
|
||||
// connect pwm to pin on timer 4, channel B
|
||||
sbi(TCCR4A, COM4B1);
|
||||
OCR4B = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR4A) && defined(COM4C1)
|
||||
case TIMER4C:
|
||||
// connect pwm to pin on timer 4, channel C
|
||||
sbi(TCCR4A, COM4C1);
|
||||
OCR4C = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR4C) && defined(COM4D1)
|
||||
case TIMER4D:
|
||||
// connect pwm to pin on timer 4, channel D
|
||||
sbi(TCCR4C, COM4D1);
|
||||
#if defined(COM4D0) // only used on 32U4
|
||||
cbi(TCCR4C, COM4D0);
|
||||
#endif
|
||||
OCR4D = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(TCCR5A) && defined(COM5A1)
|
||||
case TIMER5A:
|
||||
// connect pwm to pin on timer 5, channel A
|
||||
sbi(TCCR5A, COM5A1);
|
||||
OCR5A = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR5A) && defined(COM5B1)
|
||||
case TIMER5B:
|
||||
// connect pwm to pin on timer 5, channel B
|
||||
sbi(TCCR5A, COM5B1);
|
||||
OCR5B = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR5A) && defined(COM5C1)
|
||||
case TIMER5C:
|
||||
// connect pwm to pin on timer 5, channel C
|
||||
sbi(TCCR5A, COM5C1);
|
||||
OCR5C = val; // set pwm duty
|
||||
break;
|
||||
#endif
|
||||
|
||||
case NOT_ON_TIMER:
|
||||
default:
|
||||
if (val < 128) {
|
||||
digitalWrite(pin, LOW);
|
||||
} else {
|
||||
digitalWrite(pin, HIGH);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,179 @@
|
||||
/*
|
||||
wiring_digital.c - digital input and output functions
|
||||
Part of Arduino - http://www.arduino.cc/
|
||||
|
||||
Copyright (c) 2005-2006 David A. Mellis
|
||||
|
||||
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., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
|
||||
Modified 28 September 2010 by Mark Sproul
|
||||
*/
|
||||
|
||||
#define ARDUINO_MAIN
|
||||
#include "wiring_private.h"
|
||||
#include "pins_arduino.h"
|
||||
|
||||
void pinMode(uint8_t pin, uint8_t mode)
|
||||
{
|
||||
uint8_t bit = digitalPinToBitMask(pin);
|
||||
uint8_t port = digitalPinToPort(pin);
|
||||
volatile uint8_t *reg, *out;
|
||||
|
||||
if (port == NOT_A_PIN) return;
|
||||
|
||||
// JWS: can I let the optimizer do this?
|
||||
reg = portModeRegister(port);
|
||||
out = portOutputRegister(port);
|
||||
|
||||
if (mode == INPUT) {
|
||||
uint8_t oldSREG = SREG;
|
||||
cli();
|
||||
*reg &= ~bit;
|
||||
*out &= ~bit;
|
||||
SREG = oldSREG;
|
||||
} else if (mode == INPUT_PULLUP) {
|
||||
uint8_t oldSREG = SREG;
|
||||
cli();
|
||||
*reg &= ~bit;
|
||||
*out |= bit;
|
||||
SREG = oldSREG;
|
||||
} else {
|
||||
uint8_t oldSREG = SREG;
|
||||
cli();
|
||||
*reg |= bit;
|
||||
SREG = oldSREG;
|
||||
}
|
||||
}
|
||||
|
||||
// Forcing this inline keeps the callers from having to push their own stuff
|
||||
// on the stack. It is a good performance win and only takes 1 more byte per
|
||||
// user than calling. (It will take more bytes on the 168.)
|
||||
//
|
||||
// But shouldn't this be moved into pinMode? Seems silly to check and do on
|
||||
// each digitalread or write.
|
||||
//
|
||||
// Mark Sproul:
|
||||
// - Removed inline. Save 170 bytes on atmega1280
|
||||
// - changed to a switch statment; added 32 bytes but much easier to read and maintain.
|
||||
// - Added more #ifdefs, now compiles for atmega645
|
||||
//
|
||||
//static inline void turnOffPWM(uint8_t timer) __attribute__ ((always_inline));
|
||||
//static inline void turnOffPWM(uint8_t timer)
|
||||
static void turnOffPWM(uint8_t timer)
|
||||
{
|
||||
switch (timer)
|
||||
{
|
||||
#if defined(TCCR1A) && defined(COM1A1)
|
||||
case TIMER1A: cbi(TCCR1A, COM1A1); break;
|
||||
#endif
|
||||
#if defined(TCCR1A) && defined(COM1B1)
|
||||
case TIMER1B: cbi(TCCR1A, COM1B1); break;
|
||||
#endif
|
||||
#if defined(TCCR1A) && defined(COM1C1)
|
||||
case TIMER1C: cbi(TCCR1A, COM1C1); break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR2) && defined(COM21)
|
||||
case TIMER2: cbi(TCCR2, COM21); break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR0A) && defined(COM0A1)
|
||||
case TIMER0A: cbi(TCCR0A, COM0A1); break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR0A) && defined(COM0B1)
|
||||
case TIMER0B: cbi(TCCR0A, COM0B1); break;
|
||||
#endif
|
||||
#if defined(TCCR2A) && defined(COM2A1)
|
||||
case TIMER2A: cbi(TCCR2A, COM2A1); break;
|
||||
#endif
|
||||
#if defined(TCCR2A) && defined(COM2B1)
|
||||
case TIMER2B: cbi(TCCR2A, COM2B1); break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR3A) && defined(COM3A1)
|
||||
case TIMER3A: cbi(TCCR3A, COM3A1); break;
|
||||
#endif
|
||||
#if defined(TCCR3A) && defined(COM3B1)
|
||||
case TIMER3B: cbi(TCCR3A, COM3B1); break;
|
||||
#endif
|
||||
#if defined(TCCR3A) && defined(COM3C1)
|
||||
case TIMER3C: cbi(TCCR3A, COM3C1); break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR4A) && defined(COM4A1)
|
||||
case TIMER4A: cbi(TCCR4A, COM4A1); break;
|
||||
#endif
|
||||
#if defined(TCCR4A) && defined(COM4B1)
|
||||
case TIMER4B: cbi(TCCR4A, COM4B1); break;
|
||||
#endif
|
||||
#if defined(TCCR4A) && defined(COM4C1)
|
||||
case TIMER4C: cbi(TCCR4A, COM4C1); break;
|
||||
#endif
|
||||
#if defined(TCCR4C) && defined(COM4D1)
|
||||
case TIMER4D: cbi(TCCR4C, COM4D1); break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR5A)
|
||||
case TIMER5A: cbi(TCCR5A, COM5A1); break;
|
||||
case TIMER5B: cbi(TCCR5A, COM5B1); break;
|
||||
case TIMER5C: cbi(TCCR5A, COM5C1); break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void digitalWrite(uint8_t pin, uint8_t val)
|
||||
{
|
||||
uint8_t timer = digitalPinToTimer(pin);
|
||||
uint8_t bit = digitalPinToBitMask(pin);
|
||||
uint8_t port = digitalPinToPort(pin);
|
||||
volatile uint8_t *out;
|
||||
|
||||
if (port == NOT_A_PIN) return;
|
||||
|
||||
// If the pin that support PWM output, we need to turn it off
|
||||
// before doing a digital write.
|
||||
if (timer != NOT_ON_TIMER) turnOffPWM(timer);
|
||||
|
||||
out = portOutputRegister(port);
|
||||
|
||||
uint8_t oldSREG = SREG;
|
||||
cli();
|
||||
|
||||
if (val == LOW) {
|
||||
*out &= ~bit;
|
||||
} else {
|
||||
*out |= bit;
|
||||
}
|
||||
|
||||
SREG = oldSREG;
|
||||
}
|
||||
|
||||
int digitalRead(uint8_t pin)
|
||||
{
|
||||
uint8_t timer = digitalPinToTimer(pin);
|
||||
uint8_t bit = digitalPinToBitMask(pin);
|
||||
uint8_t port = digitalPinToPort(pin);
|
||||
|
||||
if (port == NOT_A_PIN) return LOW;
|
||||
|
||||
// If the pin that support PWM output, we need to turn it off
|
||||
// before getting a digital reading.
|
||||
if (timer != NOT_ON_TIMER) turnOffPWM(timer);
|
||||
|
||||
if (*portInputRegister(port) & bit) return HIGH;
|
||||
return LOW;
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
/*
|
||||
wiring_pulse.c - pulseIn() function
|
||||
Part of Arduino - http://www.arduino.cc/
|
||||
|
||||
Copyright (c) 2005-2006 David A. Mellis
|
||||
|
||||
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., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "wiring_private.h"
|
||||
#include "pins_arduino.h"
|
||||
|
||||
/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH
|
||||
* or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds
|
||||
* to 3 minutes in length, but must be called at least a few dozen microseconds
|
||||
* before the start of the pulse.
|
||||
*
|
||||
* This function performs better with short pulses in noInterrupt() context
|
||||
*/
|
||||
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
|
||||
{
|
||||
// cache the port and bit of the pin in order to speed up the
|
||||
// pulse width measuring loop and achieve finer resolution. calling
|
||||
// digitalRead() instead yields much coarser resolution.
|
||||
uint8_t bit = digitalPinToBitMask(pin);
|
||||
uint8_t port = digitalPinToPort(pin);
|
||||
uint8_t stateMask = (state ? bit : 0);
|
||||
|
||||
// convert the timeout from microseconds to a number of times through
|
||||
// the initial loop; it takes approximately 16 clock cycles per iteration
|
||||
unsigned long maxloops = microsecondsToClockCycles(timeout)/16;
|
||||
|
||||
unsigned long width = countPulseASM(portInputRegister(port), bit, stateMask, maxloops);
|
||||
|
||||
// prevent clockCyclesToMicroseconds to return bogus values if countPulseASM timed out
|
||||
if (width)
|
||||
return clockCyclesToMicroseconds(width * 16 + 16);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH
|
||||
* or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds
|
||||
* to 3 minutes in length, but must be called at least a few dozen microseconds
|
||||
* before the start of the pulse.
|
||||
*
|
||||
* ATTENTION:
|
||||
* this function relies on micros() so cannot be used in noInterrupt() context
|
||||
*/
|
||||
unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout)
|
||||
{
|
||||
// cache the port and bit of the pin in order to speed up the
|
||||
// pulse width measuring loop and achieve finer resolution. calling
|
||||
// digitalRead() instead yields much coarser resolution.
|
||||
uint8_t bit = digitalPinToBitMask(pin);
|
||||
uint8_t port = digitalPinToPort(pin);
|
||||
uint8_t stateMask = (state ? bit : 0);
|
||||
|
||||
unsigned long startMicros = micros();
|
||||
|
||||
// wait for any previous pulse to end
|
||||
while ((*portInputRegister(port) & bit) == stateMask) {
|
||||
if (micros() - startMicros > timeout)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// wait for the pulse to start
|
||||
while ((*portInputRegister(port) & bit) != stateMask) {
|
||||
if (micros() - startMicros > timeout)
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long start = micros();
|
||||
// wait for the pulse to stop
|
||||
while ((*portInputRegister(port) & bit) == stateMask) {
|
||||
if (micros() - startMicros > timeout)
|
||||
return 0;
|
||||
}
|
||||
return micros() - start;
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
wiring_shift.c - shiftOut() function
|
||||
Part of Arduino - http://www.arduino.cc/
|
||||
|
||||
Copyright (c) 2005-2006 David A. Mellis
|
||||
|
||||
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., 59 Temple Place, Suite 330,
|
||||
Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "wiring_private.h"
|
||||
|
||||
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) {
|
||||
uint8_t value = 0;
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
digitalWrite(clockPin, HIGH);
|
||||
if (bitOrder == LSBFIRST)
|
||||
value |= digitalRead(dataPin) << i;
|
||||
else
|
||||
value |= digitalRead(dataPin) << (7 - i);
|
||||
digitalWrite(clockPin, LOW);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (bitOrder == LSBFIRST)
|
||||
digitalWrite(dataPin, !!(val & (1 << i)));
|
||||
else
|
||||
digitalWrite(dataPin, !!(val & (1 << (7 - i))));
|
||||
|
||||
digitalWrite(clockPin, HIGH);
|
||||
digitalWrite(clockPin, LOW);
|
||||
}
|
||||
}
|
@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright (c) 2010 by Cristian Maglie <c.maglie@arduino.cc>
|
||||
* Copyright (c) 2014 by Paul Stoffregen <paul@pjrc.com> (Transaction API)
|
||||
* Copyright (c) 2014 by Matthijs Kooijman <matthijs@stdin.nl> (SPISettings AVR)
|
||||
* Copyright (c) 2014 by Andrew J. Kroll <xxxajk@gmail.com> (atomicity fixes)
|
||||
* SPI Master library for arduino.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of either the GNU General Public License version 2
|
||||
* or the GNU Lesser General Public License version 2.1, both as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "SPI.h"
|
||||
|
||||
SPIClass SPI;
|
||||
|
||||
uint8_t SPIClass::initialized = 0;
|
||||
uint8_t SPIClass::interruptMode = 0;
|
||||
uint8_t SPIClass::interruptMask = 0;
|
||||
uint8_t SPIClass::interruptSave = 0;
|
||||
#ifdef SPI_TRANSACTION_MISMATCH_LED
|
||||
uint8_t SPIClass::inTransactionFlag = 0;
|
||||
#endif
|
||||
|
||||
void SPIClass::begin()
|
||||
{
|
||||
uint8_t sreg = SREG;
|
||||
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
|
||||
if (!initialized) {
|
||||
// Set SS to high so a connected chip will be "deselected" by default
|
||||
uint8_t port = digitalPinToPort(SS);
|
||||
uint8_t bit = digitalPinToBitMask(SS);
|
||||
volatile uint8_t *reg = portModeRegister(port);
|
||||
|
||||
// if the SS pin is not already configured as an output
|
||||
// then set it high (to enable the internal pull-up resistor)
|
||||
if(!(*reg & bit)){
|
||||
digitalWrite(SS, HIGH);
|
||||
}
|
||||
|
||||
// When the SS pin is set as OUTPUT, it can be used as
|
||||
// a general purpose output port (it doesn't influence
|
||||
// SPI operations).
|
||||
pinMode(SS, OUTPUT);
|
||||
|
||||
// Warning: if the SS pin ever becomes a LOW INPUT then SPI
|
||||
// automatically switches to Slave, so the data direction of
|
||||
// the SS pin MUST be kept as OUTPUT.
|
||||
SPCR |= _BV(MSTR);
|
||||
SPCR |= _BV(SPE);
|
||||
|
||||
// Set direction register for SCK and MOSI pin.
|
||||
// MISO pin automatically overrides to INPUT.
|
||||
// By doing this AFTER enabling SPI, we avoid accidentally
|
||||
// clocking in a single bit since the lines go directly
|
||||
// from "input" to SPI control.
|
||||
// http://code.google.com/p/arduino/issues/detail?id=888
|
||||
pinMode(SCK, OUTPUT);
|
||||
pinMode(MOSI, OUTPUT);
|
||||
}
|
||||
initialized++; // reference count
|
||||
SREG = sreg;
|
||||
}
|
||||
|
||||
void SPIClass::end() {
|
||||
uint8_t sreg = SREG;
|
||||
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
|
||||
// Decrease the reference counter
|
||||
if (initialized)
|
||||
initialized--;
|
||||
// If there are no more references disable SPI
|
||||
if (!initialized) {
|
||||
SPCR &= ~_BV(SPE);
|
||||
interruptMode = 0;
|
||||
#ifdef SPI_TRANSACTION_MISMATCH_LED
|
||||
inTransactionFlag = 0;
|
||||
#endif
|
||||
}
|
||||
SREG = sreg;
|
||||
}
|
||||
|
||||
// mapping of interrupt numbers to bits within SPI_AVR_EIMSK
|
||||
#if defined(__AVR_ATmega32U4__)
|
||||
#define SPI_INT0_MASK (1<<INT0)
|
||||
#define SPI_INT1_MASK (1<<INT1)
|
||||
#define SPI_INT2_MASK (1<<INT2)
|
||||
#define SPI_INT3_MASK (1<<INT3)
|
||||
#define SPI_INT4_MASK (1<<INT6)
|
||||
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
|
||||
#define SPI_INT0_MASK (1<<INT0)
|
||||
#define SPI_INT1_MASK (1<<INT1)
|
||||
#define SPI_INT2_MASK (1<<INT2)
|
||||
#define SPI_INT3_MASK (1<<INT3)
|
||||
#define SPI_INT4_MASK (1<<INT4)
|
||||
#define SPI_INT5_MASK (1<<INT5)
|
||||
#define SPI_INT6_MASK (1<<INT6)
|
||||
#define SPI_INT7_MASK (1<<INT7)
|
||||
#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
|
||||
#define SPI_INT0_MASK (1<<INT4)
|
||||
#define SPI_INT1_MASK (1<<INT5)
|
||||
#define SPI_INT2_MASK (1<<INT0)
|
||||
#define SPI_INT3_MASK (1<<INT1)
|
||||
#define SPI_INT4_MASK (1<<INT2)
|
||||
#define SPI_INT5_MASK (1<<INT3)
|
||||
#define SPI_INT6_MASK (1<<INT6)
|
||||
#define SPI_INT7_MASK (1<<INT7)
|
||||
#else
|
||||
#ifdef INT0
|
||||
#define SPI_INT0_MASK (1<<INT0)
|
||||
#endif
|
||||
#ifdef INT1
|
||||
#define SPI_INT1_MASK (1<<INT1)
|
||||
#endif
|
||||
#ifdef INT2
|
||||
#define SPI_INT2_MASK (1<<INT2)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void SPIClass::usingInterrupt(uint8_t interruptNumber)
|
||||
{
|
||||
uint8_t mask = 0;
|
||||
uint8_t sreg = SREG;
|
||||
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
|
||||
switch (interruptNumber) {
|
||||
#ifdef SPI_INT0_MASK
|
||||
case 0: mask = SPI_INT0_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT1_MASK
|
||||
case 1: mask = SPI_INT1_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT2_MASK
|
||||
case 2: mask = SPI_INT2_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT3_MASK
|
||||
case 3: mask = SPI_INT3_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT4_MASK
|
||||
case 4: mask = SPI_INT4_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT5_MASK
|
||||
case 5: mask = SPI_INT5_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT6_MASK
|
||||
case 6: mask = SPI_INT6_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT7_MASK
|
||||
case 7: mask = SPI_INT7_MASK; break;
|
||||
#endif
|
||||
default:
|
||||
interruptMode = 2;
|
||||
break;
|
||||
}
|
||||
interruptMask |= mask;
|
||||
if (!interruptMode)
|
||||
interruptMode = 1;
|
||||
SREG = sreg;
|
||||
}
|
||||
|
||||
void SPIClass::notUsingInterrupt(uint8_t interruptNumber)
|
||||
{
|
||||
// Once in mode 2 we can't go back to 0 without a proper reference count
|
||||
if (interruptMode == 2)
|
||||
return;
|
||||
uint8_t mask = 0;
|
||||
uint8_t sreg = SREG;
|
||||
noInterrupts(); // Protect from a scheduler and prevent transactionBegin
|
||||
switch (interruptNumber) {
|
||||
#ifdef SPI_INT0_MASK
|
||||
case 0: mask = SPI_INT0_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT1_MASK
|
||||
case 1: mask = SPI_INT1_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT2_MASK
|
||||
case 2: mask = SPI_INT2_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT3_MASK
|
||||
case 3: mask = SPI_INT3_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT4_MASK
|
||||
case 4: mask = SPI_INT4_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT5_MASK
|
||||
case 5: mask = SPI_INT5_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT6_MASK
|
||||
case 6: mask = SPI_INT6_MASK; break;
|
||||
#endif
|
||||
#ifdef SPI_INT7_MASK
|
||||
case 7: mask = SPI_INT7_MASK; break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
// this case can't be reached
|
||||
}
|
||||
interruptMask &= ~mask;
|
||||
if (!interruptMask)
|
||||
interruptMode = 0;
|
||||
SREG = sreg;
|
||||
}
|
@ -0,0 +1,326 @@
|
||||
#include "LiquidCrystal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include "Arduino.h"
|
||||
|
||||
// When the display powers up, it is configured as follows:
|
||||
//
|
||||
// 1. Display clear
|
||||
// 2. Function set:
|
||||
// DL = 1; 8-bit interface data
|
||||
// N = 0; 1-line display
|
||||
// F = 0; 5x8 dot character font
|
||||
// 3. Display on/off control:
|
||||
// D = 0; Display off
|
||||
// C = 0; Cursor off
|
||||
// B = 0; Blinking off
|
||||
// 4. Entry mode set:
|
||||
// I/D = 1; Increment by 1
|
||||
// S = 0; No shift
|
||||
//
|
||||
// Note, however, that resetting the Arduino doesn't reset the LCD, so we
|
||||
// can't assume that its in that state when a sketch starts (and the
|
||||
// LiquidCrystal constructor is called).
|
||||
|
||||
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
|
||||
{
|
||||
init(0, rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7);
|
||||
}
|
||||
|
||||
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
|
||||
{
|
||||
init(0, rs, 255, enable, d0, d1, d2, d3, d4, d5, d6, d7);
|
||||
}
|
||||
|
||||
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
|
||||
{
|
||||
init(1, rs, rw, enable, d0, d1, d2, d3, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
|
||||
{
|
||||
init(1, rs, 255, enable, d0, d1, d2, d3, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void LiquidCrystal::init(uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
|
||||
{
|
||||
_rs_pin = rs;
|
||||
_rw_pin = rw;
|
||||
_enable_pin = enable;
|
||||
|
||||
_data_pins[0] = d0;
|
||||
_data_pins[1] = d1;
|
||||
_data_pins[2] = d2;
|
||||
_data_pins[3] = d3;
|
||||
_data_pins[4] = d4;
|
||||
_data_pins[5] = d5;
|
||||
_data_pins[6] = d6;
|
||||
_data_pins[7] = d7;
|
||||
|
||||
if (fourbitmode)
|
||||
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
|
||||
else
|
||||
_displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;
|
||||
|
||||
begin(16, 1);
|
||||
}
|
||||
|
||||
void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
|
||||
if (lines > 1) {
|
||||
_displayfunction |= LCD_2LINE;
|
||||
}
|
||||
_numlines = lines;
|
||||
|
||||
setRowOffsets(0x00, 0x40, 0x00 + cols, 0x40 + cols);
|
||||
|
||||
// for some 1 line displays you can select a 10 pixel high font
|
||||
if ((dotsize != LCD_5x8DOTS) && (lines == 1)) {
|
||||
_displayfunction |= LCD_5x10DOTS;
|
||||
}
|
||||
|
||||
pinMode(_rs_pin, OUTPUT);
|
||||
// we can save 1 pin by not using RW. Indicate by passing 255 instead of pin#
|
||||
if (_rw_pin != 255) {
|
||||
pinMode(_rw_pin, OUTPUT);
|
||||
}
|
||||
pinMode(_enable_pin, OUTPUT);
|
||||
|
||||
// Do these once, instead of every time a character is drawn for speed reasons.
|
||||
for (int i=0; i<((_displayfunction & LCD_8BITMODE) ? 8 : 4); ++i)
|
||||
{
|
||||
pinMode(_data_pins[i], OUTPUT);
|
||||
}
|
||||
|
||||
// SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
|
||||
// according to datasheet, we need at least 40ms after power rises above 2.7V
|
||||
// before sending commands. Arduino can turn on way before 4.5V so we'll wait 50
|
||||
delayMicroseconds(50000);
|
||||
// Now we pull both RS and R/W low to begin commands
|
||||
digitalWrite(_rs_pin, LOW);
|
||||
digitalWrite(_enable_pin, LOW);
|
||||
if (_rw_pin != 255) {
|
||||
digitalWrite(_rw_pin, LOW);
|
||||
}
|
||||
|
||||
//put the LCD into 4 bit or 8 bit mode
|
||||
if (! (_displayfunction & LCD_8BITMODE)) {
|
||||
// this is according to the hitachi HD44780 datasheet
|
||||
// figure 24, pg 46
|
||||
|
||||
// we start in 8bit mode, try to set 4 bit mode
|
||||
write4bits(0x03);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// second try
|
||||
write4bits(0x03);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// third go!
|
||||
write4bits(0x03);
|
||||
delayMicroseconds(150);
|
||||
|
||||
// finally, set to 4-bit interface
|
||||
write4bits(0x02);
|
||||
} else {
|
||||
// this is according to the hitachi HD44780 datasheet
|
||||
// page 45 figure 23
|
||||
|
||||
// Send function set command sequence
|
||||
command(LCD_FUNCTIONSET | _displayfunction);
|
||||
delayMicroseconds(4500); // wait more than 4.1ms
|
||||
|
||||
// second try
|
||||
command(LCD_FUNCTIONSET | _displayfunction);
|
||||
delayMicroseconds(150);
|
||||
|
||||
// third go
|
||||
command(LCD_FUNCTIONSET | _displayfunction);
|
||||
}
|
||||
|
||||
// finally, set # lines, font size, etc.
|
||||
command(LCD_FUNCTIONSET | _displayfunction);
|
||||
|
||||
// turn the display on with no cursor or blinking default
|
||||
_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
|
||||
display();
|
||||
|
||||
// clear it off
|
||||
clear();
|
||||
|
||||
// Initialize to default text direction (for romance languages)
|
||||
_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
|
||||
// set the entry mode
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
|
||||
}
|
||||
|
||||
void LiquidCrystal::setRowOffsets(int row0, int row1, int row2, int row3)
|
||||
{
|
||||
_row_offsets[0] = row0;
|
||||
_row_offsets[1] = row1;
|
||||
_row_offsets[2] = row2;
|
||||
_row_offsets[3] = row3;
|
||||
}
|
||||
|
||||
/********** high level commands, for the user! */
|
||||
void LiquidCrystal::clear()
|
||||
{
|
||||
command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
|
||||
delayMicroseconds(2000); // this command takes a long time!
|
||||
}
|
||||
|
||||
void LiquidCrystal::home()
|
||||
{
|
||||
command(LCD_RETURNHOME); // set cursor position to zero
|
||||
delayMicroseconds(2000); // this command takes a long time!
|
||||
}
|
||||
|
||||
void LiquidCrystal::setCursor(uint8_t col, uint8_t row)
|
||||
{
|
||||
const size_t max_lines = sizeof(_row_offsets) / sizeof(*_row_offsets);
|
||||
if ( row >= max_lines ) {
|
||||
row = max_lines - 1; // we count rows starting w/0
|
||||
}
|
||||
if ( row >= _numlines ) {
|
||||
row = _numlines - 1; // we count rows starting w/0
|
||||
}
|
||||
|
||||
command(LCD_SETDDRAMADDR | (col + _row_offsets[row]));
|
||||
}
|
||||
|
||||
// Turn the display on/off (quickly)
|
||||
void LiquidCrystal::noDisplay() {
|
||||
_displaycontrol &= ~LCD_DISPLAYON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
void LiquidCrystal::display() {
|
||||
_displaycontrol |= LCD_DISPLAYON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
// Turns the underline cursor on/off
|
||||
void LiquidCrystal::noCursor() {
|
||||
_displaycontrol &= ~LCD_CURSORON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
void LiquidCrystal::cursor() {
|
||||
_displaycontrol |= LCD_CURSORON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
// Turn on and off the blinking cursor
|
||||
void LiquidCrystal::noBlink() {
|
||||
_displaycontrol &= ~LCD_BLINKON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
void LiquidCrystal::blink() {
|
||||
_displaycontrol |= LCD_BLINKON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
// These commands scroll the display without changing the RAM
|
||||
void LiquidCrystal::scrollDisplayLeft(void) {
|
||||
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
|
||||
}
|
||||
void LiquidCrystal::scrollDisplayRight(void) {
|
||||
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
|
||||
}
|
||||
|
||||
// This is for text that flows Left to Right
|
||||
void LiquidCrystal::leftToRight(void) {
|
||||
_displaymode |= LCD_ENTRYLEFT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// This is for text that flows Right to Left
|
||||
void LiquidCrystal::rightToLeft(void) {
|
||||
_displaymode &= ~LCD_ENTRYLEFT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// This will 'right justify' text from the cursor
|
||||
void LiquidCrystal::autoscroll(void) {
|
||||
_displaymode |= LCD_ENTRYSHIFTINCREMENT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// This will 'left justify' text from the cursor
|
||||
void LiquidCrystal::noAutoscroll(void) {
|
||||
_displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// Allows us to fill the first 8 CGRAM locations
|
||||
// with custom characters
|
||||
void LiquidCrystal::createChar(uint8_t location, uint8_t charmap[]) {
|
||||
location &= 0x7; // we only have 8 locations 0-7
|
||||
command(LCD_SETCGRAMADDR | (location << 3));
|
||||
for (int i=0; i<8; i++) {
|
||||
write(charmap[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*********** mid level commands, for sending data/cmds */
|
||||
|
||||
inline void LiquidCrystal::command(uint8_t value) {
|
||||
send(value, LOW);
|
||||
}
|
||||
|
||||
inline size_t LiquidCrystal::write(uint8_t value) {
|
||||
send(value, HIGH);
|
||||
return 1; // assume sucess
|
||||
}
|
||||
|
||||
/************ low level data pushing commands **********/
|
||||
|
||||
// write either command or data, with automatic 4/8-bit selection
|
||||
void LiquidCrystal::send(uint8_t value, uint8_t mode) {
|
||||
digitalWrite(_rs_pin, mode);
|
||||
|
||||
// if there is a RW pin indicated, set it low to Write
|
||||
if (_rw_pin != 255) {
|
||||
digitalWrite(_rw_pin, LOW);
|
||||
}
|
||||
|
||||
if (_displayfunction & LCD_8BITMODE) {
|
||||
write8bits(value);
|
||||
} else {
|
||||
write4bits(value>>4);
|
||||
write4bits(value);
|
||||
}
|
||||
}
|
||||
|
||||
void LiquidCrystal::pulseEnable(void) {
|
||||
digitalWrite(_enable_pin, LOW);
|
||||
delayMicroseconds(1);
|
||||
digitalWrite(_enable_pin, HIGH);
|
||||
delayMicroseconds(1); // enable pulse must be >450ns
|
||||
digitalWrite(_enable_pin, LOW);
|
||||
delayMicroseconds(100); // commands need > 37us to settle
|
||||
}
|
||||
|
||||
void LiquidCrystal::write4bits(uint8_t value) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
digitalWrite(_data_pins[i], (value >> i) & 0x01);
|
||||
}
|
||||
|
||||
pulseEnable();
|
||||
}
|
||||
|
||||
void LiquidCrystal::write8bits(uint8_t value) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
digitalWrite(_data_pins[i], (value >> i) & 0x01);
|
||||
}
|
||||
|
||||
pulseEnable();
|
||||
}
|
@ -0,0 +1,177 @@
|
||||
/*
|
||||
|
||||
u8g_bitmap.c
|
||||
|
||||
Universal 8bit Graphics Library
|
||||
|
||||
Copyright (c) 2011, olikraus@gmail.com
|
||||
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 "u8g.h"
|
||||
|
||||
void u8g_DrawHBitmap(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, u8g_uint_t cnt, const uint8_t *bitmap)
|
||||
{
|
||||
while( cnt > 0 )
|
||||
{
|
||||
u8g_Draw8Pixel(u8g, x, y, 0, *bitmap);
|
||||
bitmap++;
|
||||
cnt--;
|
||||
x+=8;
|
||||
}
|
||||
}
|
||||
|
||||
void u8g_DrawBitmap(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, u8g_uint_t cnt, u8g_uint_t h, const uint8_t *bitmap)
|
||||
{
|
||||
if ( u8g_IsBBXIntersection(u8g, x, y, cnt*8, h) == 0 )
|
||||
return;
|
||||
while( h > 0 )
|
||||
{
|
||||
u8g_DrawHBitmap(u8g, x, y, cnt, bitmap);
|
||||
bitmap += cnt;
|
||||
y++;
|
||||
h--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void u8g_DrawHBitmapP(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, u8g_uint_t cnt, const u8g_pgm_uint8_t *bitmap)
|
||||
{
|
||||
while( cnt > 0 )
|
||||
{
|
||||
u8g_Draw8Pixel(u8g, x, y, 0, u8g_pgm_read(bitmap));
|
||||
bitmap++;
|
||||
cnt--;
|
||||
x+=8;
|
||||
}
|
||||
}
|
||||
|
||||
void u8g_DrawBitmapP(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, u8g_uint_t cnt, u8g_uint_t h, const u8g_pgm_uint8_t *bitmap)
|
||||
{
|
||||
if ( u8g_IsBBXIntersection(u8g, x, y, cnt*8, h) == 0 )
|
||||
return;
|
||||
while( h > 0 )
|
||||
{
|
||||
u8g_DrawHBitmapP(u8g, x, y, cnt, bitmap);
|
||||
bitmap += cnt;
|
||||
y++;
|
||||
h--;
|
||||
}
|
||||
}
|
||||
|
||||
/*=========================================================================*/
|
||||
|
||||
static void u8g_DrawHXBM(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, u8g_uint_t w, const uint8_t *bitmap)
|
||||
{
|
||||
uint8_t d;
|
||||
x+=7;
|
||||
while( w >= 8 )
|
||||
{
|
||||
u8g_Draw8Pixel(u8g, x, y, 2, *bitmap);
|
||||
bitmap++;
|
||||
w-= 8;
|
||||
x+=8;
|
||||
}
|
||||
if ( w > 0 )
|
||||
{
|
||||
d = *bitmap;
|
||||
x -= 7;
|
||||
do
|
||||
{
|
||||
if ( d & 1 )
|
||||
u8g_DrawPixel(u8g, x, y);
|
||||
x++;
|
||||
w--;
|
||||
d >>= 1;
|
||||
} while ( w > 0 );
|
||||
}
|
||||
}
|
||||
|
||||
void u8g_DrawXBM(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, u8g_uint_t w, u8g_uint_t h, const uint8_t *bitmap)
|
||||
{
|
||||
u8g_uint_t b;
|
||||
b = w;
|
||||
b += 7;
|
||||
b >>= 3;
|
||||
|
||||
if ( u8g_IsBBXIntersection(u8g, x, y, w, h) == 0 )
|
||||
return;
|
||||
|
||||
while( h > 0 )
|
||||
{
|
||||
u8g_DrawHXBM(u8g, x, y, w, bitmap);
|
||||
bitmap += b;
|
||||
y++;
|
||||
h--;
|
||||
}
|
||||
}
|
||||
|
||||
static void u8g_DrawHXBMP(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, u8g_uint_t w, const u8g_pgm_uint8_t *bitmap)
|
||||
{
|
||||
uint8_t d;
|
||||
x+=7;
|
||||
while( w >= 8 )
|
||||
{
|
||||
u8g_Draw8Pixel(u8g, x, y, 2, u8g_pgm_read(bitmap));
|
||||
bitmap++;
|
||||
w-= 8;
|
||||
x+=8;
|
||||
}
|
||||
if ( w > 0 )
|
||||
{
|
||||
d = u8g_pgm_read(bitmap);
|
||||
x -= 7;
|
||||
do
|
||||
{
|
||||
if ( d & 1 )
|
||||
u8g_DrawPixel(u8g, x, y);
|
||||
x++;
|
||||
w--;
|
||||
d >>= 1;
|
||||
} while ( w > 0 );
|
||||
}
|
||||
}
|
||||
|
||||
void u8g_DrawXBMP(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, u8g_uint_t w, u8g_uint_t h, const u8g_pgm_uint8_t *bitmap)
|
||||
{
|
||||
u8g_uint_t b;
|
||||
b = w;
|
||||
b += 7;
|
||||
b >>= 3;
|
||||
|
||||
if ( u8g_IsBBXIntersection(u8g, x, y, w, h) == 0 )
|
||||
return;
|
||||
while( h > 0 )
|
||||
{
|
||||
u8g_DrawHXBMP(u8g, x, y, w, bitmap);
|
||||
bitmap += b;
|
||||
y++;
|
||||
h--;
|
||||
}
|
||||
}
|
@ -0,0 +1,156 @@
|
||||
/*
|
||||
|
||||
u8g_clip.c
|
||||
|
||||
procedures for clipping
|
||||
taken over from procs in u8g_pb.c
|
||||
|
||||
Universal 8bit Graphics Library
|
||||
|
||||
Copyright (c) 2012, olikraus@gmail.com
|
||||
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.
|
||||
|
||||
Notes
|
||||
|
||||
This is one of the most critical parts of u8glib. It must be fast, but still reliable.
|
||||
Based on the intersection program (see tools folder), there is minimized version of
|
||||
the condition for the intersaction test:
|
||||
minimized version
|
||||
---1----0 1 b1 <= a2 && b1 > b2
|
||||
-----1--0 1 b2 >= a1 && b1 > b2
|
||||
---1-1--- 1 b1 <= a2 && b2 >= a1
|
||||
It includes the assumption, that a1 <= a2 is always true (correct, because
|
||||
a1, a2 are the page dimensions.
|
||||
|
||||
The direct implementation of the above result is done in:
|
||||
uint8_t u8g_is_intersection_boolean(u8g_uint_t a0, u8g_uint_t a1, u8g_uint_t v0, u8g_uint_t v1)
|
||||
However, this is slower than a decision tree version:
|
||||
static uint8_t u8g_is_intersection_decision_tree(u8g_uint_t a0, u8g_uint_t a1, u8g_uint_t v0, u8g_uint_t v1)
|
||||
Also suprising is, that the macro implementation is slower than the inlined version.
|
||||
|
||||
The decision tree is based on the expansion of the truth table.
|
||||
|
||||
*/
|
||||
|
||||
#include "u8g.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define U8G_ALWAYS_INLINE __inline__ __attribute__((always_inline))
|
||||
#else
|
||||
#define U8G_ALWAYS_INLINE
|
||||
#endif
|
||||
|
||||
/*
|
||||
intersection assumptions:
|
||||
a1 <= a2 is always true
|
||||
|
||||
minimized version
|
||||
---1----0 1 b1 <= a2 && b1 > b2
|
||||
-----1--0 1 b2 >= a1 && b1 > b2
|
||||
---1-1--- 1 b1 <= a2 && b2 >= a1
|
||||
*/
|
||||
|
||||
#ifdef OLD_CODE_WHICH_IS_TOO_SLOW
|
||||
static uint8_t u8g_is_intersection_boolean(u8g_uint_t a0, u8g_uint_t a1, u8g_uint_t v0, u8g_uint_t v1)
|
||||
{
|
||||
uint8_t c1, c2, c3, tmp;
|
||||
c1 = v0 <= a1;
|
||||
c2 = v1 >= a0;
|
||||
c3 = v0 > v1;
|
||||
|
||||
tmp = c1;
|
||||
c1 &= c2;
|
||||
c2 &= c3;
|
||||
c3 &= tmp;
|
||||
c1 |= c2;
|
||||
c1 |= c3;
|
||||
return c1 & 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define U8G_IS_INTERSECTION_MACRO(a0,a1,v0,v1) ((uint8_t)( (v0) <= (a1) ) ? ( ( (v1) >= (a0) ) ? ( 1 ) : ( (v0) > (v1) ) ) : ( ( (v1) >= (a0) ) ? ( (v0) > (v1) ) : ( 0 ) ))
|
||||
|
||||
//static uint8_t u8g_is_intersection_decision_tree(u8g_uint_t a0, u8g_uint_t a1, u8g_uint_t v0, u8g_uint_t v1) U8G_ALWAYS_INLINE;
|
||||
static uint8_t U8G_ALWAYS_INLINE u8g_is_intersection_decision_tree(u8g_uint_t a0, u8g_uint_t a1, u8g_uint_t v0, u8g_uint_t v1)
|
||||
{
|
||||
/* surprisingly the macro leads to larger code */
|
||||
/* return U8G_IS_INTERSECTION_MACRO(a0,a1,v0,v1); */
|
||||
if ( v0 <= a1 )
|
||||
{
|
||||
if ( v1 >= a0 )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( v0 > v1 )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( v1 >= a0 )
|
||||
{
|
||||
if ( v0 > v1 )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t u8g_IsBBXIntersection(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, u8g_uint_t w, u8g_uint_t h)
|
||||
{
|
||||
register u8g_uint_t tmp;
|
||||
tmp = y;
|
||||
tmp += h;
|
||||
tmp--;
|
||||
if ( u8g_is_intersection_decision_tree(u8g->current_page.y0, u8g->current_page.y1, y, tmp) == 0 )
|
||||
return 0;
|
||||
|
||||
tmp = x;
|
||||
tmp += w;
|
||||
tmp--;
|
||||
return u8g_is_intersection_decision_tree(u8g->current_page.x0, u8g->current_page.x1, x, tmp);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
|
||||
u8g_com_null.c
|
||||
|
||||
communication null device
|
||||
|
||||
Universal 8bit Graphics Library
|
||||
|
||||
Copyright (c) 2011, olikraus@gmail.com
|
||||
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 "u8g.h"
|
||||
|
||||
uint8_t u8g_com_null_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
|
||||
{
|
||||
switch(msg)
|
||||
{
|
||||
case U8G_COM_MSG_INIT:
|
||||
break;
|
||||
case U8G_COM_MSG_STOP:
|
||||
break;
|
||||
|
||||
|
||||
case U8G_COM_MSG_CHIP_SELECT:
|
||||
/* arg_val contains the chip number, which should be enabled */
|
||||
break;
|
||||
|
||||
|
||||
case U8G_COM_MSG_WRITE_BYTE:
|
||||
break;
|
||||
case U8G_COM_MSG_WRITE_SEQ:
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -0,0 +1,240 @@
|
||||
/*
|
||||
|
||||
u8g_delay.c
|
||||
|
||||
Universal 8bit Graphics Library
|
||||
|
||||
Copyright (c) 2011, olikraus@gmail.com
|
||||
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.
|
||||
|
||||
|
||||
void u8g_Delay(uint16_t val) Delay by "val" milliseconds
|
||||
void u8g_MicroDelay(void) Delay be one microsecond
|
||||
void u8g_10MicroDelay(void) Delay by 10 microseconds
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "u8g.h"
|
||||
|
||||
/*==== Part 1: Derive suitable delay procedure ====*/
|
||||
|
||||
#if defined(ARDUINO)
|
||||
|
||||
# if ARDUINO < 100
|
||||
# include <WProgram.h>
|
||||
# else
|
||||
# include <Arduino.h>
|
||||
# endif
|
||||
|
||||
# if defined(__AVR__)
|
||||
# define USE_AVR_DELAY
|
||||
# elif defined(__PIC32MX)
|
||||
# define USE_PIC32_DELAY
|
||||
# elif defined(__arm__) /* Arduino Due */
|
||||
# define USE_ARDUINO_DELAY
|
||||
# else
|
||||
# define USE_ARDUINO_DELAY
|
||||
# endif
|
||||
#elif defined(__AVR__)
|
||||
# define USE_AVR_DELAY
|
||||
#elif defined(__18CXX)
|
||||
# define USE_PIC18_DELAY
|
||||
#elif defined(__arm__)
|
||||
/* do not define anything, all procedures are expected to be defined outside u8glib */
|
||||
|
||||
/*
|
||||
void u8g_Delay(uint16_t val);
|
||||
void u8g_MicroDelay(void);
|
||||
void u8g_10MicroDelay(void);
|
||||
*/
|
||||
|
||||
#else
|
||||
# define USE_DUMMY_DELAY
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*==== Part 2: Definition of the delay procedures ====*/
|
||||
|
||||
/*== AVR Delay ==*/
|
||||
|
||||
#if defined(USE_AVR_DELAY)
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/io.h>
|
||||
#include <util/delay.h>
|
||||
|
||||
/*
|
||||
Delay by the provided number of milliseconds.
|
||||
Thus, a 16 bit value will allow a delay of 0..65 seconds
|
||||
Makes use of the _delay_loop_2
|
||||
|
||||
_delay_loop_2 will do a delay of n * 4 prozessor cycles.
|
||||
with f = F_CPU cycles per second,
|
||||
n = f / (1000 * 4 )
|
||||
with f = 16000000 the result is 4000
|
||||
with f = 1000000 the result is 250
|
||||
|
||||
the millisec loop, gcc requires the following overhead:
|
||||
- movev 1
|
||||
- subwi 2x2
|
||||
- bne i 2
|
||||
==> 7 cycles
|
||||
==> must be devided by 4, rounded up 7/4 = 2
|
||||
*/
|
||||
void u8g_Delay(uint16_t val)
|
||||
{
|
||||
/* old version did a call to the arduino lib: delay(val); */
|
||||
while( val != 0 )
|
||||
{
|
||||
_delay_loop_2( (F_CPU / 4000 ) -2);
|
||||
val--;
|
||||
}
|
||||
}
|
||||
|
||||
/* delay by one micro second */
|
||||
void u8g_MicroDelay(void)
|
||||
{
|
||||
#if (F_CPU / 4000000 ) > 0
|
||||
_delay_loop_2( (F_CPU / 4000000 ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
/* delay by 10 micro seconds */
|
||||
void u8g_10MicroDelay(void)
|
||||
{
|
||||
#if (F_CPU / 400000 ) > 0
|
||||
_delay_loop_2( (F_CPU / 400000 ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*== Delay for PIC18 (not tested) ==*/
|
||||
|
||||
#if defined(USE_PIC18_DELAY)
|
||||
#include <delays.h>
|
||||
#define GetSystemClock() (64000000ul) // Hz
|
||||
#define GetInstructionClock() (GetSystemClock()/4)
|
||||
|
||||
void u8g_Delay(uint16_t val)
|
||||
{/*
|
||||
unsigned int _iTemp = (val);
|
||||
while(_iTemp--)
|
||||
Delay1KTCYx((GetInstructionClock()+999999)/1000000);
|
||||
*/
|
||||
}
|
||||
void u8g_MicroDelay(void)
|
||||
{
|
||||
/* not implemented */
|
||||
}
|
||||
void u8g_10MicroDelay(void)
|
||||
{
|
||||
/* not implemented */
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*== Arduino Delay ==*/
|
||||
#if defined(USE_ARDUINO_DELAY)
|
||||
void u8g_Delay(uint16_t val)
|
||||
{
|
||||
#if defined(__arm__)
|
||||
delayMicroseconds((uint32_t)val*(uint32_t)1000);
|
||||
#else
|
||||
delay(val);
|
||||
#endif
|
||||
}
|
||||
void u8g_MicroDelay(void)
|
||||
{
|
||||
delayMicroseconds(1);
|
||||
}
|
||||
void u8g_10MicroDelay(void)
|
||||
{
|
||||
delayMicroseconds(10);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(USE_PIC32_DELAY)
|
||||
/*
|
||||
Assume chipkit here with F_CPU correctly defined
|
||||
The problem was, that u8g_Delay() is called within the constructor.
|
||||
It seems that the chipkit is not fully setup at this time, so a
|
||||
call to delay() will not work. So here is my own implementation.
|
||||
|
||||
*/
|
||||
#define CPU_COUNTS_PER_SECOND (F_CPU/2UL)
|
||||
#define TICKS_PER_MILLISECOND (CPU_COUNTS_PER_SECOND/1000UL)
|
||||
#include "plib.h"
|
||||
void u8g_Delay(uint16_t val)
|
||||
{
|
||||
uint32_t d;
|
||||
uint32_t s;
|
||||
d = val;
|
||||
d *= TICKS_PER_MILLISECOND;
|
||||
s = ReadCoreTimer();
|
||||
while ( (uint32_t)(ReadCoreTimer() - s) < d )
|
||||
;
|
||||
}
|
||||
|
||||
void u8g_MicroDelay(void)
|
||||
{
|
||||
uint32_t d;
|
||||
uint32_t s;
|
||||
d = TICKS_PER_MILLISECOND/1000;
|
||||
s = ReadCoreTimer();
|
||||
while ( (uint32_t)(ReadCoreTimer() - s) < d )
|
||||
;
|
||||
}
|
||||
|
||||
void u8g_10MicroDelay(void)
|
||||
{
|
||||
uint32_t d;
|
||||
uint32_t s;
|
||||
d = TICKS_PER_MILLISECOND/100;
|
||||
s = ReadCoreTimer();
|
||||
while ( (uint32_t)(ReadCoreTimer() - s) < d )
|
||||
;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*== Any other systems: Dummy Delay ==*/
|
||||
#if defined(USE_DUMMY_DELAY)
|
||||
void u8g_Delay(uint16_t val)
|
||||
{
|
||||
/* do not know how to delay... */
|
||||
}
|
||||
void u8g_MicroDelay(void)
|
||||
{
|
||||
}
|
||||
void u8g_10MicroDelay(void)
|
||||
{
|
||||
}
|
||||
#endif
|
@ -0,0 +1,1501 @@
|
||||
/*
|
||||
|
||||
u8g_font.c
|
||||
|
||||
U8G Font High Level Interface
|
||||
|
||||
Universal 8bit Graphics Library
|
||||
|
||||
Copyright (c) 2011, olikraus@gmail.com
|
||||
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 "u8g.h"
|
||||
|
||||
/* font api */
|
||||
|
||||
/* pointer to the start adress of the glyph, points to progmem area */
|
||||
typedef void * u8g_glyph_t;
|
||||
|
||||
/* size of the font data structure, there is no struct or class... */
|
||||
#define U8G_FONT_DATA_STRUCT_SIZE 17
|
||||
|
||||
/*
|
||||
... instead the fields of the font data structure are accessed directly by offset
|
||||
font information
|
||||
offset
|
||||
0 font format
|
||||
1 FONTBOUNDINGBOX width unsigned
|
||||
2 FONTBOUNDINGBOX height unsigned
|
||||
3 FONTBOUNDINGBOX x-offset signed
|
||||
4 FONTBOUNDINGBOX y-offset signed
|
||||
5 capital A height unsigned
|
||||
6 start 'A'
|
||||
8 start 'a'
|
||||
10 encoding start
|
||||
11 encoding end
|
||||
12 descent 'g' negative: below baseline
|
||||
13 font max ascent
|
||||
14 font min decent negative: below baseline
|
||||
15 font xascent
|
||||
16 font xdecent negative: below baseline
|
||||
|
||||
*/
|
||||
|
||||
/* use case: What is the width and the height of the minimal box into which string s fints? */
|
||||
void u8g_font_GetStrSize(const void *font, const char *s, u8g_uint_t *width, u8g_uint_t *height);
|
||||
void u8g_font_GetStrSizeP(const void *font, const char *s, u8g_uint_t *width, u8g_uint_t *height);
|
||||
|
||||
/* use case: lower left edge of a minimal box is known, what is the correct x, y position for the string draw procedure */
|
||||
void u8g_font_AdjustXYToDraw(const void *font, const char *s, u8g_uint_t *x, u8g_uint_t *y);
|
||||
void u8g_font_AdjustXYToDrawP(const void *font, const char *s, u8g_uint_t *x, u8g_uint_t *y);
|
||||
|
||||
/* use case: Baseline origin known, return minimal box */
|
||||
void u8g_font_GetStrMinBox(u8g_t *u8g, const void *font, const char *s, u8g_uint_t *x, u8g_uint_t *y, u8g_uint_t *width, u8g_uint_t *height);
|
||||
|
||||
/* procedures */
|
||||
|
||||
/*========================================================================*/
|
||||
/* low level byte and word access */
|
||||
|
||||
/* removed NOINLINE, because it leads to smaller code, might also be faster */
|
||||
//static uint8_t u8g_font_get_byte(const u8g_fntpgm_uint8_t *font, uint8_t offset) U8G_NOINLINE;
|
||||
static uint8_t u8g_font_get_byte(const u8g_fntpgm_uint8_t *font, uint8_t offset)
|
||||
{
|
||||
font += offset;
|
||||
return u8g_pgm_read( (u8g_pgm_uint8_t *)font );
|
||||
}
|
||||
|
||||
static uint16_t u8g_font_get_word(const u8g_fntpgm_uint8_t *font, uint8_t offset) U8G_NOINLINE;
|
||||
static uint16_t u8g_font_get_word(const u8g_fntpgm_uint8_t *font, uint8_t offset)
|
||||
{
|
||||
uint16_t pos;
|
||||
font += offset;
|
||||
pos = u8g_pgm_read( (u8g_pgm_uint8_t *)font );
|
||||
font++;
|
||||
pos <<= 8;
|
||||
pos += u8g_pgm_read( (u8g_pgm_uint8_t *)font);
|
||||
return pos;
|
||||
}
|
||||
|
||||
/*========================================================================*/
|
||||
/* direct access on the font */
|
||||
|
||||
static uint8_t u8g_font_GetFormat(const u8g_fntpgm_uint8_t *font) U8G_NOINLINE;
|
||||
static uint8_t u8g_font_GetFormat(const u8g_fntpgm_uint8_t *font)
|
||||
{
|
||||
return u8g_font_get_byte(font, 0);
|
||||
}
|
||||
|
||||
static uint8_t u8g_font_GetFontGlyphStructureSize(const u8g_fntpgm_uint8_t *font) U8G_NOINLINE;
|
||||
static uint8_t u8g_font_GetFontGlyphStructureSize(const u8g_fntpgm_uint8_t *font)
|
||||
{
|
||||
switch(u8g_font_GetFormat(font))
|
||||
{
|
||||
case 0: return 6;
|
||||
case 1: return 3;
|
||||
case 2: return 6;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
static uint8_t u8g_font_GetBBXWidth(const void *font)
|
||||
{
|
||||
return u8g_font_get_byte(font, 1);
|
||||
}
|
||||
|
||||
static uint8_t u8g_font_GetBBXHeight(const void *font)
|
||||
{
|
||||
return u8g_font_get_byte(font, 2);
|
||||
}
|
||||
|
||||
static int8_t u8g_font_GetBBXOffX(const void *font)
|
||||
{
|
||||
return u8g_font_get_byte(font, 3);
|
||||
}
|
||||
|
||||
static int8_t u8g_font_GetBBXOffY(const void *font)
|
||||
{
|
||||
return u8g_font_get_byte(font, 4);
|
||||
}
|
||||
|
||||
uint8_t u8g_font_GetCapitalAHeight(const void *font)
|
||||
{
|
||||
return u8g_font_get_byte(font, 5);
|
||||
}
|
||||
|
||||
uint16_t u8g_font_GetEncoding65Pos(const void *font) U8G_NOINLINE;
|
||||
uint16_t u8g_font_GetEncoding65Pos(const void *font)
|
||||
{
|
||||
return u8g_font_get_word(font, 6);
|
||||
}
|
||||
|
||||
uint16_t u8g_font_GetEncoding97Pos(const void *font) U8G_NOINLINE;
|
||||
uint16_t u8g_font_GetEncoding97Pos(const void *font)
|
||||
{
|
||||
return u8g_font_get_word(font, 8);
|
||||
}
|
||||
|
||||
uint8_t u8g_font_GetFontStartEncoding(const void *font)
|
||||
{
|
||||
return u8g_font_get_byte(font, 10);
|
||||
}
|
||||
|
||||
uint8_t u8g_font_GetFontEndEncoding(const void *font)
|
||||
{
|
||||
return u8g_font_get_byte(font, 11);
|
||||
}
|
||||
|
||||
int8_t u8g_font_GetLowerGDescent(const void *font)
|
||||
{
|
||||
return u8g_font_get_byte(font, 12);
|
||||
}
|
||||
|
||||
int8_t u8g_font_GetFontAscent(const void *font)
|
||||
{
|
||||
return u8g_font_get_byte(font, 13);
|
||||
}
|
||||
|
||||
int8_t u8g_font_GetFontDescent(const void *font)
|
||||
{
|
||||
return u8g_font_get_byte(font, 14);
|
||||
}
|
||||
|
||||
int8_t u8g_font_GetFontXAscent(const void *font)
|
||||
{
|
||||
return u8g_font_get_byte(font, 15);
|
||||
}
|
||||
|
||||
int8_t u8g_font_GetFontXDescent(const void *font)
|
||||
{
|
||||
return u8g_font_get_byte(font, 16);
|
||||
}
|
||||
|
||||
|
||||
/* return the data start for a font and the glyph pointer */
|
||||
static uint8_t *u8g_font_GetGlyphDataStart(const void *font, u8g_glyph_t g)
|
||||
{
|
||||
return ((u8g_fntpgm_uint8_t *)g) + u8g_font_GetFontGlyphStructureSize(font);
|
||||
}
|
||||
|
||||
/* calculate the overall length of the font, only used to create the picture for the google wiki */
|
||||
size_t u8g_font_GetSize(const void *font)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)(font);
|
||||
uint8_t font_format = u8g_font_GetFormat(font);
|
||||
uint8_t data_structure_size = u8g_font_GetFontGlyphStructureSize(font);
|
||||
uint8_t start, end;
|
||||
uint8_t i;
|
||||
uint8_t mask = 255;
|
||||
|
||||
start = u8g_font_GetFontStartEncoding(font);
|
||||
end = u8g_font_GetFontEndEncoding(font);
|
||||
|
||||
if ( font_format == 1 )
|
||||
mask = 15;
|
||||
|
||||
p += U8G_FONT_DATA_STRUCT_SIZE; /* skip font general information */
|
||||
|
||||
i = start;
|
||||
for(;;)
|
||||
{
|
||||
if ( u8g_pgm_read((u8g_pgm_uint8_t *)(p)) == 255 )
|
||||
{
|
||||
p += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
p += u8g_pgm_read( ((u8g_pgm_uint8_t *)(p)) + 2 ) & mask;
|
||||
p += data_structure_size;
|
||||
}
|
||||
if ( i == end )
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
|
||||
return p - (uint8_t *)font;
|
||||
}
|
||||
|
||||
/*========================================================================*/
|
||||
/* u8g interface, font access */
|
||||
|
||||
uint8_t u8g_GetFontBBXWidth(u8g_t *u8g)
|
||||
{
|
||||
return u8g_font_GetBBXWidth(u8g->font);
|
||||
}
|
||||
|
||||
uint8_t u8g_GetFontBBXHeight(u8g_t *u8g)
|
||||
{
|
||||
return u8g_font_GetBBXHeight(u8g->font);
|
||||
}
|
||||
|
||||
int8_t u8g_GetFontBBXOffX(u8g_t *u8g) U8G_NOINLINE;
|
||||
int8_t u8g_GetFontBBXOffX(u8g_t *u8g)
|
||||
{
|
||||
return u8g_font_GetBBXOffX(u8g->font);
|
||||
}
|
||||
|
||||
int8_t u8g_GetFontBBXOffY(u8g_t *u8g) U8G_NOINLINE;
|
||||
int8_t u8g_GetFontBBXOffY(u8g_t *u8g)
|
||||
{
|
||||
return u8g_font_GetBBXOffY(u8g->font);
|
||||
}
|
||||
|
||||
uint8_t u8g_GetFontCapitalAHeight(u8g_t *u8g) U8G_NOINLINE;
|
||||
uint8_t u8g_GetFontCapitalAHeight(u8g_t *u8g)
|
||||
{
|
||||
return u8g_font_GetCapitalAHeight(u8g->font);
|
||||
}
|
||||
|
||||
/*========================================================================*/
|
||||
/* glyph handling */
|
||||
|
||||
static void u8g_CopyGlyphDataToCache(u8g_t *u8g, u8g_glyph_t g)
|
||||
{
|
||||
uint8_t tmp;
|
||||
switch( u8g_font_GetFormat(u8g->font) )
|
||||
{
|
||||
case 0:
|
||||
case 2:
|
||||
/*
|
||||
format 0
|
||||
glyph information
|
||||
offset
|
||||
0 BBX width unsigned
|
||||
1 BBX height unsigned
|
||||
2 data size unsigned (BBX width + 7)/8 * BBX height
|
||||
3 DWIDTH signed
|
||||
4 BBX xoffset signed
|
||||
5 BBX yoffset signed
|
||||
byte 0 == 255 indicates empty glyph
|
||||
*/
|
||||
u8g->glyph_width = u8g_pgm_read( ((u8g_pgm_uint8_t *)g) + 0 );
|
||||
u8g->glyph_height = u8g_pgm_read( ((u8g_pgm_uint8_t *)g) + 1 );
|
||||
u8g->glyph_dx = u8g_pgm_read( ((u8g_pgm_uint8_t *)g) + 3 );
|
||||
u8g->glyph_x = u8g_pgm_read( ((u8g_pgm_uint8_t *)g) + 4 );
|
||||
u8g->glyph_y = u8g_pgm_read( ((u8g_pgm_uint8_t *)g) + 5 );
|
||||
break;
|
||||
case 1:
|
||||
default:
|
||||
/*
|
||||
format 1
|
||||
0 BBX xoffset signed --> upper 4 Bit
|
||||
0 BBX yoffset signed --> lower 4 Bit
|
||||
1 BBX width unsigned --> upper 4 Bit
|
||||
1 BBX height unsigned --> lower 4 Bit
|
||||
2 data size unsigned -(BBX width + 7)/8 * BBX height --> lower 4 Bit
|
||||
2 DWIDTH signed --> upper 4 Bit
|
||||
byte 0 == 255 indicates empty glyph
|
||||
*/
|
||||
|
||||
tmp = u8g_pgm_read( ((u8g_pgm_uint8_t *)g) + 0 );
|
||||
u8g->glyph_y = tmp & 15;
|
||||
u8g->glyph_y-=2;
|
||||
tmp >>= 4;
|
||||
u8g->glyph_x = tmp;
|
||||
|
||||
tmp = u8g_pgm_read( ((u8g_pgm_uint8_t *)g) + 1 );
|
||||
u8g->glyph_height = tmp & 15;
|
||||
tmp >>= 4;
|
||||
u8g->glyph_width = tmp;
|
||||
|
||||
tmp = u8g_pgm_read( ((u8g_pgm_uint8_t *)g) + 2 );
|
||||
tmp >>= 4;
|
||||
u8g->glyph_dx = tmp;
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//void u8g_FillEmptyGlyphCache(u8g_t *u8g) U8G_NOINLINE;
|
||||
static void u8g_FillEmptyGlyphCache(u8g_t *u8g)
|
||||
{
|
||||
u8g->glyph_dx = 0;
|
||||
u8g->glyph_width = 0;
|
||||
u8g->glyph_height = 0;
|
||||
u8g->glyph_x = 0;
|
||||
u8g->glyph_y = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Find (with some speed optimization) and return a pointer to the glyph data structure
|
||||
Also uncompress (format 1) and copy the content of the data structure to the u8g structure
|
||||
*/
|
||||
u8g_glyph_t u8g_GetGlyph(u8g_t *u8g, uint8_t requested_encoding)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)(u8g->font);
|
||||
uint8_t font_format = u8g_font_GetFormat(u8g->font);
|
||||
uint8_t data_structure_size = u8g_font_GetFontGlyphStructureSize(u8g->font);
|
||||
uint8_t start, end;
|
||||
uint16_t pos;
|
||||
uint8_t i;
|
||||
uint8_t mask = 255;
|
||||
|
||||
if ( font_format == 1 )
|
||||
mask = 15;
|
||||
|
||||
start = u8g_font_GetFontStartEncoding(u8g->font);
|
||||
end = u8g_font_GetFontEndEncoding(u8g->font);
|
||||
|
||||
pos = u8g_font_GetEncoding97Pos(u8g->font);
|
||||
if ( requested_encoding >= 97 && pos > 0 )
|
||||
{
|
||||
p+= pos;
|
||||
start = 97;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = u8g_font_GetEncoding65Pos(u8g->font);
|
||||
if ( requested_encoding >= 65 && pos > 0 )
|
||||
{
|
||||
p+= pos;
|
||||
start = 65;
|
||||
}
|
||||
else
|
||||
p += U8G_FONT_DATA_STRUCT_SIZE; /* skip font general information */
|
||||
}
|
||||
|
||||
if ( requested_encoding > end )
|
||||
{
|
||||
u8g_FillEmptyGlyphCache(u8g);
|
||||
return NULL; /* not found */
|
||||
}
|
||||
|
||||
i = start;
|
||||
if ( i <= end )
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
if ( u8g_pgm_read((u8g_pgm_uint8_t *)(p)) == 255 )
|
||||
{
|
||||
p += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( i == requested_encoding )
|
||||
{
|
||||
u8g_CopyGlyphDataToCache(u8g, p);
|
||||
return p;
|
||||
}
|
||||
p += u8g_pgm_read( ((u8g_pgm_uint8_t *)(p)) + 2 ) & mask;
|
||||
p += data_structure_size;
|
||||
}
|
||||
if ( i == end )
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
u8g_FillEmptyGlyphCache(u8g);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t u8g_IsGlyph(u8g_t *u8g, uint8_t requested_encoding)
|
||||
{
|
||||
if ( u8g_GetGlyph(u8g, requested_encoding) != NULL )
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t u8g_GetGlyphDeltaX(u8g_t *u8g, uint8_t requested_encoding)
|
||||
{
|
||||
if ( u8g_GetGlyph(u8g, requested_encoding) == NULL )
|
||||
return 0; /* should never happen, so return something */
|
||||
return u8g->glyph_dx;
|
||||
}
|
||||
|
||||
|
||||
/*========================================================================*/
|
||||
/* glyph drawing procedures */
|
||||
|
||||
#ifdef OBSOLETE
|
||||
/*
|
||||
Draw a glyph
|
||||
x,y: left baseline position of the glyph
|
||||
*/
|
||||
int8_t u8g_DrawGlyphDir(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, uint8_t dir, uint8_t encoding)
|
||||
{
|
||||
u8g_glyph_t g;
|
||||
uint8_t w, h, i, j;
|
||||
const u8g_pgm_uint8_t *data;
|
||||
uint8_t bytes_per_line;
|
||||
u8g_uint_t ix, iy;
|
||||
|
||||
g = u8g_GetGlyph(u8g, encoding);
|
||||
if ( g == NULL )
|
||||
return 0;
|
||||
w = u8g->glyph_width;
|
||||
h = u8g->glyph_height;
|
||||
|
||||
bytes_per_line = w;
|
||||
bytes_per_line += 7;
|
||||
bytes_per_line /= 8;
|
||||
|
||||
data = u8g_font_GetGlyphDataStart(u8g->font, g);
|
||||
|
||||
switch(dir)
|
||||
{
|
||||
case 0:
|
||||
x += u8g->glyph_x;
|
||||
y -= u8g->glyph_y;
|
||||
y--;
|
||||
//u8g_DrawFrame(u8g, x, y-h+1, w, h);
|
||||
if ( u8g_IsBBXIntersection(u8g, x, y-h+1, w, h) == 0 )
|
||||
return u8g->glyph_dx;
|
||||
|
||||
iy = y;
|
||||
iy -= h;
|
||||
iy++;
|
||||
|
||||
for( j = 0; j < h; j++ )
|
||||
{
|
||||
ix = x;
|
||||
for( i = 0; i < bytes_per_line; i++ )
|
||||
{
|
||||
u8g_Draw8Pixel(u8g, ix, iy, dir, u8g_pgm_read(data));
|
||||
data++;
|
||||
ix+=8;
|
||||
}
|
||||
iy++;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
x += u8g->glyph_y;
|
||||
x++;
|
||||
y += u8g->glyph_x;
|
||||
//printf("enc %d, dir %d, x %d, y %d, w %d, h %d\n", encoding, dir, x, y, w, h);
|
||||
//u8g_DrawFrame(u8g, x, y, h, w);
|
||||
if ( u8g_IsBBXIntersection(u8g, x, y, h, w) == 0 )
|
||||
return u8g->glyph_dx;
|
||||
|
||||
ix = x;
|
||||
ix += h;
|
||||
ix--;
|
||||
for( j = 0; j < h; j++ )
|
||||
{
|
||||
iy = y;
|
||||
for( i = 0; i < bytes_per_line; i++ )
|
||||
{
|
||||
u8g_Draw8Pixel(u8g, ix, iy, dir, u8g_pgm_read(data));
|
||||
data++;
|
||||
iy+=8;
|
||||
}
|
||||
ix--;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
x -= u8g->glyph_x;
|
||||
y += u8g->glyph_y;
|
||||
y++;
|
||||
if ( u8g_IsBBXIntersection(u8g, x-w-1, y, w, h) == 0 )
|
||||
return u8g->glyph_dx;
|
||||
|
||||
iy = y;
|
||||
iy += h;
|
||||
iy--;
|
||||
for( j = 0; j < h; j++ )
|
||||
{
|
||||
ix = x;
|
||||
for( i = 0; i < bytes_per_line; i++ )
|
||||
{
|
||||
u8g_Draw8Pixel(u8g, ix, iy, dir, u8g_pgm_read(data));
|
||||
data++;
|
||||
ix-=8;
|
||||
}
|
||||
iy--;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
x -= u8g->glyph_y;
|
||||
x--;
|
||||
y -= u8g->glyph_x;
|
||||
|
||||
if ( u8g_IsBBXIntersection(u8g, x-h-1, y-w-1, h, w) == 0 )
|
||||
return u8g->glyph_dx;
|
||||
|
||||
ix = x;
|
||||
ix -= h;
|
||||
ix++;
|
||||
|
||||
for( j = 0; j < h; j++ )
|
||||
{
|
||||
iy = y;
|
||||
for( i = 0; i < bytes_per_line; i++ )
|
||||
{
|
||||
u8g_Draw8Pixel(u8g, ix, iy, dir, u8g_pgm_read(data));
|
||||
data++;
|
||||
iy-=8;
|
||||
}
|
||||
ix++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return u8g->glyph_dx;
|
||||
}
|
||||
#endif
|
||||
|
||||
int8_t u8g_draw_glyph(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, uint8_t encoding)
|
||||
{
|
||||
const u8g_pgm_uint8_t *data;
|
||||
uint8_t w, h;
|
||||
uint8_t i, j;
|
||||
u8g_uint_t ix, iy;
|
||||
|
||||
{
|
||||
u8g_glyph_t g = u8g_GetGlyph(u8g, encoding);
|
||||
if ( g == NULL )
|
||||
return 0;
|
||||
data = u8g_font_GetGlyphDataStart(u8g->font, g);
|
||||
}
|
||||
|
||||
w = u8g->glyph_width;
|
||||
h = u8g->glyph_height;
|
||||
|
||||
x += u8g->glyph_x;
|
||||
y -= u8g->glyph_y;
|
||||
y--;
|
||||
|
||||
if ( u8g_IsBBXIntersection(u8g, x, y-h+1, w, h) == 0 )
|
||||
return u8g->glyph_dx;
|
||||
|
||||
/* now, w is reused as bytes per line */
|
||||
w += 7;
|
||||
w /= 8;
|
||||
|
||||
iy = y;
|
||||
iy -= h;
|
||||
iy++;
|
||||
|
||||
for( j = 0; j < h; j++ )
|
||||
{
|
||||
ix = x;
|
||||
for( i = 0; i < w; i++ )
|
||||
{
|
||||
u8g_Draw8Pixel(u8g, ix, iy, 0, u8g_pgm_read(data));
|
||||
data++;
|
||||
ix+=8;
|
||||
}
|
||||
iy++;
|
||||
}
|
||||
return u8g->glyph_dx;
|
||||
}
|
||||
|
||||
int8_t u8g_DrawGlyph(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, uint8_t encoding)
|
||||
{
|
||||
y += u8g->font_calc_vref(u8g);
|
||||
return u8g_draw_glyph(u8g, x, y, encoding);
|
||||
}
|
||||
|
||||
int8_t u8g_draw_glyph90(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, uint8_t encoding)
|
||||
{
|
||||
const u8g_pgm_uint8_t *data;
|
||||
uint8_t w, h;
|
||||
uint8_t i, j;
|
||||
u8g_uint_t ix, iy;
|
||||
|
||||
{
|
||||
u8g_glyph_t g = u8g_GetGlyph(u8g, encoding);
|
||||
if ( g == NULL )
|
||||
return 0;
|
||||
data = u8g_font_GetGlyphDataStart(u8g->font, g);
|
||||
}
|
||||
|
||||
w = u8g->glyph_width;
|
||||
h = u8g->glyph_height;
|
||||
|
||||
x += u8g->glyph_y;
|
||||
x++;
|
||||
y += u8g->glyph_x;
|
||||
|
||||
if ( u8g_IsBBXIntersection(u8g, x, y, h, w) == 0 )
|
||||
return u8g->glyph_dx;
|
||||
|
||||
/* now, w is reused as bytes per line */
|
||||
w += 7;
|
||||
w /= 8;
|
||||
|
||||
ix = x;
|
||||
ix += h;
|
||||
ix--;
|
||||
for( j = 0; j < h; j++ )
|
||||
{
|
||||
iy = y;
|
||||
for( i = 0; i < w; i++ )
|
||||
{
|
||||
u8g_Draw8Pixel(u8g, ix, iy, 1, u8g_pgm_read(data));
|
||||
data++;
|
||||
iy+=8;
|
||||
}
|
||||
ix--;
|
||||
}
|
||||
return u8g->glyph_dx;
|
||||
}
|
||||
|
||||
int8_t u8g_DrawGlyph90(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, uint8_t encoding)
|
||||
{
|
||||
x -= u8g->font_calc_vref(u8g);
|
||||
return u8g_draw_glyph90(u8g, x, y, encoding);
|
||||
}
|
||||
|
||||
|
||||
int8_t u8g_draw_glyph180(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, uint8_t encoding)
|
||||
{
|
||||
const u8g_pgm_uint8_t *data;
|
||||
uint8_t w, h;
|
||||
uint8_t i, j;
|
||||
u8g_uint_t ix, iy;
|
||||
|
||||
{
|
||||
u8g_glyph_t g = u8g_GetGlyph(u8g, encoding);
|
||||
if ( g == NULL )
|
||||
return 0;
|
||||
data = u8g_font_GetGlyphDataStart(u8g->font, g);
|
||||
}
|
||||
|
||||
w = u8g->glyph_width;
|
||||
h = u8g->glyph_height;
|
||||
|
||||
x -= u8g->glyph_x;
|
||||
y += u8g->glyph_y;
|
||||
y++;
|
||||
|
||||
if ( u8g_IsBBXIntersection(u8g, x-(w-1), y, w, h) == 0 )
|
||||
return u8g->glyph_dx;
|
||||
|
||||
/* now, w is reused as bytes per line */
|
||||
w += 7;
|
||||
w /= 8;
|
||||
|
||||
iy = y;
|
||||
iy += h;
|
||||
iy--;
|
||||
for( j = 0; j < h; j++ )
|
||||
{
|
||||
ix = x;
|
||||
for( i = 0; i < w; i++ )
|
||||
{
|
||||
u8g_Draw8Pixel(u8g, ix, iy, 2, u8g_pgm_read(data));
|
||||
data++;
|
||||
ix-=8;
|
||||
}
|
||||
iy--;
|
||||
}
|
||||
return u8g->glyph_dx;
|
||||
}
|
||||
|
||||
int8_t u8g_DrawGlyph180(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, uint8_t encoding)
|
||||
{
|
||||
y -= u8g->font_calc_vref(u8g);
|
||||
return u8g_draw_glyph180(u8g, x, y, encoding);
|
||||
}
|
||||
|
||||
|
||||
int8_t u8g_draw_glyph270(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, uint8_t encoding)
|
||||
{
|
||||
const u8g_pgm_uint8_t *data;
|
||||
uint8_t w, h;
|
||||
uint8_t i, j;
|
||||
u8g_uint_t ix, iy;
|
||||
|
||||
{
|
||||
u8g_glyph_t g = u8g_GetGlyph(u8g, encoding);
|
||||
if ( g == NULL )
|
||||
return 0;
|
||||
data = u8g_font_GetGlyphDataStart(u8g->font, g);
|
||||
}
|
||||
|
||||
w = u8g->glyph_width;
|
||||
h = u8g->glyph_height;
|
||||
|
||||
x -= u8g->glyph_y;
|
||||
x--;
|
||||
y -= u8g->glyph_x;
|
||||
|
||||
if ( u8g_IsBBXIntersection(u8g, x-(h-1), y-(w-1), h, w) == 0 )
|
||||
return u8g->glyph_dx;
|
||||
|
||||
|
||||
/* now, w is reused as bytes per line */
|
||||
w += 7;
|
||||
w /= 8;
|
||||
|
||||
ix = x;
|
||||
ix -= h;
|
||||
ix++;
|
||||
|
||||
for( j = 0; j < h; j++ )
|
||||
{
|
||||
iy = y;
|
||||
for( i = 0; i < w; i++ )
|
||||
{
|
||||
u8g_Draw8Pixel(u8g, ix, iy, 3, u8g_pgm_read(data));
|
||||
data++;
|
||||
iy-=8;
|
||||
}
|
||||
ix++;
|
||||
}
|
||||
return u8g->glyph_dx;
|
||||
}
|
||||
|
||||
int8_t u8g_DrawGlyph270(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, uint8_t encoding)
|
||||
{
|
||||
x += u8g->font_calc_vref(u8g);
|
||||
return u8g_draw_glyph270(u8g, x, y, encoding);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef OBSOLETE
|
||||
/*
|
||||
Draw a glyph
|
||||
x,y: lower left corner of the font bounding box
|
||||
*/
|
||||
int8_t u8g_DrawGlyphFontBBX(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, uint8_t dir, uint8_t encoding)
|
||||
{
|
||||
/* TODO: apply "dir" */
|
||||
x -= u8g_GetFontBBXOffX(u8g);
|
||||
y += u8g_GetFontBBXOffY(u8g);
|
||||
return u8g_DrawGlyphDir(u8g, x, y, dir, encoding);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*========================================================================*/
|
||||
/* string drawing procedures */
|
||||
|
||||
|
||||
u8g_uint_t u8g_DrawStr(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, const char *s)
|
||||
{
|
||||
u8g_uint_t t = 0;
|
||||
int8_t d;
|
||||
|
||||
//u8g_uint_t u8g_GetStrWidth(u8g, s);
|
||||
//u8g_font_GetFontAscent(u8g->font)-u8g_font_GetFontDescent(u8g->font);
|
||||
|
||||
y += u8g->font_calc_vref(u8g);
|
||||
|
||||
while( *s != '\0' )
|
||||
{
|
||||
d = u8g_draw_glyph(u8g, x, y, *s);
|
||||
x += d;
|
||||
t += d;
|
||||
s++;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
u8g_uint_t u8g_DrawStr90(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, const char *s)
|
||||
{
|
||||
u8g_uint_t t = 0;
|
||||
int8_t d;
|
||||
|
||||
x -= u8g->font_calc_vref(u8g);
|
||||
|
||||
while( *s != '\0' )
|
||||
{
|
||||
d = u8g_draw_glyph90(u8g, x, y, *s);
|
||||
y += d;
|
||||
t += d;
|
||||
s++;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
u8g_uint_t u8g_DrawStr180(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, const char *s)
|
||||
{
|
||||
u8g_uint_t t = 0;
|
||||
int8_t d;
|
||||
|
||||
y -= u8g->font_calc_vref(u8g);
|
||||
|
||||
while( *s != '\0' )
|
||||
{
|
||||
d = u8g_draw_glyph180(u8g, x, y, *s);
|
||||
x -= d;
|
||||
t += d;
|
||||
s++;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
u8g_uint_t u8g_DrawStr270(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, const char *s)
|
||||
{
|
||||
u8g_uint_t t = 0;
|
||||
int8_t d;
|
||||
|
||||
x += u8g->font_calc_vref(u8g);
|
||||
|
||||
while( *s != '\0' )
|
||||
{
|
||||
d = u8g_draw_glyph270(u8g, x, y, *s);
|
||||
y -= d;
|
||||
t += d;
|
||||
s++;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
u8g_uint_t u8g_DrawStrDir(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, uint8_t dir, const char *s)
|
||||
{
|
||||
switch(dir)
|
||||
{
|
||||
case 0:
|
||||
return u8g_DrawStr(u8g, x, y, s);
|
||||
case 1:
|
||||
return u8g_DrawStr90(u8g, x, y, s);
|
||||
case 2:
|
||||
return u8g_DrawStr180(u8g, x, y, s);
|
||||
case 3:
|
||||
return u8g_DrawStr270(u8g, x, y, s);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8g_uint_t u8g_DrawStrP(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, const u8g_pgm_uint8_t *s)
|
||||
{
|
||||
u8g_uint_t t = 0;
|
||||
int8_t d;
|
||||
uint8_t c;
|
||||
|
||||
y += u8g->font_calc_vref(u8g);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
c = u8g_pgm_read(s);
|
||||
if ( c == '\0' )
|
||||
break;
|
||||
d = u8g_draw_glyph(u8g, x, y, c);
|
||||
x += d;
|
||||
t += d;
|
||||
s++;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
u8g_uint_t u8g_DrawStr90P(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, const u8g_pgm_uint8_t *s)
|
||||
{
|
||||
u8g_uint_t t = 0;
|
||||
int8_t d;
|
||||
|
||||
x -= u8g->font_calc_vref(u8g);
|
||||
|
||||
while( *s != '\0' )
|
||||
{
|
||||
d = u8g_DrawGlyph90(u8g, x, y, u8g_pgm_read(s));
|
||||
y += d;
|
||||
t += d;
|
||||
s++;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
u8g_uint_t u8g_DrawStr180P(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, const u8g_pgm_uint8_t *s)
|
||||
{
|
||||
u8g_uint_t t = 0;
|
||||
int8_t d;
|
||||
|
||||
y -= u8g->font_calc_vref(u8g);
|
||||
|
||||
while( *s != '\0' )
|
||||
{
|
||||
d = u8g_DrawGlyph180(u8g, x, y, u8g_pgm_read(s));
|
||||
x -= d;
|
||||
t += d;
|
||||
s++;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
u8g_uint_t u8g_DrawStr270P(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, const u8g_pgm_uint8_t *s)
|
||||
{
|
||||
u8g_uint_t t = 0;
|
||||
int8_t d;
|
||||
|
||||
x += u8g->font_calc_vref(u8g);
|
||||
|
||||
while( *s != '\0' )
|
||||
{
|
||||
d = u8g_DrawGlyph270(u8g, x, y, u8g_pgm_read(s));
|
||||
y -= d;
|
||||
t += d;
|
||||
s++;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
u8g_uint_t u8g_DrawStrFontBBX(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, uint8_t dir, const char *s)
|
||||
{
|
||||
x -= u8g_GetFontBBXOffX(u8g);
|
||||
y += u8g_GetFontBBXOffY(u8g);
|
||||
return u8g_DrawStrDir(u8g, x, y, dir, s);
|
||||
}
|
||||
|
||||
/* still used by picgen.c, dir argument is ignored */
|
||||
int8_t u8g_DrawGlyphFontBBX(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, uint8_t dir, uint8_t encoding)
|
||||
{
|
||||
x -= u8g_GetFontBBXOffX(u8g);
|
||||
y += u8g_GetFontBBXOffY(u8g);
|
||||
u8g_draw_glyph(u8g, x, y, encoding);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*========================================================================*/
|
||||
/* set ascent/descent for reference point calculation */
|
||||
|
||||
void u8g_UpdateRefHeight(u8g_t *u8g)
|
||||
{
|
||||
uint16_t ls;
|
||||
if ( u8g->font == NULL )
|
||||
return;
|
||||
if ( u8g->font_height_mode == U8G_FONT_HEIGHT_MODE_TEXT )
|
||||
{
|
||||
u8g->font_ref_ascent = u8g_font_GetCapitalAHeight(u8g->font);
|
||||
u8g->font_ref_descent = u8g_font_GetLowerGDescent(u8g->font);
|
||||
}
|
||||
else if ( u8g->font_height_mode == U8G_FONT_HEIGHT_MODE_XTEXT )
|
||||
{
|
||||
u8g->font_ref_ascent = u8g_font_GetFontXAscent(u8g->font);
|
||||
u8g->font_ref_descent = u8g_font_GetFontXDescent(u8g->font);
|
||||
}
|
||||
else
|
||||
{
|
||||
u8g->font_ref_ascent = u8g_font_GetFontAscent(u8g->font);
|
||||
u8g->font_ref_descent = u8g_font_GetFontDescent(u8g->font);
|
||||
}
|
||||
|
||||
ls = u8g->font_ref_ascent - u8g->font_ref_descent;
|
||||
if ( u8g->font_line_spacing_factor != 64 )
|
||||
{
|
||||
ls &= 255;
|
||||
ls *= u8g->font_line_spacing_factor;
|
||||
ls >>= 6;
|
||||
}
|
||||
u8g->line_spacing = ls;
|
||||
}
|
||||
|
||||
void u8g_SetFontRefHeightText(u8g_t *u8g)
|
||||
{
|
||||
u8g->font_height_mode = U8G_FONT_HEIGHT_MODE_TEXT;
|
||||
u8g_UpdateRefHeight(u8g);
|
||||
}
|
||||
|
||||
void u8g_SetFontRefHeightExtendedText(u8g_t *u8g)
|
||||
{
|
||||
u8g->font_height_mode = U8G_FONT_HEIGHT_MODE_XTEXT;
|
||||
u8g_UpdateRefHeight(u8g);
|
||||
}
|
||||
|
||||
|
||||
void u8g_SetFontRefHeightAll(u8g_t *u8g)
|
||||
{
|
||||
u8g->font_height_mode = U8G_FONT_HEIGHT_MODE_ALL;
|
||||
u8g_UpdateRefHeight(u8g);
|
||||
}
|
||||
|
||||
/* factor = 64: linespaceing == ascent and descent */
|
||||
void u8g_SetFontLineSpacingFactor(u8g_t *u8g, uint8_t factor)
|
||||
{
|
||||
u8g->font_line_spacing_factor = factor;
|
||||
u8g_UpdateRefHeight(u8g);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*========================================================================*/
|
||||
/* callback procedures to correct the y position */
|
||||
|
||||
u8g_uint_t u8g_font_calc_vref_font(u8g_t *u8g)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void u8g_SetFontPosBaseline(u8g_t *u8g)
|
||||
{
|
||||
u8g->font_calc_vref = u8g_font_calc_vref_font;
|
||||
}
|
||||
|
||||
|
||||
u8g_uint_t u8g_font_calc_vref_bottom(u8g_t *u8g)
|
||||
{
|
||||
/* y += (u8g_uint_t)(u8g_int_t)(u8g->font_ref_descent); */
|
||||
return (u8g_uint_t)(u8g_int_t)(u8g->font_ref_descent);
|
||||
}
|
||||
|
||||
void u8g_SetFontPosBottom(u8g_t *u8g)
|
||||
{
|
||||
u8g->font_calc_vref = u8g_font_calc_vref_bottom;
|
||||
}
|
||||
|
||||
u8g_uint_t u8g_font_calc_vref_top(u8g_t *u8g)
|
||||
{
|
||||
u8g_uint_t tmp;
|
||||
/* reference pos is one pixel above the upper edge of the reference glyph */
|
||||
|
||||
/*
|
||||
y += (u8g_uint_t)(u8g_int_t)(u8g->font_ref_ascent);
|
||||
y++;
|
||||
*/
|
||||
tmp = (u8g_uint_t)(u8g_int_t)(u8g->font_ref_ascent);
|
||||
tmp++;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void u8g_SetFontPosTop(u8g_t *u8g)
|
||||
{
|
||||
u8g->font_calc_vref = u8g_font_calc_vref_top;
|
||||
}
|
||||
|
||||
u8g_uint_t u8g_font_calc_vref_center(u8g_t *u8g)
|
||||
{
|
||||
int8_t tmp;
|
||||
tmp = u8g->font_ref_ascent;
|
||||
tmp -= u8g->font_ref_descent;
|
||||
tmp /= 2;
|
||||
tmp += u8g->font_ref_descent;
|
||||
/* y += (u8g_uint_t)(u8g_int_t)(tmp); */
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void u8g_SetFontPosCenter(u8g_t *u8g)
|
||||
{
|
||||
u8g->font_calc_vref = u8g_font_calc_vref_center;
|
||||
}
|
||||
|
||||
/*========================================================================*/
|
||||
/* string pixel width calculation */
|
||||
|
||||
char u8g_font_get_char(const void *s)
|
||||
{
|
||||
return *(const char *)(s);
|
||||
}
|
||||
|
||||
char u8g_font_get_charP(const void *s)
|
||||
{
|
||||
return u8g_pgm_read(s);
|
||||
}
|
||||
|
||||
typedef char (*u8g_font_get_char_fn)(const void *s);
|
||||
|
||||
|
||||
u8g_uint_t u8g_font_calc_str_pixel_width(u8g_t *u8g, const char *s, u8g_font_get_char_fn get_char )
|
||||
{
|
||||
u8g_uint_t w;
|
||||
uint8_t enc;
|
||||
|
||||
/* reset the total minimal width to zero, this will be expanded during calculation */
|
||||
w = 0;
|
||||
|
||||
enc = get_char(s);
|
||||
|
||||
/* check for empty string, width is already 0 */
|
||||
if ( enc == '\0' )
|
||||
{
|
||||
return w;
|
||||
}
|
||||
|
||||
/* get the glyph information of the first char. This must be valid, because we already checked for the empty string */
|
||||
/* if *s is not inside the font, then the cached parameters of the glyph are all zero */
|
||||
u8g_GetGlyph(u8g, enc);
|
||||
|
||||
/* strlen(s) == 1: width = width(s[0]) */
|
||||
/* strlen(s) == 2: width = - offx(s[0]) + deltax(s[0]) + offx(s[1]) + width(s[1]) */
|
||||
/* strlen(s) == 3: width = - offx(s[0]) + deltax(s[0]) + deltax(s[1]) + offx(s[2]) + width(s[2]) */
|
||||
|
||||
/* assume that the string has size 2 or more, than start with negative offset-x */
|
||||
/* for string with size 1, this will be nullified after the loop */
|
||||
w = -u8g->glyph_x;
|
||||
for(;;)
|
||||
{
|
||||
|
||||
/* check and stop if the end of the string is reached */
|
||||
s++;
|
||||
if ( get_char(s) == '\0' )
|
||||
break;
|
||||
|
||||
/* if there are still more characters, add the delta to the next glyph */
|
||||
w += u8g->glyph_dx;
|
||||
|
||||
/* store the encoding in a local variable, used also after the for(;;) loop */
|
||||
enc = get_char(s);
|
||||
|
||||
/* load the next glyph information */
|
||||
u8g_GetGlyph(u8g, enc);
|
||||
}
|
||||
|
||||
/* finally calculate the width of the last char */
|
||||
/* here is another exception, if the last char is a black, use the dx value instead */
|
||||
if ( enc != ' ' )
|
||||
{
|
||||
/* if g was not updated in the for loop (strlen() == 1), then the initial offset x gets removed */
|
||||
w += u8g->glyph_width;
|
||||
w += u8g->glyph_x;
|
||||
}
|
||||
else
|
||||
{
|
||||
w += u8g->glyph_dx;
|
||||
}
|
||||
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
u8g_uint_t u8g_GetStrPixelWidth(u8g_t *u8g, const char *s)
|
||||
{
|
||||
return u8g_font_calc_str_pixel_width(u8g, s, u8g_font_get_char);
|
||||
}
|
||||
|
||||
u8g_uint_t u8g_GetStrPixelWidthP(u8g_t *u8g, const u8g_pgm_uint8_t *s)
|
||||
{
|
||||
return u8g_font_calc_str_pixel_width(u8g, (const char *)s, u8g_font_get_charP);
|
||||
}
|
||||
|
||||
int8_t u8g_GetStrX(u8g_t *u8g, const char *s)
|
||||
{
|
||||
u8g_GetGlyph(u8g, *s);
|
||||
return u8g->glyph_x;
|
||||
}
|
||||
|
||||
int8_t u8g_GetStrXP(u8g_t *u8g, const u8g_pgm_uint8_t *s)
|
||||
{
|
||||
u8g_GetGlyph(u8g, u8g_pgm_read(s));
|
||||
return u8g->glyph_x;
|
||||
}
|
||||
|
||||
/*========================================================================*/
|
||||
/* string width calculation */
|
||||
|
||||
u8g_uint_t u8g_GetStrWidth(u8g_t *u8g, const char *s)
|
||||
{
|
||||
u8g_uint_t w;
|
||||
uint8_t encoding;
|
||||
|
||||
/* reset the total width to zero, this will be expanded during calculation */
|
||||
w = 0;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
encoding = *s;
|
||||
if ( encoding == 0 )
|
||||
break;
|
||||
|
||||
/* load glyph information */
|
||||
u8g_GetGlyph(u8g, encoding);
|
||||
w += u8g->glyph_dx;
|
||||
|
||||
/* goto next char */
|
||||
s++;
|
||||
}
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
|
||||
u8g_uint_t u8g_GetStrWidthP(u8g_t *u8g, const u8g_pgm_uint8_t *s)
|
||||
{
|
||||
u8g_uint_t w;
|
||||
uint8_t encoding;
|
||||
|
||||
/* reset the total width to zero, this will be expanded during calculation */
|
||||
w = 0;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
encoding = u8g_pgm_read(s);
|
||||
if ( encoding == 0 )
|
||||
break;
|
||||
|
||||
/* load glyph information */
|
||||
u8g_GetGlyph(u8g, encoding);
|
||||
w += u8g->glyph_dx;
|
||||
|
||||
/* goto next char */
|
||||
s++;
|
||||
}
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
|
||||
/*========================================================================*/
|
||||
/* calculation of font/glyph/string characteristics */
|
||||
|
||||
|
||||
/*
|
||||
Description:
|
||||
Calculate parameter for the minimal bounding box on a given string
|
||||
Output
|
||||
buf->y_min extend of the lower left edge if the string below (y_min<0) or above (y_min>0) baseline (descent)
|
||||
buf->y_max extend of the upper left edge if the string below (y_min<0) or above (y_min>0) baseline (ascent)
|
||||
buf->w the width of the string
|
||||
*/
|
||||
struct u8g_str_size_struct
|
||||
{
|
||||
int8_t y_min; /* descent */
|
||||
int8_t y_max; /* ascent */
|
||||
int8_t x, y; /* the reference point of the font (negated!) */
|
||||
u8g_uint_t w; /* width of the overall string */
|
||||
};
|
||||
typedef struct u8g_str_size_struct u8g_str_size_t;
|
||||
|
||||
static void u8g_font_calc_str_min_box(u8g_t *u8g, const char *s, u8g_str_size_t *buf)
|
||||
{
|
||||
/* u8g_glyph_t g; */
|
||||
int8_t tmp;
|
||||
|
||||
/* reset the total minimal width to zero, this will be expanded during calculation */
|
||||
buf->w = 0;
|
||||
|
||||
/* check for empty string, width is already 0, but also reset y_min and y_max to 0 */
|
||||
if ( *s == '\0' )
|
||||
{
|
||||
buf->y_min = 0;
|
||||
buf->y_max = 0;
|
||||
buf->x = 0;
|
||||
buf->y = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* reset y_min to the largest possible value. Later we search for the smallest value */
|
||||
/* y_min contains the position [pixel] of the lower left edge of the glyph above (y_min>0) or below (y_min<0) baseline */
|
||||
buf->y_min = 127;
|
||||
/* reset y_max to the smallest possible value. Later we search for the highest value */
|
||||
/* y_max contains the position [pixel] of the upper left edge of the glyph above (y_max>0) or below (y_max<0) baseline */
|
||||
buf->y_max = -128;
|
||||
|
||||
/* get the glyph information of the first char. This must be valid, because we already checked for the empty string */
|
||||
u8g_GetGlyph(u8g, *s);
|
||||
|
||||
/* strlen(s) == 1: width = width(s[0]) */
|
||||
/* strlen(s) == 2: width = - offx(s[0]) + deltax(s[0]) + offx(s[1]) + width(s[1]) */
|
||||
/* strlen(s) == 3: width = - offx(s[0]) + deltax(s[0]) + deltax(s[1]) + offx(s[2]) + width(s[2]) */
|
||||
|
||||
/* assume that the string has size 2 or more, than start with negative offset-x */
|
||||
/* for string with size 1, this will be nullified after the loop */
|
||||
// buf->w = - u8g_font_GetGlyphBBXOffX(u8g->font, g);
|
||||
buf->w = - u8g->glyph_x;
|
||||
|
||||
/* Also copy the position of the first glyph. This is the reference point of the string (negated) */
|
||||
buf->x = u8g->glyph_x;
|
||||
buf->y = u8g->glyph_y;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
|
||||
/* calculated y position of the upper left corner (y_max) and lower left corner (y_min) of the string */
|
||||
/* relative to the base line */
|
||||
|
||||
tmp = u8g->glyph_y;
|
||||
if ( buf->y_min > tmp )
|
||||
buf->y_min = tmp;
|
||||
|
||||
tmp +=u8g->glyph_height;
|
||||
if ( buf->y_max < tmp )
|
||||
buf->y_max = tmp;
|
||||
|
||||
/* check and stop if the end of the string is reached */
|
||||
s++;
|
||||
if ( *s == '\0' )
|
||||
break;
|
||||
|
||||
/* if there are still more characters, add the delta to the next glyph */
|
||||
buf->w += u8g->glyph_dx;
|
||||
|
||||
/* load the next glyph information */
|
||||
u8g_GetGlyph(u8g, *s);
|
||||
}
|
||||
|
||||
/* finally calculate the width of the last char */
|
||||
/* if g was not updated in the for loop (strlen() == 1), then the initial offset x gets removed */
|
||||
buf->w += u8g->glyph_width;
|
||||
// buf->w += u8g_font_GetGlyphBBXOffX(u8g->font, g);
|
||||
|
||||
buf->w += u8g->glyph_x;
|
||||
}
|
||||
|
||||
/* calculate minimal box */
|
||||
void u8g_font_box_min(u8g_t *u8g, const char *s, u8g_str_size_t *buf)
|
||||
{
|
||||
u8g_font_calc_str_min_box(u8g, s, buf);
|
||||
}
|
||||
|
||||
/* calculate gA box, but do not calculate the overall width */
|
||||
void u8g_font_box_left_gA(u8g_t *u8g, const char *s, u8g_str_size_t *buf)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/* calculate gA box, including overall width */
|
||||
void u8g_font_box_all_gA(u8g_t *u8g, const char *s, u8g_str_size_t *buf)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void u8g_font_get_str_box_fill_args(u8g_t *u8g, const char *s, u8g_str_size_t *buf, u8g_uint_t *x, u8g_uint_t *y, u8g_uint_t *width, u8g_uint_t *height)
|
||||
{
|
||||
/*
|
||||
u8g_glyph_t g;
|
||||
g =
|
||||
*/
|
||||
u8g_GetGlyph(u8g, *s);
|
||||
*x += u8g->glyph_x;
|
||||
*width = buf->w;
|
||||
*y -= buf->y_max;
|
||||
/* +1 because y_max is a height, this compensates the next step */
|
||||
//*y += 1;
|
||||
/* because the reference point is one below the string, this compensates the previous step */
|
||||
//*y -= 1;
|
||||
*height = buf->y_max;
|
||||
*height -= buf->y_min;
|
||||
}
|
||||
|
||||
|
||||
void u8g_GetStrMinBox(u8g_t *u8g, const char *s, u8g_uint_t *x, u8g_uint_t *y, u8g_uint_t *width, u8g_uint_t *height)
|
||||
{
|
||||
u8g_str_size_t buf;
|
||||
|
||||
if ( *s == '\0' )
|
||||
{
|
||||
*width= 0;
|
||||
*height = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
u8g_font_calc_str_min_box(u8g, s, &buf);
|
||||
u8g_font_get_str_box_fill_args(u8g, s, &buf, x, y, width, height);
|
||||
}
|
||||
|
||||
|
||||
void u8g_GetStrAMinBox(u8g_t *u8g, const char *s, u8g_uint_t *x, u8g_uint_t *y, u8g_uint_t *width, u8g_uint_t *height)
|
||||
{
|
||||
u8g_str_size_t buf;
|
||||
uint8_t cap_a;
|
||||
|
||||
if ( *s == '\0' )
|
||||
{
|
||||
*width= 0;
|
||||
*height = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
cap_a = u8g_font_GetCapitalAHeight(u8g->font);
|
||||
u8g_font_calc_str_min_box(u8g, s, &buf);
|
||||
if ( buf.y_max < cap_a )
|
||||
buf.y_max = cap_a;
|
||||
u8g_font_get_str_box_fill_args(u8g, s, &buf, x, y, width, height);
|
||||
}
|
||||
|
||||
void u8g_SetFont(u8g_t *u8g, const u8g_fntpgm_uint8_t *font)
|
||||
{
|
||||
if ( u8g->font != font )
|
||||
{
|
||||
u8g->font = font;
|
||||
u8g_UpdateRefHeight(u8g);
|
||||
u8g_SetFontPosBaseline(u8g);
|
||||
}
|
||||
}
|
||||
|
||||
/*========================================================================*/
|
||||
/* anti aliasing fonts */
|
||||
|
||||
int8_t u8g_draw_aa_glyph(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, uint8_t encoding)
|
||||
{
|
||||
const u8g_pgm_uint8_t *data;
|
||||
uint8_t w, h;
|
||||
uint8_t i, j;
|
||||
u8g_uint_t ix, iy;
|
||||
|
||||
{
|
||||
u8g_glyph_t g = u8g_GetGlyph(u8g, encoding);
|
||||
if ( g == NULL )
|
||||
return 0;
|
||||
data = u8g_font_GetGlyphDataStart(u8g->font, g);
|
||||
}
|
||||
|
||||
w = u8g->glyph_width;
|
||||
h = u8g->glyph_height;
|
||||
|
||||
x += u8g->glyph_x;
|
||||
y -= u8g->glyph_y;
|
||||
y--;
|
||||
|
||||
if ( u8g_IsBBXIntersection(u8g, x, y-h+1, w, h) == 0 )
|
||||
return u8g->glyph_dx;
|
||||
|
||||
/* now, w is reused as bytes per line */
|
||||
w += 3;
|
||||
w /= 4;
|
||||
|
||||
iy = y;
|
||||
iy -= h;
|
||||
iy++;
|
||||
|
||||
for( j = 0; j < h; j++ )
|
||||
{
|
||||
ix = x;
|
||||
for( i = 0; i < w; i++ )
|
||||
{
|
||||
u8g_Draw4TPixel(u8g, ix, iy, 0, u8g_pgm_read(data));
|
||||
data++;
|
||||
ix+=4;
|
||||
}
|
||||
iy++;
|
||||
}
|
||||
return u8g->glyph_dx;
|
||||
}
|
||||
|
||||
int8_t u8g_DrawAAGlyph(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, uint8_t encoding)
|
||||
{
|
||||
y += u8g->font_calc_vref(u8g);
|
||||
return u8g_draw_aa_glyph(u8g, x, y, encoding);
|
||||
}
|
||||
|
||||
u8g_uint_t u8g_DrawAAStr(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, const char *s)
|
||||
{
|
||||
u8g_uint_t t = 0;
|
||||
int8_t d;
|
||||
|
||||
if ( u8g_font_GetFormat(u8g->font) != 2 )
|
||||
return 0;
|
||||
//u8g_uint_t u8g_GetStrWidth(u8g, s);
|
||||
//u8g_font_GetFontAscent(u8g->font)-u8g_font_GetFontDescent(u8g->font);
|
||||
|
||||
y += u8g->font_calc_vref(u8g);
|
||||
|
||||
while( *s != '\0' )
|
||||
{
|
||||
d = u8g_draw_aa_glyph(u8g, x, y, *s);
|
||||
x += d;
|
||||
t += d;
|
||||
s++;
|
||||
}
|
||||
return t;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,573 @@
|
||||
/*
|
||||
|
||||
u8g_ll_api.c
|
||||
|
||||
low level api
|
||||
|
||||
Universal 8bit Graphics Library
|
||||
|
||||
Copyright (c) 2011, olikraus@gmail.com
|
||||
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 <stddef.h>
|
||||
#include "u8g.h"
|
||||
|
||||
uint8_t u8g_call_dev_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg)
|
||||
{
|
||||
return dev->dev_fn(u8g, dev, msg, arg);
|
||||
}
|
||||
|
||||
/*====================================================================*/
|
||||
|
||||
uint8_t u8g_InitLL(u8g_t *u8g, u8g_dev_t *dev)
|
||||
{
|
||||
uint8_t r;
|
||||
u8g->state_cb(U8G_STATE_MSG_BACKUP_ENV);
|
||||
r = u8g_call_dev_fn(u8g, dev, U8G_DEV_MSG_INIT, NULL);
|
||||
u8g->state_cb(U8G_STATE_MSG_BACKUP_U8G);
|
||||
u8g->state_cb(U8G_STATE_MSG_RESTORE_ENV);
|
||||
return r;
|
||||
}
|
||||
|
||||
void u8g_FirstPageLL(u8g_t *u8g, u8g_dev_t *dev)
|
||||
{
|
||||
u8g->state_cb(U8G_STATE_MSG_BACKUP_ENV);
|
||||
u8g->state_cb(U8G_STATE_MSG_RESTORE_U8G);
|
||||
u8g_call_dev_fn(u8g, dev, U8G_DEV_MSG_PAGE_FIRST, NULL);
|
||||
u8g_call_dev_fn(u8g, dev, U8G_DEV_MSG_GET_PAGE_BOX, &(u8g->current_page));
|
||||
u8g->state_cb(U8G_STATE_MSG_RESTORE_ENV);
|
||||
}
|
||||
|
||||
uint8_t u8g_NextPageLL(u8g_t *u8g, u8g_dev_t *dev)
|
||||
{
|
||||
uint8_t r;
|
||||
u8g->state_cb(U8G_STATE_MSG_BACKUP_ENV);
|
||||
u8g->state_cb(U8G_STATE_MSG_RESTORE_U8G);
|
||||
r = u8g_call_dev_fn(u8g, dev, U8G_DEV_MSG_PAGE_NEXT, NULL);
|
||||
if ( r != 0 )
|
||||
{
|
||||
u8g_call_dev_fn(u8g, dev, U8G_DEV_MSG_GET_PAGE_BOX, &(u8g->current_page));
|
||||
}
|
||||
u8g->state_cb(U8G_STATE_MSG_RESTORE_ENV);
|
||||
return r;
|
||||
}
|
||||
|
||||
uint8_t u8g_SetContrastLL(u8g_t *u8g, u8g_dev_t *dev, uint8_t contrast)
|
||||
{
|
||||
return u8g_call_dev_fn(u8g, dev, U8G_DEV_MSG_CONTRAST, &contrast);
|
||||
}
|
||||
|
||||
void u8g_DrawPixelLL(u8g_t *u8g, u8g_dev_t *dev, u8g_uint_t x, u8g_uint_t y)
|
||||
{
|
||||
u8g_dev_arg_pixel_t *arg = &(u8g->arg_pixel);
|
||||
arg->x = x;
|
||||
arg->y = y;
|
||||
u8g_call_dev_fn(u8g, dev, U8G_DEV_MSG_SET_PIXEL, arg);
|
||||
}
|
||||
|
||||
void u8g_Draw8PixelLL(u8g_t *u8g, u8g_dev_t *dev, u8g_uint_t x, u8g_uint_t y, uint8_t dir, uint8_t pixel)
|
||||
{
|
||||
u8g_dev_arg_pixel_t *arg = &(u8g->arg_pixel);
|
||||
arg->x = x;
|
||||
arg->y = y;
|
||||
arg->dir = dir;
|
||||
arg->pixel = pixel;
|
||||
u8g_call_dev_fn(u8g, dev, U8G_DEV_MSG_SET_8PIXEL, arg);
|
||||
}
|
||||
|
||||
void u8g_Draw4TPixelLL(u8g_t *u8g, u8g_dev_t *dev, u8g_uint_t x, u8g_uint_t y, uint8_t dir, uint8_t pixel)
|
||||
{
|
||||
u8g_dev_arg_pixel_t *arg = &(u8g->arg_pixel);
|
||||
arg->x = x;
|
||||
arg->y = y;
|
||||
arg->dir = dir;
|
||||
arg->pixel = pixel;
|
||||
u8g_call_dev_fn(u8g, dev, U8G_DEV_MSG_SET_4TPIXEL, arg);
|
||||
}
|
||||
|
||||
|
||||
#ifdef U8G_DEV_MSG_IS_BBX_INTERSECTION
|
||||
uint8_t u8g_IsBBXIntersectionLL(u8g_t *u8g, u8g_dev_t *dev, u8g_uint_t x, u8g_uint_t y, u8g_uint_t w, u8g_uint_t h)
|
||||
{
|
||||
return u8g_call_dev_fn(u8g, dev, U8G_DEV_MSG_IS_BBX_INTERSECTION, &arg);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
u8g_uint_t u8g_GetWidthLL(u8g_t *u8g, u8g_dev_t *dev)
|
||||
{
|
||||
u8g_uint_t r;
|
||||
u8g_call_dev_fn(u8g, dev, U8G_DEV_MSG_GET_WIDTH, &r);
|
||||
return r;
|
||||
}
|
||||
|
||||
u8g_uint_t u8g_GetHeightLL(u8g_t *u8g, u8g_dev_t *dev)
|
||||
{
|
||||
u8g_uint_t r;
|
||||
u8g_call_dev_fn(u8g, dev, U8G_DEV_MSG_GET_HEIGHT, &r);
|
||||
return r;
|
||||
}
|
||||
|
||||
u8g_uint_t u8g_GetModeLL(u8g_t *u8g, u8g_dev_t *dev)
|
||||
{
|
||||
return u8g_call_dev_fn(u8g, dev, U8G_DEV_MSG_GET_MODE, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*====================================================================*/
|
||||
|
||||
void u8g_UpdateDimension(u8g_t *u8g)
|
||||
{
|
||||
u8g->width = u8g_GetWidthLL(u8g, u8g->dev);
|
||||
u8g->height = u8g_GetHeightLL(u8g, u8g->dev);
|
||||
u8g->mode = u8g_GetModeLL(u8g, u8g->dev);
|
||||
/* 9 Dec 2012: u8g_scale.c requires update of current page */
|
||||
u8g_call_dev_fn(u8g, u8g->dev, U8G_DEV_MSG_GET_PAGE_BOX, &(u8g->current_page));
|
||||
}
|
||||
|
||||
static void u8g_init_data(u8g_t *u8g)
|
||||
{
|
||||
u8g->font = NULL;
|
||||
u8g->cursor_font = NULL;
|
||||
u8g->cursor_bg_color = 0;
|
||||
u8g->cursor_fg_color = 1;
|
||||
u8g->cursor_encoding = 34;
|
||||
u8g->cursor_fn = (u8g_draw_cursor_fn)0;
|
||||
|
||||
#if defined(U8G_WITH_PINLIST)
|
||||
{
|
||||
uint8_t i;
|
||||
for( i = 0; i < U8G_PIN_LIST_LEN; i++ )
|
||||
u8g->pin_list[i] = U8G_PIN_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
u8g_SetColorIndex(u8g, 1);
|
||||
|
||||
u8g_SetFontPosBaseline(u8g);
|
||||
|
||||
u8g->font_height_mode = U8G_FONT_HEIGHT_MODE_XTEXT;
|
||||
u8g->font_ref_ascent = 0;
|
||||
u8g->font_ref_descent = 0;
|
||||
u8g->font_line_spacing_factor = 64; /* 64 = 1.0, 77 = 1.2 line spacing factor */
|
||||
u8g->line_spacing = 0;
|
||||
|
||||
u8g->state_cb = u8g_state_dummy_cb;
|
||||
|
||||
}
|
||||
|
||||
uint8_t u8g_Begin(u8g_t *u8g)
|
||||
{
|
||||
/* call and init low level driver and com device */
|
||||
if ( u8g_InitLL(u8g, u8g->dev) == 0 )
|
||||
return 0;
|
||||
/* fetch width and height from the low level */
|
||||
u8g_UpdateDimension(u8g);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t u8g_Init(u8g_t *u8g, u8g_dev_t *dev)
|
||||
{
|
||||
u8g_init_data(u8g);
|
||||
u8g->dev = dev;
|
||||
|
||||
/* On the Arduino Environment this will lead to two calls to u8g_Begin(), the following line will be called first (by U8glib constructors) */
|
||||
/* if - in future releases - this is removed, then still call u8g_UpdateDimension() */
|
||||
/* if Arduino call u8g_UpdateDimension else u8g_Begin */
|
||||
/* issue 146 */
|
||||
return u8g_Begin(u8g);
|
||||
}
|
||||
|
||||
/* special init for pure ARM systems */
|
||||
uint8_t u8g_InitComFn(u8g_t *u8g, u8g_dev_t *dev, u8g_com_fnptr com_fn)
|
||||
{
|
||||
u8g_init_data(u8g);
|
||||
|
||||
#if defined(U8G_WITH_PINLIST)
|
||||
{
|
||||
uint8_t i;
|
||||
for( i = 0; i < U8G_PIN_LIST_LEN; i++ )
|
||||
u8g->pin_list[i] = U8G_PIN_DUMMY;
|
||||
}
|
||||
#endif
|
||||
|
||||
u8g->dev = dev;
|
||||
|
||||
/* replace the device procedure with a custom communication procedure */
|
||||
u8g->dev->com_fn = com_fn;
|
||||
|
||||
/* On the Arduino Environment this will lead to two calls to u8g_Begin(), the following line will be called first (by U8glib constructors) */
|
||||
/* if - in future releases - this is removed, then still call u8g_UpdateDimension() */
|
||||
/* if Arduino call u8g_UpdateDimension else u8g_Begin */
|
||||
/* issue 146 */
|
||||
return u8g_Begin(u8g);
|
||||
}
|
||||
|
||||
|
||||
#if defined(U8G_WITH_PINLIST)
|
||||
uint8_t u8g_InitSPI(u8g_t *u8g, u8g_dev_t *dev, uint8_t sck, uint8_t mosi, uint8_t cs, uint8_t a0, uint8_t reset)
|
||||
{
|
||||
|
||||
/* fill data structure with some suitable values */
|
||||
u8g_init_data(u8g);
|
||||
u8g->dev = dev;
|
||||
|
||||
/* assign user pins */
|
||||
u8g->pin_list[U8G_PI_SCK] = sck;
|
||||
u8g->pin_list[U8G_PI_MOSI] = mosi;
|
||||
u8g->pin_list[U8G_PI_CS] = cs;
|
||||
u8g->pin_list[U8G_PI_A0] = a0;
|
||||
u8g->pin_list[U8G_PI_RESET] = reset;
|
||||
|
||||
/* On the Arduino Environment this will lead to two calls to u8g_Begin(), the following line will be called first (by U8glib constructors) */
|
||||
/* if - in future releases - this is removed, then still call u8g_UpdateDimension() */
|
||||
/* if Arduino call u8g_UpdateDimension else u8g_Begin */
|
||||
/* issue 146 */
|
||||
return u8g_Begin(u8g);
|
||||
}
|
||||
|
||||
uint8_t u8g_InitHWSPI(u8g_t *u8g, u8g_dev_t *dev, uint8_t cs, uint8_t a0, uint8_t reset)
|
||||
{
|
||||
/* fill data structure with some suitable values */
|
||||
u8g_init_data(u8g);
|
||||
u8g->dev = dev;
|
||||
|
||||
|
||||
/* assign user pins */
|
||||
u8g->pin_list[U8G_PI_CS] = cs;
|
||||
u8g->pin_list[U8G_PI_A0] = a0;
|
||||
u8g->pin_list[U8G_PI_RESET] = reset;
|
||||
|
||||
return u8g_Begin(u8g);
|
||||
}
|
||||
|
||||
uint8_t u8g_InitI2C(u8g_t *u8g, u8g_dev_t *dev, uint8_t options)
|
||||
{
|
||||
/* fill data structure with some suitable values */
|
||||
u8g_init_data(u8g);
|
||||
u8g->dev = dev;
|
||||
|
||||
u8g->pin_list[U8G_PI_I2C_OPTION] = options;
|
||||
|
||||
return u8g_Begin(u8g);
|
||||
}
|
||||
|
||||
|
||||
uint8_t u8g_Init8BitFixedPort(u8g_t *u8g, u8g_dev_t *dev, uint8_t en, uint8_t cs, uint8_t di, uint8_t rw, uint8_t reset)
|
||||
{
|
||||
|
||||
/* fill data structure with some suitable values */
|
||||
u8g_init_data(u8g);
|
||||
u8g->dev = dev;
|
||||
|
||||
/* assign user pins */
|
||||
|
||||
u8g->pin_list[U8G_PI_EN] = en;
|
||||
u8g->pin_list[U8G_PI_CS] = cs;
|
||||
u8g->pin_list[U8G_PI_DI] = di;
|
||||
u8g->pin_list[U8G_PI_RW] = rw;
|
||||
u8g->pin_list[U8G_PI_RESET] = reset;
|
||||
|
||||
return u8g_Begin(u8g);
|
||||
}
|
||||
|
||||
uint8_t u8g_Init8Bit(u8g_t *u8g, u8g_dev_t *dev, uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7,
|
||||
uint8_t en, uint8_t cs1, uint8_t cs2, uint8_t di, uint8_t rw, uint8_t reset)
|
||||
{
|
||||
|
||||
/* fill data structure with some suitable values */
|
||||
u8g_init_data(u8g);
|
||||
u8g->dev = dev;
|
||||
|
||||
/* assign user pins */
|
||||
|
||||
u8g->pin_list[U8G_PI_D0] = d0;
|
||||
u8g->pin_list[U8G_PI_D1] = d1;
|
||||
u8g->pin_list[U8G_PI_D2] = d2;
|
||||
u8g->pin_list[U8G_PI_D3] = d3;
|
||||
u8g->pin_list[U8G_PI_D4] = d4;
|
||||
u8g->pin_list[U8G_PI_D5] = d5;
|
||||
u8g->pin_list[U8G_PI_D6] = d6;
|
||||
u8g->pin_list[U8G_PI_D7] = d7;
|
||||
|
||||
u8g->pin_list[U8G_PI_EN] = en;
|
||||
u8g->pin_list[U8G_PI_CS1] = cs1;
|
||||
u8g->pin_list[U8G_PI_CS2] = cs2;
|
||||
u8g->pin_list[U8G_PI_DI] = di;
|
||||
u8g->pin_list[U8G_PI_RW] = rw;
|
||||
u8g->pin_list[U8G_PI_RESET] = reset;
|
||||
|
||||
return u8g_Begin(u8g);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
PIN_D0 8
|
||||
PIN_D1 9
|
||||
PIN_D2 10
|
||||
PIN_D3 11
|
||||
PIN_D4 4
|
||||
PIN_D5 5
|
||||
PIN_D6 6
|
||||
PIN_D7 7
|
||||
|
||||
PIN_CS 14
|
||||
PIN_A0 15
|
||||
PIN_RESET 16
|
||||
PIN_WR 17
|
||||
PIN_RD 18
|
||||
|
||||
u8g_InitRW8Bit(u8g, dev, d0, d1, d2, d3, d4, d5, d6, d7, cs, a0, wr, rd, reset)
|
||||
u8g_InitRW8Bit(u8g, dev, 8, 9, 10, 11, 4, 5, 6, 7, 14, 15, 17, 18, 16)
|
||||
|
||||
*/
|
||||
|
||||
uint8_t u8g_InitRW8Bit(u8g_t *u8g, u8g_dev_t *dev, uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7,
|
||||
uint8_t cs, uint8_t a0, uint8_t wr, uint8_t rd, uint8_t reset)
|
||||
{
|
||||
|
||||
/* fill data structure with some suitable values */
|
||||
u8g_init_data(u8g);
|
||||
u8g->dev = dev;
|
||||
|
||||
/* assign user pins */
|
||||
|
||||
u8g->pin_list[U8G_PI_D0] = d0;
|
||||
u8g->pin_list[U8G_PI_D1] = d1;
|
||||
u8g->pin_list[U8G_PI_D2] = d2;
|
||||
u8g->pin_list[U8G_PI_D3] = d3;
|
||||
u8g->pin_list[U8G_PI_D4] = d4;
|
||||
u8g->pin_list[U8G_PI_D5] = d5;
|
||||
u8g->pin_list[U8G_PI_D6] = d6;
|
||||
u8g->pin_list[U8G_PI_D7] = d7;
|
||||
|
||||
u8g->pin_list[U8G_PI_CS] = cs;
|
||||
u8g->pin_list[U8G_PI_A0] = a0;
|
||||
u8g->pin_list[U8G_PI_WR] = wr;
|
||||
u8g->pin_list[U8G_PI_RD] = rd;
|
||||
u8g->pin_list[U8G_PI_RESET] = reset;
|
||||
|
||||
return u8g_Begin(u8g);
|
||||
}
|
||||
#endif /* defined(U8G_WITH_PINLIST) */
|
||||
|
||||
void u8g_FirstPage(u8g_t *u8g)
|
||||
{
|
||||
u8g_FirstPageLL(u8g, u8g->dev);
|
||||
}
|
||||
|
||||
uint8_t u8g_NextPage(u8g_t *u8g)
|
||||
{
|
||||
if ( u8g->cursor_fn != (u8g_draw_cursor_fn)0 )
|
||||
{
|
||||
u8g->cursor_fn(u8g);
|
||||
}
|
||||
return u8g_NextPageLL(u8g, u8g->dev);
|
||||
}
|
||||
|
||||
uint8_t u8g_SetContrast(u8g_t *u8g, uint8_t contrast)
|
||||
{
|
||||
return u8g_SetContrastLL(u8g, u8g->dev, contrast);
|
||||
}
|
||||
|
||||
void u8g_SleepOn(u8g_t *u8g)
|
||||
{
|
||||
u8g_call_dev_fn(u8g, u8g->dev, U8G_DEV_MSG_SLEEP_ON, NULL);
|
||||
}
|
||||
|
||||
void u8g_SleepOff(u8g_t *u8g)
|
||||
{
|
||||
u8g_call_dev_fn(u8g, u8g->dev, U8G_DEV_MSG_SLEEP_OFF, NULL);
|
||||
}
|
||||
|
||||
|
||||
void u8g_DrawPixel(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y)
|
||||
{
|
||||
u8g_DrawPixelLL(u8g, u8g->dev, x, y);
|
||||
}
|
||||
|
||||
void u8g_Draw8Pixel(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, uint8_t dir, uint8_t pixel)
|
||||
{
|
||||
u8g_Draw8PixelLL(u8g, u8g->dev, x, y, dir, pixel);
|
||||
}
|
||||
|
||||
void u8g_Draw4TPixel(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, uint8_t dir, uint8_t pixel)
|
||||
{
|
||||
u8g_Draw4TPixelLL(u8g, u8g->dev, x, y, dir, pixel);
|
||||
}
|
||||
|
||||
|
||||
/* u8g_IsBBXIntersection() has been moved to u8g_clip.c */
|
||||
#ifdef OBSOLETE_CODE
|
||||
uint8_t u8g_IsBBXIntersection(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, u8g_uint_t w, u8g_uint_t h)
|
||||
{
|
||||
/* new code */
|
||||
u8g_dev_arg_bbx_t arg;
|
||||
arg.x = x;
|
||||
arg.y = y;
|
||||
arg.w = w;
|
||||
arg.h = h;
|
||||
return u8g_is_box_bbx_intersection(&(u8g->current_page), &arg);
|
||||
|
||||
/* old code */
|
||||
//return u8g_IsBBXIntersectionLL(u8g, u8g->dev, x, y, w, h);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
idx: index for the palette entry (0..255)
|
||||
r: value for red (0..255)
|
||||
g: value for green (0..255)
|
||||
b: value for blue (0..255)
|
||||
*/
|
||||
void u8g_SetColorEntry(u8g_t *u8g, uint8_t idx, uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
u8g_dev_arg_irgb_t irgb;
|
||||
irgb.idx = idx;
|
||||
irgb.r = r;
|
||||
irgb.g = g;
|
||||
irgb.b = b;
|
||||
u8g_call_dev_fn(u8g, u8g->dev, U8G_DEV_MSG_SET_COLOR_ENTRY, &irgb);
|
||||
}
|
||||
|
||||
void u8g_SetColorIndex(u8g_t *u8g, uint8_t idx)
|
||||
{
|
||||
u8g->arg_pixel.color = idx;
|
||||
/*u8g->color_index = idx; */ /* must be removed */
|
||||
}
|
||||
|
||||
void u8g_SetHiColor(u8g_t *u8g, uint16_t rgb)
|
||||
{
|
||||
u8g->arg_pixel.color = rgb&255;
|
||||
u8g->arg_pixel.hi_color = rgb>>8;
|
||||
/*u8g->color_index = idx; */ /* must be removed */
|
||||
}
|
||||
|
||||
void u8g_SetHiColorByRGB(u8g_t *u8g, uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
|
||||
r &= ~7;
|
||||
g >>= 2;
|
||||
b >>= 3;
|
||||
u8g->arg_pixel.color = b;
|
||||
u8g->arg_pixel.color |= (g & 7) << 5;
|
||||
u8g->arg_pixel.hi_color = r;
|
||||
u8g->arg_pixel.hi_color |= (g>>3) & 7;
|
||||
|
||||
//u8g_SetHiColor(u8g, U8G_GET_HICOLOR_BY_RGB(r,g,b));
|
||||
}
|
||||
|
||||
void u8g_SetRGB(u8g_t *u8g, uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
if ( u8g->mode == U8G_MODE_R3G3B2 )
|
||||
{
|
||||
r &= 0x0e0;
|
||||
g &= 0x0e0;
|
||||
g >>= 3;
|
||||
b >>= 6;
|
||||
u8g->arg_pixel.color = r | g | b;
|
||||
}
|
||||
else if ( u8g->mode == U8G_MODE_HICOLOR )
|
||||
{
|
||||
u8g_SetHiColorByRGB(u8g, r,g,b);
|
||||
}
|
||||
else
|
||||
{
|
||||
u8g->arg_pixel.color = r;
|
||||
u8g->arg_pixel.hi_color = g;
|
||||
u8g->arg_pixel.blue = b;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t u8g_GetColorIndex(u8g_t *u8g)
|
||||
{
|
||||
return u8g->arg_pixel.color;
|
||||
}
|
||||
|
||||
uint8_t u8g_GetDefaultForegroundColor(u8g_t *u8g)
|
||||
{
|
||||
uint8_t mode;
|
||||
mode = u8g_GetMode(u8g);
|
||||
if ( mode == U8G_MODE_R3G3B2 )
|
||||
return 255; /* white */
|
||||
else if ( u8g_GetMode(u8g) == U8G_MODE_GRAY2BIT )
|
||||
return 3; /* max intensity */
|
||||
else /* if ( u8g.getMode() == U8G_MODE_BW ) */
|
||||
return 1; /* pixel on */
|
||||
return 1;
|
||||
}
|
||||
|
||||
void u8g_SetDefaultForegroundColor(u8g_t *u8g)
|
||||
{
|
||||
if ( u8g->mode == U8G_MODE_HICOLOR )
|
||||
{
|
||||
u8g->arg_pixel.color = 0x0ff;
|
||||
u8g->arg_pixel.hi_color = 0x0ff;
|
||||
}
|
||||
else
|
||||
{
|
||||
u8g_SetColorIndex(u8g, u8g_GetDefaultForegroundColor(u8g));
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t u8g_GetDefaultBackgroundColor(u8g_t *u8g)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void u8g_SetDefaultBackgroundColor(u8g_t *u8g)
|
||||
{
|
||||
u8g_SetColorIndex(u8g, u8g_GetDefaultBackgroundColor(u8g)); /* pixel on / black */
|
||||
}
|
||||
|
||||
uint8_t u8g_GetDefaultMidColor(u8g_t *u8g)
|
||||
{
|
||||
uint8_t mode;
|
||||
mode = u8g_GetMode(u8g);
|
||||
if ( mode == U8G_MODE_R3G3B2 )
|
||||
return 0x06d; /* gray: 01101101 */
|
||||
else if ( u8g_GetMode(u8g) == U8G_MODE_GRAY2BIT )
|
||||
return 1; /* low mid intensity */
|
||||
else /* if ( u8g.getMode() == U8G_MODE_BW ) */
|
||||
return 1; /* pixel on */
|
||||
return 1; /* default */
|
||||
}
|
||||
|
||||
void u8g_SetDefaultMidColor(u8g_t *u8g)
|
||||
{
|
||||
u8g_SetColorIndex(u8g, u8g_GetDefaultMidColor(u8g));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
|
||||
u8g_page.c
|
||||
|
||||
page helper functions, only called by the dev handler.
|
||||
|
||||
Universal 8bit Graphics Library
|
||||
|
||||
Copyright (c) 2011, olikraus@gmail.com
|
||||
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 "u8g.h"
|
||||
|
||||
/*
|
||||
setup page count structure
|
||||
conditions: page_height <= total_height
|
||||
*/
|
||||
void u8g_page_Init(u8g_page_t *p, u8g_uint_t page_height, u8g_uint_t total_height )
|
||||
{
|
||||
p->page_height = page_height;
|
||||
p->total_height = total_height;
|
||||
p->page = 0;
|
||||
u8g_page_First(p);
|
||||
}
|
||||
|
||||
void u8g_page_First(u8g_page_t *p)
|
||||
{
|
||||
p->page_y0 = 0;
|
||||
p->page_y1 = p->page_height;
|
||||
p->page_y1--;
|
||||
p->page = 0;
|
||||
}
|
||||
|
||||
uint8_t u8g_page_Next(u8g_page_t * p)
|
||||
{
|
||||
register u8g_uint_t y1;
|
||||
p->page_y0 += p->page_height;
|
||||
if ( p->page_y0 >= p->total_height )
|
||||
return 0;
|
||||
p->page++;
|
||||
y1 = p->page_y1;
|
||||
y1 += p->page_height;
|
||||
if ( y1 >= p->total_height )
|
||||
{
|
||||
y1 = p->total_height;
|
||||
y1--;
|
||||
}
|
||||
p->page_y1 = y1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,191 @@
|
||||
/*
|
||||
|
||||
u8g_pb.c
|
||||
|
||||
common procedures for the page buffer
|
||||
|
||||
Universal 8bit Graphics Library
|
||||
|
||||
Copyright (c) 2011, olikraus@gmail.com
|
||||
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 "u8g.h"
|
||||
|
||||
void u8g_pb_Clear(u8g_pb_t *b)
|
||||
{
|
||||
uint8_t *ptr = (uint8_t *)b->buf;
|
||||
uint8_t *end_ptr = ptr;
|
||||
end_ptr += b->width;
|
||||
do
|
||||
{
|
||||
*ptr++ = 0;
|
||||
} while( ptr != end_ptr );
|
||||
}
|
||||
|
||||
/* the following procedure does not work. why? Can be checked with descpic */
|
||||
/*
|
||||
void u8g_pb_Clear(u8g_pb_t *b)
|
||||
{
|
||||
uint8_t *ptr = (uint8_t *)b->buf;
|
||||
uint8_t cnt = b->width;
|
||||
do
|
||||
{
|
||||
*ptr++ = 0;
|
||||
cnt--;
|
||||
} while( cnt != 0 );
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
intersection assumptions:
|
||||
a1 <= a2 is always true
|
||||
*/
|
||||
/*
|
||||
minimized version
|
||||
---1----0 1 b1 <= a2 && b1 > b2
|
||||
-----1--0 1 b2 >= a1 && b1 > b2
|
||||
---1-1--- 1 b1 <= a2 && b2 >= a1
|
||||
*/
|
||||
/*
|
||||
uint8_t u8g_pb8v1_IsYIntersection___Old(u8g_pb_t *b, u8g_uint_t v0, u8g_uint_t v1)
|
||||
{
|
||||
uint8_t c0, c1, c;
|
||||
c0 = v0 <= b->p.page_y1;
|
||||
c1 = v1 >= b->p.page_y0;
|
||||
c = v0 > v1;
|
||||
if ( c0 && c1 ) return 1;
|
||||
if ( c0 && c ) return 1;
|
||||
if ( c1 && c ) return 1;
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
uint8_t u8g_pb_IsYIntersection(u8g_pb_t *pb, u8g_uint_t v0, u8g_uint_t v1)
|
||||
{
|
||||
uint8_t c1, c2, c3, tmp;
|
||||
c1 = v0 <= pb->p.page_y1;
|
||||
c2 = v1 >= pb->p.page_y0;
|
||||
c3 = v0 > v1;
|
||||
/*
|
||||
if ( c1 && c2 )
|
||||
return 1;
|
||||
if ( c1 && c3 )
|
||||
return 1;
|
||||
if ( c2 && c3 )
|
||||
return 1;
|
||||
return 0;
|
||||
*/
|
||||
|
||||
tmp = c1;
|
||||
c1 &= c2;
|
||||
c2 &= c3;
|
||||
c3 &= tmp;
|
||||
c1 |= c2;
|
||||
c1 |= c3;
|
||||
return c1 & 1;
|
||||
}
|
||||
|
||||
|
||||
uint8_t u8g_pb_IsXIntersection(u8g_pb_t *b, u8g_uint_t v0, u8g_uint_t v1)
|
||||
{
|
||||
uint8_t /*c0, c1, */ c2, c3;
|
||||
/*
|
||||
conditions: b->p.page_y0 < b->p.page_y1
|
||||
there are no restriction on v0 and v1. If v0 > v1, then warp around unsigned is assumed
|
||||
*/
|
||||
/*
|
||||
c0 = v0 < 0;
|
||||
c1 = v1 < 0;
|
||||
*/
|
||||
c2 = v0 > b->width;
|
||||
c3 = v1 > b->width;
|
||||
/*if ( c0 && c1 ) return 0;*/
|
||||
if ( c2 && c3 ) return 0;
|
||||
/*if ( c1 && c2 ) return 0;*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t u8g_pb_IsIntersection(u8g_pb_t *pb, u8g_dev_arg_bbx_t *bbx)
|
||||
{
|
||||
u8g_uint_t tmp;
|
||||
|
||||
tmp = bbx->y;
|
||||
tmp += bbx->h;
|
||||
tmp--;
|
||||
|
||||
if ( u8g_pb_IsYIntersection(pb, bbx->y, tmp) == 0 )
|
||||
return 0;
|
||||
|
||||
/* maybe this one can be skiped... probability is very high to have an intersection, so it would be ok to always return 1 */
|
||||
tmp = bbx->x;
|
||||
tmp += bbx->w;
|
||||
tmp--;
|
||||
|
||||
return u8g_pb_IsXIntersection(pb, bbx->x, tmp);
|
||||
}
|
||||
|
||||
void u8g_pb_GetPageBox(u8g_pb_t *pb, u8g_box_t *box)
|
||||
{
|
||||
box->x0 = 0;
|
||||
box->y0 = pb->p.page_y0;
|
||||
box->x1 = pb->width;
|
||||
box->x1--;
|
||||
box->y1 = pb->p.page_y1;
|
||||
}
|
||||
|
||||
|
||||
uint8_t u8g_pb_Is8PixelVisible(u8g_pb_t *b, u8g_dev_arg_pixel_t *arg_pixel)
|
||||
{
|
||||
u8g_uint_t v0, v1;
|
||||
v0 = arg_pixel->y;
|
||||
v1 = v0;
|
||||
switch( arg_pixel->dir )
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
v1 += 8; /* this is independent from the page height */
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
v0 -= 8;
|
||||
break;
|
||||
}
|
||||
return u8g_pb_IsYIntersection(b, v0, v1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint8_t u8g_pb_WriteBuffer(u8g_pb_t *b, u8g_t *u8g, u8g_dev_t *dev)
|
||||
{
|
||||
return u8g_WriteSequence(u8g, dev, b->width, b->buf);
|
||||
}
|
||||
|
@ -0,0 +1,213 @@
|
||||
/*
|
||||
|
||||
u8g_pb16h1.c
|
||||
|
||||
2x 8bit height monochrom (1 bit) page buffer
|
||||
byte has horizontal orientation
|
||||
|
||||
Universal 8bit Graphics Library
|
||||
|
||||
Copyright (c) 2012, olikraus@gmail.com
|
||||
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.
|
||||
|
||||
|
||||
total buffer size is limited to 2*256 bytes because of the calculation inside the set pixel procedure
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#include "u8g.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
void u8g_pb16h1_Init(u8g_pb_t *b, void *buf, u8g_uint_t width) U8G_NOINLINE;
|
||||
void u8g_pb16h1_set_pixel(u8g_pb_t *b, u8g_uint_t x, u8g_uint_t y, uint8_t color_index) U8G_NOINLINE;
|
||||
void u8g_pb16h1_SetPixel(u8g_pb_t *b, const u8g_dev_arg_pixel_t * const arg_pixel) U8G_NOINLINE ;
|
||||
void u8g_pb16h1_Set8PixelStd(u8g_pb_t *b, u8g_dev_arg_pixel_t *arg_pixel) U8G_NOINLINE;
|
||||
uint8_t u8g_dev_pb8h1_base_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg);
|
||||
|
||||
void u8g_pb16h1_Clear(u8g_pb_t *b)
|
||||
{
|
||||
uint8_t *ptr = (uint8_t *)b->buf;
|
||||
uint8_t *end_ptr = ptr;
|
||||
end_ptr += b->width*2;
|
||||
do
|
||||
{
|
||||
*ptr++ = 0;
|
||||
} while( ptr != end_ptr );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void u8g_pb16h1_Init(u8g_pb_t *b, void *buf, u8g_uint_t width)
|
||||
{
|
||||
b->buf = buf;
|
||||
b->width = width;
|
||||
u8g_pb16h1_Clear(b);
|
||||
}
|
||||
|
||||
|
||||
/* limitation: total buffer must not exceed 2*256 bytes */
|
||||
void u8g_pb16h1_set_pixel(u8g_pb_t *b, u8g_uint_t x, u8g_uint_t y, uint8_t color_index)
|
||||
{
|
||||
register uint8_t mask;
|
||||
u8g_uint_t tmp;
|
||||
uint8_t *ptr = b->buf;
|
||||
|
||||
y -= b->p.page_y0;
|
||||
if ( y >= 8 )
|
||||
{
|
||||
ptr += b->width;
|
||||
y &= 0x07;
|
||||
}
|
||||
tmp = b->width;
|
||||
tmp >>= 3;
|
||||
tmp *= (uint8_t)y;
|
||||
ptr += tmp;
|
||||
|
||||
mask = 0x080;
|
||||
mask >>= x & 7;
|
||||
x >>= 3;
|
||||
ptr += x;
|
||||
if ( color_index )
|
||||
{
|
||||
*ptr |= mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask ^=0xff;
|
||||
*ptr &= mask;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void u8g_pb16h1_SetPixel(u8g_pb_t *b, const u8g_dev_arg_pixel_t * const arg_pixel)
|
||||
{
|
||||
if ( arg_pixel->y < b->p.page_y0 )
|
||||
return;
|
||||
if ( arg_pixel->y > b->p.page_y1 )
|
||||
return;
|
||||
if ( arg_pixel->x >= b->width )
|
||||
return;
|
||||
u8g_pb16h1_set_pixel(b, arg_pixel->x, arg_pixel->y, arg_pixel->color);
|
||||
}
|
||||
|
||||
void u8g_pb16h1_Set8PixelStd(u8g_pb_t *b, u8g_dev_arg_pixel_t *arg_pixel)
|
||||
{
|
||||
register uint8_t pixel = arg_pixel->pixel;
|
||||
do
|
||||
{
|
||||
if ( pixel & 128 )
|
||||
{
|
||||
u8g_pb16h1_SetPixel(b, arg_pixel);
|
||||
}
|
||||
switch( arg_pixel->dir )
|
||||
{
|
||||
case 0: arg_pixel->x++; break;
|
||||
case 1: arg_pixel->y++; break;
|
||||
case 2: arg_pixel->x--; break;
|
||||
case 3: arg_pixel->y--; break;
|
||||
}
|
||||
pixel <<= 1;
|
||||
} while( pixel != 0 );
|
||||
}
|
||||
|
||||
void u8g_pb16h1_Set8PixelOpt2(u8g_pb_t *b, u8g_dev_arg_pixel_t *arg_pixel)
|
||||
{
|
||||
register uint8_t pixel = arg_pixel->pixel;
|
||||
u8g_uint_t dx = 0;
|
||||
u8g_uint_t dy = 0;
|
||||
|
||||
switch( arg_pixel->dir )
|
||||
{
|
||||
case 0: dx++; break;
|
||||
case 1: dy++; break;
|
||||
case 2: dx--; break;
|
||||
case 3: dy--; break;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if ( pixel & 128 )
|
||||
u8g_pb16h1_SetPixel(b, arg_pixel);
|
||||
arg_pixel->x += dx;
|
||||
arg_pixel->y += dy;
|
||||
pixel <<= 1;
|
||||
} while( pixel != 0 );
|
||||
}
|
||||
|
||||
|
||||
uint8_t u8g_dev_pb16h1_base_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg)
|
||||
{
|
||||
u8g_pb_t *pb = (u8g_pb_t *)(dev->dev_mem);
|
||||
switch(msg)
|
||||
{
|
||||
case U8G_DEV_MSG_SET_8PIXEL:
|
||||
if ( u8g_pb_Is8PixelVisible(pb, (u8g_dev_arg_pixel_t *)arg) )
|
||||
u8g_pb16h1_Set8PixelOpt2(pb, (u8g_dev_arg_pixel_t *)arg);
|
||||
break;
|
||||
case U8G_DEV_MSG_SET_PIXEL:
|
||||
u8g_pb16h1_SetPixel(pb, (u8g_dev_arg_pixel_t *)arg);
|
||||
break;
|
||||
case U8G_DEV_MSG_INIT:
|
||||
break;
|
||||
case U8G_DEV_MSG_STOP:
|
||||
break;
|
||||
case U8G_DEV_MSG_PAGE_FIRST:
|
||||
u8g_pb16h1_Clear(pb);
|
||||
u8g_page_First(&(pb->p));
|
||||
break;
|
||||
case U8G_DEV_MSG_PAGE_NEXT:
|
||||
if ( u8g_page_Next(&(pb->p)) == 0 )
|
||||
return 0;
|
||||
u8g_pb16h1_Clear(pb);
|
||||
break;
|
||||
#ifdef U8G_DEV_MSG_IS_BBX_INTERSECTION
|
||||
case U8G_DEV_MSG_IS_BBX_INTERSECTION:
|
||||
return u8g_pb_IsIntersection(pb, (u8g_dev_arg_bbx_t *)arg);
|
||||
#endif
|
||||
case U8G_DEV_MSG_GET_PAGE_BOX:
|
||||
u8g_pb_GetPageBox(pb, (u8g_box_t *)arg);
|
||||
break;
|
||||
case U8G_DEV_MSG_GET_WIDTH:
|
||||
*((u8g_uint_t *)arg) = pb->width;
|
||||
break;
|
||||
case U8G_DEV_MSG_GET_HEIGHT:
|
||||
*((u8g_uint_t *)arg) = pb->p.total_height;
|
||||
break;
|
||||
case U8G_DEV_MSG_SET_COLOR_ENTRY:
|
||||
break;
|
||||
case U8G_DEV_MSG_SET_XY_CB:
|
||||
break;
|
||||
case U8G_DEV_MSG_GET_MODE:
|
||||
return U8G_MODE_BW;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,232 @@
|
||||
/*
|
||||
|
||||
u8g_rect.c
|
||||
|
||||
U8G high level interface for horizontal and vertical things
|
||||
|
||||
Universal 8bit Graphics Library
|
||||
|
||||
Copyright (c) 2011, olikraus@gmail.com
|
||||
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 "u8g.h"
|
||||
|
||||
void u8g_draw_hline(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, u8g_uint_t w)
|
||||
{
|
||||
uint8_t pixel = 0x0ff;
|
||||
while( w >= 8 )
|
||||
{
|
||||
u8g_Draw8Pixel(u8g, x, y, 0, pixel);
|
||||
w-=8;
|
||||
x+=8;
|
||||
}
|
||||
if ( w != 0 )
|
||||
{
|
||||
w ^=7;
|
||||
w++;
|
||||
pixel <<= w&7;
|
||||
u8g_Draw8Pixel(u8g, x, y, 0, pixel);
|
||||
}
|
||||
}
|
||||
|
||||
void u8g_draw_vline(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, u8g_uint_t h)
|
||||
{
|
||||
uint8_t pixel = 0x0ff;
|
||||
while( h >= 8 )
|
||||
{
|
||||
u8g_Draw8Pixel(u8g, x, y, 1, pixel);
|
||||
h-=8;
|
||||
y+=8;
|
||||
}
|
||||
if ( h != 0 )
|
||||
{
|
||||
h ^=7;
|
||||
h++;
|
||||
pixel <<= h&7;
|
||||
u8g_Draw8Pixel(u8g, x, y, 1, pixel);
|
||||
}
|
||||
}
|
||||
|
||||
void u8g_DrawHLine(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, u8g_uint_t w)
|
||||
{
|
||||
if ( u8g_IsBBXIntersection(u8g, x, y, w, 1) == 0 )
|
||||
return;
|
||||
u8g_draw_hline(u8g, x, y, w);
|
||||
}
|
||||
|
||||
void u8g_DrawVLine(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, u8g_uint_t w)
|
||||
{
|
||||
if ( u8g_IsBBXIntersection(u8g, x, y, 1, w) == 0 )
|
||||
return;
|
||||
u8g_draw_vline(u8g, x, y, w);
|
||||
}
|
||||
|
||||
/* restrictions: w > 0 && h > 0 */
|
||||
void u8g_DrawFrame(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, u8g_uint_t w, u8g_uint_t h)
|
||||
{
|
||||
u8g_uint_t xtmp = x;
|
||||
|
||||
if ( u8g_IsBBXIntersection(u8g, x, y, w, h) == 0 )
|
||||
return;
|
||||
|
||||
|
||||
u8g_draw_hline(u8g, x, y, w);
|
||||
u8g_draw_vline(u8g, x, y, h);
|
||||
x+=w;
|
||||
x--;
|
||||
u8g_draw_vline(u8g, x, y, h);
|
||||
y+=h;
|
||||
y--;
|
||||
u8g_draw_hline(u8g, xtmp, y, w);
|
||||
}
|
||||
|
||||
void u8g_draw_box(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, u8g_uint_t w, u8g_uint_t h)
|
||||
{
|
||||
do
|
||||
{
|
||||
u8g_draw_hline(u8g, x, y, w);
|
||||
y++;
|
||||
h--;
|
||||
} while( h != 0 );
|
||||
}
|
||||
|
||||
/* restrictions: h > 0 */
|
||||
void u8g_DrawBox(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, u8g_uint_t w, u8g_uint_t h)
|
||||
{
|
||||
if ( u8g_IsBBXIntersection(u8g, x, y, w, h) == 0 )
|
||||
return;
|
||||
u8g_draw_box(u8g, x, y, w, h);
|
||||
}
|
||||
|
||||
|
||||
void u8g_DrawRFrame(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, u8g_uint_t w, u8g_uint_t h, u8g_uint_t r)
|
||||
{
|
||||
u8g_uint_t xl, yu;
|
||||
|
||||
if ( u8g_IsBBXIntersection(u8g, x, y, w, h) == 0 )
|
||||
return;
|
||||
|
||||
xl = x;
|
||||
xl += r;
|
||||
yu = y;
|
||||
yu += r;
|
||||
|
||||
{
|
||||
u8g_uint_t yl, xr;
|
||||
|
||||
xr = x;
|
||||
xr += w;
|
||||
xr -= r;
|
||||
xr -= 1;
|
||||
|
||||
yl = y;
|
||||
yl += h;
|
||||
yl -= r;
|
||||
yl -= 1;
|
||||
|
||||
u8g_draw_circle(u8g, xl, yu, r, U8G_DRAW_UPPER_LEFT);
|
||||
u8g_draw_circle(u8g, xr, yu, r, U8G_DRAW_UPPER_RIGHT);
|
||||
u8g_draw_circle(u8g, xl, yl, r, U8G_DRAW_LOWER_LEFT);
|
||||
u8g_draw_circle(u8g, xr, yl, r, U8G_DRAW_LOWER_RIGHT);
|
||||
}
|
||||
|
||||
{
|
||||
u8g_uint_t ww, hh;
|
||||
|
||||
ww = w;
|
||||
ww -= r;
|
||||
ww -= r;
|
||||
ww -= 2;
|
||||
hh = h;
|
||||
hh -= r;
|
||||
hh -= r;
|
||||
hh -= 2;
|
||||
|
||||
xl++;
|
||||
yu++;
|
||||
h--;
|
||||
w--;
|
||||
u8g_draw_hline(u8g, xl, y, ww);
|
||||
u8g_draw_hline(u8g, xl, y+h, ww);
|
||||
u8g_draw_vline(u8g, x, yu, hh);
|
||||
u8g_draw_vline(u8g, x+w, yu, hh);
|
||||
}
|
||||
}
|
||||
|
||||
void u8g_DrawRBox(u8g_t *u8g, u8g_uint_t x, u8g_uint_t y, u8g_uint_t w, u8g_uint_t h, u8g_uint_t r)
|
||||
{
|
||||
u8g_uint_t xl, yu;
|
||||
u8g_uint_t yl, xr;
|
||||
|
||||
if ( u8g_IsBBXIntersection(u8g, x, y, w, h) == 0 )
|
||||
return;
|
||||
|
||||
xl = x;
|
||||
xl += r;
|
||||
yu = y;
|
||||
yu += r;
|
||||
|
||||
xr = x;
|
||||
xr += w;
|
||||
xr -= r;
|
||||
xr -= 1;
|
||||
|
||||
yl = y;
|
||||
yl += h;
|
||||
yl -= r;
|
||||
yl -= 1;
|
||||
|
||||
u8g_draw_disc(u8g, xl, yu, r, U8G_DRAW_UPPER_LEFT);
|
||||
u8g_draw_disc(u8g, xr, yu, r, U8G_DRAW_UPPER_RIGHT);
|
||||
u8g_draw_disc(u8g, xl, yl, r, U8G_DRAW_LOWER_LEFT);
|
||||
u8g_draw_disc(u8g, xr, yl, r, U8G_DRAW_LOWER_RIGHT);
|
||||
|
||||
{
|
||||
u8g_uint_t ww, hh;
|
||||
|
||||
ww = w;
|
||||
ww -= r;
|
||||
ww -= r;
|
||||
ww -= 2;
|
||||
hh = h;
|
||||
hh -= r;
|
||||
hh -= r;
|
||||
hh -= 2;
|
||||
|
||||
xl++;
|
||||
yu++;
|
||||
h--;
|
||||
u8g_draw_box(u8g, xl, y, ww, r+1);
|
||||
u8g_draw_box(u8g, xl, yl, ww, r+1);
|
||||
//u8g_draw_hline(u8g, xl, y+h, ww);
|
||||
u8g_draw_box(u8g, x, yu, w, hh);
|
||||
//u8g_draw_vline(u8g, x+w, yu, hh);
|
||||
}
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
/*
|
||||
|
||||
u8g_state.c
|
||||
|
||||
backup and restore hardware state
|
||||
|
||||
Universal 8bit Graphics Library
|
||||
|
||||
Copyright (c) 2011, olikraus@gmail.com
|
||||
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.
|
||||
|
||||
|
||||
state callback: backup env U8G_STATE_MSG_BACKUP_ENV
|
||||
device callback: DEV_MSG_INIT
|
||||
state callback: backup u8g U8G_STATE_MSG_BACKUP_U8G
|
||||
state callback: restore env U8G_STATE_MSG_RESTORE_ENV
|
||||
|
||||
state callback: backup env U8G_STATE_MSG_BACKUP_ENV
|
||||
state callback: retore u8g U8G_STATE_MSG_RESTORE_U8G
|
||||
DEV_MSG_PAGE_FIRST or DEV_MSG_PAGE_NEXT
|
||||
state callback: restore env U8G_STATE_MSG_RESTORE_ENV
|
||||
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include "u8g.h"
|
||||
|
||||
void u8g_state_dummy_cb(uint8_t msg)
|
||||
{
|
||||
/* the dummy procedure does nothing */
|
||||
}
|
||||
|
||||
void u8g_SetHardwareBackup(u8g_t *u8g, u8g_state_cb backup_cb)
|
||||
{
|
||||
u8g->state_cb = backup_cb;
|
||||
/* in most cases the init message was already sent, so this will backup the */
|
||||
/* current u8g state */
|
||||
backup_cb(U8G_STATE_MSG_BACKUP_U8G);
|
||||
}
|
||||
|
||||
|
||||
/*===============================================================*/
|
||||
/* register variable for restoring interrupt state */
|
||||
|
||||
#if defined(__AVR__)
|
||||
uint8_t global_SREG_backup;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*===============================================================*/
|
||||
/* AVR */
|
||||
|
||||
#if defined(__AVR__)
|
||||
#define U8G_ATMEGA_HW_SPI
|
||||
|
||||
/* remove the definition for attiny */
|
||||
#if __AVR_ARCH__ == 2
|
||||
#undef U8G_ATMEGA_HW_SPI
|
||||
#endif
|
||||
#if __AVR_ARCH__ == 25
|
||||
#undef U8G_ATMEGA_HW_SPI
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(U8G_ATMEGA_HW_SPI)
|
||||
#include <avr/interrupt.h>
|
||||
static uint8_t u8g_state_avr_spi_memory[2];
|
||||
|
||||
void u8g_backup_spi(uint8_t msg)
|
||||
{
|
||||
if ( U8G_STATE_MSG_IS_BACKUP(msg) )
|
||||
{
|
||||
u8g_state_avr_spi_memory[U8G_STATE_MSG_GET_IDX(msg)] = SPCR;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t tmp = SREG;
|
||||
cli();
|
||||
SPCR = 0;
|
||||
SPCR = u8g_state_avr_spi_memory[U8G_STATE_MSG_GET_IDX(msg)];
|
||||
SREG = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(ARDUINO) && defined(__arm__) // Arduino Due, maybe we should better check for __SAM3X8E__
|
||||
|
||||
#include "sam.h"
|
||||
|
||||
struct sam_backup_struct
|
||||
{
|
||||
uint32_t mr;
|
||||
uint32_t sr;
|
||||
uint32_t csr[4];
|
||||
} sam_backup[2];
|
||||
|
||||
void u8g_backup_spi(uint8_t msg)
|
||||
{
|
||||
uint8_t idx = U8G_STATE_MSG_GET_IDX(msg);
|
||||
if ( U8G_STATE_MSG_IS_BACKUP(msg) )
|
||||
{
|
||||
sam_backup[idx].mr = SPI0->SPI_MR;
|
||||
sam_backup[idx].sr = SPI0->SPI_SR;
|
||||
sam_backup[idx].csr[0] = SPI0->SPI_CSR[0];
|
||||
sam_backup[idx].csr[1] = SPI0->SPI_CSR[1];
|
||||
sam_backup[idx].csr[2] = SPI0->SPI_CSR[2];
|
||||
sam_backup[idx].csr[3] = SPI0->SPI_CSR[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
SPI0->SPI_MR = sam_backup[idx].mr;
|
||||
SPI0->SPI_CSR[0] = sam_backup[idx].csr[0];
|
||||
SPI0->SPI_CSR[1] = sam_backup[idx].csr[1];
|
||||
SPI0->SPI_CSR[2] = sam_backup[idx].csr[2];
|
||||
SPI0->SPI_CSR[3] = sam_backup[idx].csr[3];
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void u8g_backup_spi(uint8_t msg)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in new issue