#include "units/ieee485.hpp"
#include "units/led.hpp"
#include "units/lcd.hpp"
-
-
-// #include "units/switch.hpp"
-// #include "units/rgb.hpp"
-// #include "units/seg7.hpp"
-// #include "units/poti.hpp"
-// #include "units/r2r.hpp"
-// #include "units/motor.hpp"
-// #include "units/portexp.hpp"
-// #include "units/uart1.hpp"
-// #include "units/modbus.hpp"
-
-
-
+#include "units/switch.hpp"
+#include "units/rgb.hpp"
+#include "units/seg7.hpp"
+#include "units/poti.hpp"
+#include "units/r2r.hpp"
+#include "units/motor.hpp"
+#include "units/portexp.hpp"
+#include "units/uart1.hpp"
+#include "units/modbus.hpp"
extern "C" {
void __cxa_pure_virtual () {
static volatile int keyUart0 = EOF;
Led led;
- // Switch sw;
- // Rgb rgb;
- // Seg7 seg7;
- // Poti poti;
+ Switch sw;
+ Rgb rgb;
+ Seg7 seg7;
+ Poti poti;
Encoder encoder;
- // R2r r2r;
- // Motor motor;
- // PortExp portExp;
+ R2r r2r;
+ Motor motor;
+ PortExp portExp;
Lcd lcd;
- // Uart1 uart1;
- // Modbus modbus;
+ Uart1 uart1;
+ Modbus modbus;
Ieee485 ieee485;
I2c i2cSparkfun(I2c::SparkFunEnvCombo);
I2c i2cMaster(I2c::Master);
int main () {
+ #ifdef __AVR_ATmega644P__
// Nano-644 LEDs (Green, Orange, Red)
DDRC |= (1 << DDC4) | (1 << DDC3) | (1 << DDC2);
PORTC &= ~((1 << PORT4) | (1 << PORT3) | (1 << PORT2));
// Nano-644 push button SW2
DDRC &= ~(1 << DDC5);
PORTC |= (1 << PORT5); // enable internal pullup resistor
+ #endif
+
+ #ifdef __AVR_ATmega328P__
+ DDRB |= (1 << PB5);
+ PORTB &= ~(1 << PB5);
+ #endif
// UART0 interface on Nano-644
UCSR0A = (1 << U2X0);
sei();
- // TestUnit *unit[] = {
- // &led, &sw, &rgb, &seg7, &poti, &encoder, &r2r, &motor, &portExp, &lcd, &uart1, &modbus, &ieee485,
- // &i2cMaster, &i2cSlave, &i2cSparkfun
- // };
+ #ifdef __AVR_ATmega644P__
+ TestUnit *unit[] = {
+ &led, &sw, &rgb, &seg7, &poti, &encoder, &r2r, &motor, &portExp, &lcd, &uart1, &modbus, &ieee485,
+ &i2cMaster, &i2cSlave, &i2cSparkfun
+ };
+ #endif
- TestUnit *unit[] = {
- &led, &encoder, &lcd,
- &i2cMaster, &i2cSlave, &i2cSparkfun
- };
+ #ifdef __AVR_ATmega328P__
+ TestUnit *unit[] = {
+ &led, &sw, &rgb, &seg7, &poti, &encoder, &r2r, &motor, &lcd,
+ &i2cMaster, &i2cSlave, &i2cSparkfun
+ };
+ #endif
while (1) {
uint16_t i;
} while (sscanf(s, "%x", &i) != 1 || i < 0 || i >= sizeof(unit) / sizeof(unit[0]) );
TestUnit *pu = unit[i];
- printf_P(PSTR("\n\n[%s]: "), pu->getName());
+ printf_P(PSTR("\n\n[")); printf_P(pu->getName()); printf_P(PSTR("]: "));
keyUart0 = EOF;
+ pu->init();
for (uint8_t subtest = 0; subtest < 0xff; subtest++) {
printf_P(PSTR("\n%4d: "), subtest);
if (pu->run(subtest) < 0) {
if (encoder.enabled) {
encoder.tick100us();
}
- #ifdef MOTOR_HPP
- if (motor.enabled) {
- motor.tick100us();
- }
- #endif
+ if (motor.enabled) {
+ motor.tick100us();
+ }
timer100us++;
if (timer100us >= 10) {
timer500ms++;
if (timer500ms >= 5000) {
- PORTC ^= (1 << PORTC3); // orange LED blinking
+ #ifdef __AVR_ATmega644P__
+ PORTC ^= (1 << PC3); // orange LED blinking
+ #endif
+ #ifdef __AVR_ATmega328P__
+ if (!seg7.enabled) {
+ PORTB ^= (1 << PB5); // LED L
+ }
+ #endif
timer500ms = 0;
}
}
class TestUnit {
public:
virtual int8_t run (uint8_t subtest) = 0;
+ virtual void init () = 0;
virtual void cleanup () = 0;
virtual PGM_P getName () = 0;
};
#include "encoder.hpp"
#include "../main.hpp"
-// PB0/T0 ... Encoder A
-// PB1/T1 ... Encoder B
-// PB2/INT2 ... push switch of encoder (pushed = 0)
-
// Encoder signals on rotation clockwise 1 step:
// A -----____------ one char app. 1ms..2ms (rotation speed)
// B -------___-----
// B --______-----
// one step when: A = 0, B= 0->1
+#ifdef __AVR_ATmega644P__
+
+ // Nano-644
+ // ---------------------------------------------------------------
+ // PB0/T0 ... Encoder A
+ // PB1/T1 ... Encoder B
+ // PB2/INT2 ... push switch of encoder (pushed = 0)
+
+ void Encoder::init () {
+ DDRB &= ~((1 << PB2) | (1 << PB1) | (1 << PB0));
+ PORTB |= (1 << PORTB2) | (1 << PORTB1) | (1 << PORTB0); // enable pullup
+ enabled = 1;
+ }
+
+ void Encoder::cleanup () {
+ enabled = 0;
+ DDRB &= ~((1 << PB2) | (1 << PB1) | (1 << PB0));
+ PORTB &= ~((1 << PORTB2) | (1 << PORTB1) | (1 << PORTB0));
+ }
+
+ bool Encoder::isPressed () {
+ return (PINB & (1 << PB2)) == 0;
+ }
+
+ bool Encoder::getA () {
+ return (PINB & (1 << PB0)) == 0;
+ }
+
+ bool Encoder::getB () {
+ return (PINB & (1 << PB1)) == 0;
+ }
+
+
+#endif
+
+#ifdef __AVR_ATmega328P__
+
+ // Arduino-Nano-5V
+ // ---------------------------------------------------------------
+ // PD4/T0 ... Encoder A
+ // PB0 ... Encoder B
+ // PD7 ... push switch of encoder (pushed = 0)
+
+ void Encoder::init () {
+ DDRB &= ~(1 << PB0);
+ DDRD &= ~((1 << PD7) | (1 << PD4));
+ PORTB |= (1 << PB0); // enable pullup
+ PORTD |= (1 << PD7) | (1 << PD4); // enable pullup
+ enabled = 1;
+ }
+
+ void Encoder::cleanup () {
+ enabled = 0;
+ PORTB &= ~(1 << PB0);
+ PORTD &= ~((1 << PD7) | (1 << PD4));
+ DDRB &= ~(1 << PB0);
+ DDRD &= ~((1 << PD7) | (1 << PD4));
+ }
+
+ bool Encoder::isPressed () {
+ return (PIND & (1 << PD7)) == 0;
+ }
+
+ bool Encoder::getA () {
+ return (PIND & (1 << PD4)) == 0;
+ }
+
+ bool Encoder::getB () {
+ return (PINB & (1 << PB0)) == 0;
+ }
+
+#endif
-void Encoder::cleanup () {
- DDRB &= ~((1 << PB2) | (1 << PB1) | (1 << PB0));
- PORTB &= ~((1 << PORTB2) | (1 << PORTB1) | (1 << PORTB0));
- enabled = 0;
-}
int8_t Encoder::run (uint8_t subtest) {
switch (subtest) {
case 0: {
- printf_P(PSTR("init"));
- DDRB &= ~((1 << PB2) | (1 << PB1) | (1 << PB0));
- PORTB |= (1 << PORTB2) | (1 << PORTB1) | (1 << PORTB0); // enable pullup
- enabled = 1;
- return 0;
- }
-
- case 1: {
while (wait(10) == EOF) {
printf_P(PSTR("\r => Encoder (push to clear): "));
printf_P(PSTR("%5d (0x%02x) "), count, (uint8_t)count);
- if ((PINB & (1 << PINB2)) == 0) {
+ if (isPressed()) {
reset();
}
}
return 0;
}
-
- case 2: {
- printf_P(PSTR("end"));
- break;
- }
}
return -1;
}
struct EncoderState {
- uint8_t a:1; // signal A
- uint8_t b:1; // signal B
+ int8_t a:1; // signal A
+ int8_t b:1; // signal B
};
void Encoder::tick100us () {
static EncoderState lastState = { 1, 1 };
static EncoderState lastStableState = { 1, 1 };
- if ((DDRB & 0x03) || (PORTB & 0x07) != 0x07) {
+ if (!enabled) {
count = 0;
- return; // Enocder pins not configured
+ return;
}
- EncoderState nextState = { (PINB & 0x01) == 0x01, (PINB & 0x02) == 0x02 };
+ EncoderState nextState;
+ nextState.a = getA() ? 1 : 0;
+ nextState.b = getB() ? 1 : 0;
if (nextState.a == lastState.a && nextState.b == lastState.b) {
if (lastStableState.a == 0 && nextState.b != lastStableState.b) {
if (nextState.b == 0) {
public:
Encoder () { reset(); enabled = 0; };
+ virtual void init ();
virtual void cleanup ();
virtual int8_t run (uint8_t subtest);
virtual PGM_P getName () { return PSTR("Encoder"); }
void reset () { count = 0; }
void tick100us ();
+ bool isPressed ();
+
+ private:
+ bool getA ();
+ bool getB ();
};
#endif
\ No newline at end of file
return "?";
}
+void I2c::init () {
+ TWBR = 13; // 100kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 100000) / (2 * 100000 * 4);
+ TWBR = 28; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4);
+ TWBR = 100; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4);
+ TWCR = (1 << TWEN);
+ ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V
+ ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128
+ enabled = true;
+}
+
void I2c::cleanup () {
enabled = false;
TWCR = (1 << TWEN);
}
int8_t I2c::run (uint8_t subtest) {
- if (subtest == 0) {
- TWBR = 13; // 100kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 100000) / (2 * 100000 * 4);
- TWBR = 28; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4);
- TWBR = 100; // 50kHz (TWPS1:0 = 00), TWBR = (F_CPU - 16 * 50000) / (2 * 50000 * 4);
- TWCR = (1 << TWEN);
- ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V
- ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128
- enabled = true;
- printf_P(PSTR("init"));
-
- } else if (subtest == 1 && mode == I2c::SparkFunEnvCombo) {
+ if (subtest == 0 && mode == I2c::SparkFunEnvCombo) {
printf_P(PSTR(" BM280 ... "));
if (!bm280.begin()) {
printf_P(PSTR("E1"));
} while (wait(1000) == EOF);
- } else if (subtest == 1 && mode == I2c::Master) {
+ } else if (subtest == 0 && mode == I2c::Master) {
if (!master.begin(0x01)) {
printf_P(PSTR("E1"));
return -1;
} while (wait(1000) == EOF);
master.end();
- } else if (subtest == 1 && mode == I2c::Slave) {
+ } else if (subtest == 0 && mode == I2c::Slave) {
if (!slave.begin(0x01, false)) {
printf_P(PSTR("E1"));
return -1;
TWCR |= (1 << TWINT); // clear Interrupt Request
}
}
-
-// uint16_t I2c::startRead (uint8_t address) {
-// TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // send START condition
-// while (!(TWCR & (1 << TWINT))) {}; // wait until last action done
-// uint8_t sr = TWSR & 0xf8;
-// if (sr != 0x08 && sr != 0x10) {
-// return 0x0100 | sr;
-// }
-
-// TWDR = (address << 1) | 0x01; // address + READ (R/W = 1)
-// TWCR = (1 << TWINT) | (1 << TWEN); // send address/RW
-// while (!(TWCR & (1 << TWINT))) {}; // wait until last action done
-// sr = TWSR & 0xf8;
-// if (sr != 0x40) {
-// return 0x0200 | sr;
-// }
-// return 0;
-// }
-
-// uint16_t I2c::startWrite (uint8_t address) {
-// TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // send START condition
-// while (!(TWCR & (1 << TWINT))) {}; // wait until last action done
-// uint8_t sr = TWSR & 0xf8;
-// if (sr != 0x08 && sr != 0x10) {
-// return 0x0300 | sr;
-// }
-
-// TWDR = (address << 1) | 0x00; // address + WRITE (R/W = 0)
-// TWCR = (1 << TWINT) | (1 << TWEN); // send address/RW
-// while (!(TWCR & (1 << TWINT))) {}; // wait until last action done
-// sr = TWSR & 0xf8;
-// if (sr != 0x18) {
-// return 0x0400 | sr;
-// }
-// return 0;
-// }
-
-// void I2c::stop () {
-// TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
-// }
-
-// uint16_t I2c::writeData (uint8_t size, const uint8_t *data) {
-// while (size-- > 0) {
-// TWDR = *data++;
-// TWCR = (1 << TWINT) | (1 << TWEN); // send data byte
-// while (!(TWCR & (1 << TWINT))) {}; // wait until last action done
-// uint8_t sr = TWSR & 0xf8;
-// if (sr != 0x28) {
-// return 0x0500 | sr;
-// }
-// }
-// return 0;
-// }
-
-// uint16_t I2c::writeByte (uint8_t data) {
-// return writeData(1, &data);
-// }
-
-// uint16_t I2c::readData (uint8_t size, uint8_t *data) {
-// while (size-- > 0) {
-// if (size > 0) {
-// TWCR = (1 << TWEA) | (1 << TWINT) | (1 << TWEN); // read data byte with ACK enabled
-// } else {
-// TWCR = (1 << TWINT) | (1 << TWEN); // read data byte with ACK disabled
-// }
-// while (!(TWCR & (1 << TWINT))) {}; // wait until last action done
-// uint8_t sr = TWSR & 0xf8;
-// if ((size > 0 && sr != 0x50) || (size == 0 && sr != 0x58)) {
-// return 0x0600 | sr;
-// }
-// *data++ = TWDR;
-// }
-// return 0;
-// }
-
-// int32_t I2c::compensateBm280T (int32_t adcT) {
-// // int32_t var1, var2, t;
-// // var1 = ((((adcT >> 3) - ((int32_t)bm280.digT[0] << 1))) * ((int32_t)bm280.digT[1])) >> 11;
-// // var2 = (((((adcT >> 4) - ((int32_t)bm280.digT[0])) * ((adcT >> 4) - ((int32_t)bm280.digT[0]))) >> 12) * ((int32_t)bm280.digT[2])) >> 14;
-// // bm280.tFine = var1 + var2;
-// // t = (bm280.tFine * 5 + 128) >> 8;
-// // return t;
-// return -1;
-// }
public:
I2c (I2cMode mode) { enabled = false; this->mode = mode; }
void tick1ms () { master.tick1ms(); slave.tick1ms(); }
+ virtual void init ();
virtual void cleanup ();
virtual int8_t run (uint8_t subtest);
virtual PGM_P getName ();
// ------------------------------------
// IEE485 not supported (no UART1)
+void Ieee485::init () {}
void Ieee485::cleanup () {}
int8_t Ieee485::run (uint8_t subtest) {
return -1;
#define SET_DE (PORTB |= (1 << PB1))
#define CLR_DE (PORTB &= ~(1 << PB1))
+void Ieee485::init () {
+ // Poti
+ ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V
+ ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128
+
+ // Modbus
+ SET_nRE;
+ CLR_DE;
+ DDRB |= (1 << PB1) | (1 << PB0);
+
+ // UART1 interface on Nano-644
+ PORTD |= (1 << PD2); // enable RxD1 pullup
+ UCSR1A = (1 << U2X1);
+ UCSR1B = (1 << RXCIE1) | (1 << RXEN1) | (1 <<TXEN1);
+ UCSR1C = (1 << UCSZ11) | ( 1<< UCSZ10);
+ // UCSR1C |= (1 <<UPM11); // even Parity
+ // UCSR1C |= (1 << UPM11) | (1 << UPM10); // odd Parity
+ UBRR1H = 0;
+ UBRR1L = F_CPU / 8 / 9600 - 1;
+
+ enabled = 1;
+}
+
void Ieee485::cleanup () {
enabled = 0;
int8_t Ieee485::run (uint8_t subtest) {
if (subtest == 0) {
- // Poti
- ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V
- ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128
-
- // Modbus
- SET_nRE;
- CLR_DE;
- DDRB |= (1 << PB1) | (1 << PB0);
-
- // UART1 interface on Nano-644
- PORTD |= (1 << PD2); // enable RxD1 pullup
- UCSR1A = (1 << U2X1);
- UCSR1B = (1 << RXCIE1) | (1 << RXEN1) | (1 <<TXEN1);
- UCSR1C = (1 << UCSZ11) | ( 1<< UCSZ10);
- // UCSR1C |= (1 <<UPM11); // even Parity
- // UCSR1C |= (1 << UPM11) | (1 << UPM10); // odd Parity
- UBRR1H = 0;
- UBRR1L = F_CPU / 8 / 9600 - 1;
-
- enabled = 1;
- printf_P(PSTR("init"));
-
- } else if (subtest == 1) {
CLR_nRE; CLR_DE;
while (wait(500) == EOF) {
ADCSRA |= (1 << ADSC); // start ADC
public:
Ieee485 () { enabled = 0; receivedByte = -1; }
+ virtual void init ();
virtual void cleanup ();
virtual int8_t run (uint8_t subtest);
virtual const char *getName () { return PSTR("IEEE485"); }
#define DATA_PIN PINB
#endif
- void Lcd::initDDR () {
+ void Lcd::init () {
DDRA |= (1 << PA3);
DDRB = 0xff;
DDRD |= (1 << PD7) | (1 << PD6);
+ initLcd();
+ #ifdef LCD_3V3
+ printf_P(PSTR("init 3.3V LCD"));
+ #else
+ printf_P(PSTR("init 5V LCD"));
+ #endif
}
void Lcd::cleanup () {
// PB4 ..... Data6
// PB5 ..... Data7
- void Lcd::initDDR () {
+ void Lcd::init () {
+ clrRW();
+ clrRS();
+ clrE();
+ setData(0);
DDRB |= (1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB0);
+ DDRC |= (1 << PC3);
DDRD |= (1 << PD7) | (1 << PD6) | (1 << PD4) | (1 << PD3) | (1 << PD2);
+ initLcd();
+ #ifdef LCD_3V3
+ printf_P(PSTR("init 3.3V LCD"));
+ #else
+ printf_P(PSTR("init 5V LCD"));
+ #endif
}
void Lcd::cleanup () {
+ clrRW();
+ clrRS();
+ clrE();
+ setData(0);
DDRB &= ~((1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB0));
+ DDRC &= ~(1 << PC3);
DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD4) | (1 << PD3) | (1 << PD2));
}
int8_t Lcd::run (uint8_t subtest) {
if (subtest == 0) {
- init();
- #ifdef LCD_3V3
- printf_P(PSTR("init 3.3V LCD"));
- #else
- printf_P(PSTR("init 5V LCD"));
- #endif
-
- } else if (subtest == 1) {
for (uint8_t i = 0; i < 20 * 4; i++) {
char c = (char)(i + 32);
if (i % 20 == 0) {
return 0;
}
-void Lcd::init () {
- clrRW();
- clrRS();
- clrE();
- setData(0);
- initDDR();
+void Lcd::initLcd () {
_delay_ms(16); // min 15ms warten für Reset des Displays
setData( 0b00111011 ); // 8bit Modus, 5x7 Zeichen, Mehrzeilen Display
// DIR_DATA_PORT = 0xff;
// return busy != 0;
_delay_us(200);
- return 0;
#else
_delay_us(200);
- return 0;
#endif
-
+ return 0;
}
void Lcd::writeCommand (uint8_t cmd) {
setE(); // E = 1 (transfer start)
_delay_us(10); // min. 10us
clrE(); // E = 0 (transfer end)
- writeData(0);
+ setData(0);
}
void Lcd::setDDRamAddr (uint8_t address) {
_delay_us(10); // min. 10us
clrE(); // E = 0 (transfer end)
_delay_us(10); // min. 10us
- writeData(0);
+ setData(0);
}
void Lcd::writeString (const char *s) {
clrE(); // E = 0 (transfer end)
_delay_us(10); // min. 10us
clrRS();
- writeData(0);
+ setData(0);
}
void Lcd::setCursor (uint8_t row, uint8_t column) {
class Lcd : public TestUnit {
public:
Lcd () {};
+ virtual void init ();
virtual void cleanup ();
virtual int8_t run (uint8_t subtest);
virtual PGM_P getName () { return PSTR("Lcd"); }
private:
- void init ();
- void initDDR ();
+ void initLcd ();
uint8_t isBusy ();
void writeCommand (uint8_t);
void setDDRamAddr (uint8_t);
// PD6 ..... Green
// PD7 ..... Blue
- void Led::initDDR () {
+ void Led::init () {
+ PORTD &= ~((1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4));
DDRD |= (1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4);
}
}
void Led::ledToggle (LED led) {
- case RED: PORTD ^= (1 << PD4); break;
- case ORANGE: PORTD ^= (1 << PD5); break;
- case GREEN: PORTD ^= (1 << PD6); break;
- case BLUE: PORTD ^= (1 << PD7); break;
+ switch(led) {
+ case RED: PORTD ^= (1 << PD4); break;
+ case ORANGE: PORTD ^= (1 << PD5); break;
+ case GREEN: PORTD ^= (1 << PD6); break;
+ case BLUE: PORTD ^= (1 << PD7); break;
+ }
}
#endif
// PD3 ..... Green
// PD2 ..... Blue
- void Led::initDDR () {
+ void Led::init () {
+ PORTD &= ~((1 << PD5) | (1 << PD3) | (1 << PD2));
+ PORTB &= ~(1 << PB1);
DDRD |= (1 << PD5) | (1 << PD3) | (1 << PD2);
DDRB |= (1 << PB1);
}
int8_t Led::run (uint8_t subtest) {
- if (subtest == 0) {
- initDDR();
- printf_P(PSTR("init"));
-
- } else if (subtest <= 16) {
- subtest = (subtest - 1) % 4;
+ if (subtest <= 15) {
+ subtest = (subtest) % 4;
switch (subtest) {
case 0: ledOff(BLUE); ledOn(RED); break;
case 1: ledOff(RED); ledOn(ORANGE); break;
case 2: ledOff(ORANGE); ledOn(GREEN); break;
case 3: ledOff(GREEN); ledOn(BLUE); break;
}
- printf_P(PSTR("Test LED PD%d"), subtest + 4);
-
- } else {
- printf_P(PSTR("end"));
- return -1;
+ printf_P(PSTR("Test LED D%d"), subtest + 1);
+ wait(500);
+ return 0;
}
- wait(500);
- return 0;
+
+ return -1;
}
public:
enum LED { RED, ORANGE, GREEN, BLUE };
-
public:
Led () {};
+ virtual void init ();
virtual void cleanup ();
virtual int8_t run (uint8_t subtest);
virtual PGM_P getName () { return PSTR("Led"); }
void ledOn (LED led);
void ledOff (LED led);
void ledToggle (LED led);
-
- private:
- void initDDR ();
};
#endif
\ No newline at end of file
--- /dev/null
+#include <stdio.h>
+#include <avr/io.h>
+#include <util/delay.h>
+
+#include "modbus.hpp"
+#include "../main.hpp"
+
+
+#ifdef __AVR_ATmega328P__
+void Modbus::init () {}
+void Modbus::cleanup () {}
+int8_t Modbus::run (uint8_t subtest) { return -1; }
+void Modbus::handleRxByte (uint8_t b) {}
+#endif
+
+#ifdef __AVR_ATmega644P__
+
+// PB0 ... nRE .. Read enable
+// PB1 ... DE .. Data enable
+
+#define SET_nRE (PORTB |= (1 << PB0))
+#define CLR_nRE (PORTB &= ~(1 << PB0))
+#define SET_DE (PORTB |= (1 << PB1))
+#define CLR_DE (PORTB &= ~(1 << PB1))
+
+
+void Modbus::init () {
+}
+
+void Modbus::cleanup () {
+ enabled = 0;
+ UCSR1A = 0;
+ UCSR1B = 0;
+ UCSR1C = 0;
+ UBRR1H = 0;
+ UBRR1L = 0;
+ PORTD &= ~(1 << PD2);
+ DDRB &= ~((1 << PB1) | (1 << PB0));
+ PORTB &= ~((1 << PB1) | (1 << PB0));
+}
+
+int8_t Modbus::run (uint8_t subtest) {
+ if (subtest == 0) {
+ SET_nRE;
+ CLR_DE;
+ DDRB |= (1 << PB1) | (1 << PB0);
+
+ // UART1 interface on Nano-644
+ PORTD |= (1 << PD2); // enable RxD1 pullup
+ UCSR1A = (1 << U2X1);
+ UCSR1B = (1 << RXCIE1) | (1 << RXEN1) | (1 <<TXEN1);
+ UCSR1C = (1 << UCSZ11) | ( 1<< UCSZ10);
+ // UCSR1C |= (1 <<UPM11); // even Parity
+ // UCSR1C |= (1 << UPM11) | (1 << UPM10); // odd Parity
+ UBRR1H = 0;
+ UBRR1L = F_CPU / 8 / 9600 - 1;
+
+ enabled = 1;
+ printf_P(PSTR("init"));
+
+ } else if (subtest >= 1 && subtest <= 4) {
+ uint8_t nre, de, b;
+ switch (subtest) {
+ case 1: nre = 1; de = 0; b = 0x01; break;
+ case 2: nre = 1; de = 1; b = 0x8e; break;
+ case 3: nre = 0; de = 0; b = 0x55; break;
+ case 4: nre = 0; de = 1; b = 0xaa; break;
+ default: return -1;
+ }
+ printf_P(PSTR(" DE=%u, nRE=%u send 0x%02x... "), de, nre, b);
+ if (nre) {
+ SET_nRE;
+ } else {
+ CLR_nRE;
+ }
+ if (de) {
+ SET_DE;
+ } else {
+ CLR_DE;
+ }
+ _delay_us(100);
+ receivedBytes = 0;
+ UDR1 = b;
+ _delay_ms(1);
+ if (receivedBytes > 0) {
+ printf_P(PSTR("0x%02x received"), received[0]);
+ receivedBytes = 0;
+ } else {
+ printf_P(PSTR("no byte received"));
+ }
+ printf_P(PSTR(" ... press key to proceed"));
+ while (wait(0xffffffff) == EOF) {}
+ CLR_DE;
+ SET_nRE;
+
+ } else if (subtest == 5) {
+ static uint8_t frame[] = { 0x01, 0x04, 0x00, 0x00, 0x00, 0x02, 0x71, 0xcb };
+ printf_P(PSTR("Modbus: lese Spannung von Eastron SDM-230 (Einphasenzähler)"));
+ SET_DE;
+ CLR_nRE;
+ _delay_us(100);
+ do {
+ SET_DE;
+ receivedBytes = 0;
+ for (uint8_t i = 0; i < sizeof(frame); i++) {
+ UCSR1A |= (1 << TXC1);
+ UDR1 = frame[i];
+ while ((UCSR1A & (1 <<UDRE1)) == 0) {}
+ }
+ while ((UCSR1A & (1 << TXC1)) == 0) {}
+ CLR_DE;
+ printf_P(PSTR("\n => Sending:"));
+ for (uint8_t i = 0; i < sizeof(frame); i++) {
+ printf_P(PSTR(" 0x%02x"), frame[i]);
+ }
+ int k = wait(100);
+
+ printf_P(PSTR("\n RxD1:"));
+ if (receivedBytes == 0) {
+ printf_P(PSTR("?"));
+ } else {
+ for (uint8_t i = 0; i < receivedBytes; i++) {
+ if (i == sizeof(frame)) {
+ printf_P(PSTR(" "));
+ }
+ printf_P(PSTR(" 0x%02x"), received[i]);
+ }
+ }
+ if (receivedBytes >= 16) {
+ union {
+ uint8_t b[4];
+ float value;
+ } f;
+ f.b[0] = received[14];
+ f.b[1] = received[13];
+ f.b[2] = received[12];
+ f.b[3] = received[11];
+ printf_P(PSTR(" -> %4.8fV\n"), (double)f.value);
+ }
+ if (k != EOF) {
+ break;
+ }
+
+ } while (wait(1000) == EOF);
+
+ } else {
+ printf_P(PSTR("end"));
+ return -1;
+ }
+ wait(500);
+ return 0;
+}
+
+void Modbus::handleRxByte (uint8_t b) {
+ if (receivedBytes < sizeof(received)) {
+ received[receivedBytes++] = b;
+ }
+}
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef MODBUS_HPP
+#define MODBUS_HPP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+class Modbus : public TestUnit {
+ public:
+ uint8_t enabled;
+ uint8_t receivedBytes;
+ uint8_t received[16];
+
+
+ public:
+ Modbus () { enabled = 0; receivedBytes = 0; }
+ virtual void init ();
+ virtual void cleanup ();
+ virtual int8_t run (uint8_t subtest);
+ virtual PGM_P getName () { return PSTR("Modbus"); }
+ void handleRxByte (uint8_t);
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#include <stdio.h>
+#include <avr/io.h>
+#include <util/atomic.h>
+
+#include "motor.hpp"
+#include "../main.hpp"
+
+#ifdef __AVR_ATmega644P__
+
+ // Nano-644
+ // ---------------------------------------------------------------
+ // PB0 ..... rotation-sensor
+ // PB2 ..... nFault
+ // PB3 ..... PWM (OC0A)
+ // PB4 ..... EN
+ // PA3 ..... SW3 -> push button for Motor enable control
+
+ #define ADC0K 64
+
+ void Motor::init () {
+ ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V
+ ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128
+ TCCR0A = (1 << COM0A1) | (1 << WGM01) | (1 << WGM00); // Fast PWM on OC0A
+ // TCCR0B = (1 << CS02) | ( 1 << CS00); // f = 12 MHz / 1024 = 11,71875 kHz -> fPWM=45Hz
+ TCCR0B = (1 << CS02); // f = 12 MHz / 256 = 46,875 kHz -> fPWM=183,1Hz
+ DDRB |= (1 << PB4) | (1 << PB3); // Motor enable
+ PORTA |= (1 << PORTA3); // push button for Motor enable control
+ setEnable();
+ enabled = 1;
+ }
+
+ void Motor::cleanup () {
+ ADMUX = 0;
+ ADCSRA = 0;
+ TCCR0A = 0;
+ TCCR0B = 0;
+ DDRB &= ~((1 << PB4) | (1 << PB3));
+ PORTA &= ~(1 << PORTA3);
+ enabled = 0;
+ }
+
+ bool Motor::isSW3Pressed () {
+ return (PINA & (1 << PC3)) == 0;
+ }
+
+ void Motor::clearEnable () {
+ PORTB &= ~(1 << PB4);
+ }
+
+ void Motor::setEnable () {
+ PORTB |= (1 << PB4);
+ }
+
+ bool Motor::isFaultLow () {
+ return (PINB & (1 << PB2)) == 0;
+ }
+
+ bool Motor::isSensorHigh () {
+ return (PINB & (1 << PB0)) != 0;
+ }
+#endif
+
+#ifdef __AVR_ATmega328P__
+
+ // Arduino-Nano-5V
+ // ---------------------------------------------------------------
+ // PD4 ..... rotation-sensor
+ // PD7 ..... nFault
+ // PD6/OC0A ..... PWM
+ // PB2 ..... EN
+ // PC3 ..... SW3 -> push button for Motor enable control
+
+ #define ADC0K 91
+
+ void Motor::init () {
+ ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=5V
+ ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128
+ TCCR0A = (1 << COM0A1) | (1 << WGM01) | (1 << WGM00); // Fast PWM on OC0A
+ // TCCR0B = (1 << CS02) | ( 1 << CS00); // f = 16 MHz / 1024 = 15,625 kHz -> fPWM=61.04Hz
+ TCCR0B = (1 << CS02); // f = 16 MHz / 256 = 62.5 kHz -> fPWM=244.14Hz
+ DDRB |= (1 << PB2);
+ DDRC &= ~(1 << PC3);
+ DDRD |= (1 << PD6);
+ DDRD &= ~((1 << PD4) | (1 << PD7));
+ PORTC |= ( 1 << PC3);
+ PORTD |= (1 << PD7) | (1 << PD5);
+ setEnable();
+ enabled = 1;
+ }
+
+ void Motor::cleanup () {
+ enabled = 0;
+ ADMUX = 0;
+ ADCSRA = 0;
+ TCCR0A = 0;
+ TCCR0B = 0;
+ clearEnable();
+ DDRB &= ~((1 << PB2));
+ DDRC &= ~(1 << PC3);
+ DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD4));
+ PORTC &= ~( 1 << PC3);
+ PORTD &= ~((1 << PD7) | (1 << PD6));
+ }
+
+ bool Motor::isSW3Pressed () {
+ return (PINC & (1 << PC3)) == 0;
+ }
+
+ void Motor::clearEnable () {
+ PORTB &= ~(1 << PB2);
+ }
+
+ void Motor::setEnable () {
+ PORTB |= (1 << PB2);
+ }
+
+ bool Motor::isFaultLow () {
+ return (PIND & (1 << PD7)) == 0;
+ }
+
+ bool Motor::isSensorHigh () {
+ return (PIND & (1 << PD4)) != 0;
+ }
+
+#endif
+
+int8_t Motor::run (uint8_t subtest) {
+ switch (subtest) {
+ case 0: {
+ printf_P(PSTR("\n"));
+ while (wait(10) == EOF) {
+
+ printf_P(PSTR("\r SW3=%d->"), isSW3Pressed() ? 0 : 1);
+ if (isSW3Pressed()) {
+ clearEnable();
+ printf_P(PSTR("EN=0"));
+ } else {
+ setEnable();
+ printf_P(PSTR("EN=1"));
+ }
+
+ ADCSRA |= (1 << ADSC); // start ADC
+ while (ADCSRA & (1 << ADSC)) {} // wait for result
+ printf_P(PSTR("\r => ADC0=%3d"), ADCH);
+
+ ADMUX = (1 << ADLAR) | (1 << REFS1) | (1 << REFS0) | 2; // ADC2, VREF=2.5V
+
+ int16_t x = ((int16_t)(ADCH) - 5) * ADC0K / 64;
+ if (x < 0) x = 0; else if (x > 255) x = 255;
+ uint8_t dutyCycle = 0xff - (uint8_t)x;
+ if (dutyCycle <= 1) {
+ dutyCycle = 0;
+ } else if (dutyCycle > 254) {
+ dutyCycle = 255;
+ }
+ OCR0A = dutyCycle;
+ printf_P(PSTR(" PWM/OC0A=%3d"), dutyCycle);
+
+ ADCSRA |= (1 << ADSC); // start ADC
+ while (ADCSRA & (1 << ADSC)) {} // wait for result
+ printf_P(PSTR(" ADC2=%3d"), ADCH);
+ ADMUX = (1 << ADLAR) | (1 << REFS0); // ADC0, VREF=AVCC=3.3V
+
+ printf_P(PSTR(" nFAULT=%d"), isFaultLow() ? 0 : 1);
+ printf_P(PSTR(" SENSOR=%d "), isSensorHigh());
+ uint16_t timer;
+ ATOMIC_BLOCK(ATOMIC_FORCEON) {
+ timer = rpmTimer;
+ }
+ float rpm = 60.0 / (float)timer / 0.0001;
+ if (timer > 0) {
+ printf_P(PSTR(" n= %4d U/min"), (int)rpm);
+ } else {
+ printf_P(PSTR(" no rotation "));
+ }
+
+ }
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+void Motor::tick100us () {
+ static uint16_t timerH = 0;
+ static uint16_t timerL = 0;
+ static bool lastSensorHigh = false;
+
+ bool sensorHigh = isSensorHigh();
+ if (!sensorHigh && sensorHigh != lastSensorHigh && timerL > 10) {
+ rpmTimer = timerL + timerH;
+ timerL = 0;
+ timerH = 0;
+ }
+ if (sensorHigh) {
+ timerH = timerH < 0x4000 ? timerH + 1 : 0x4000;
+ } else {
+ timerL = timerL < 0x4000 ? timerL + 1 : 0x4000;
+ }
+ if (timerH >= 0x4000 || timerL >= 0x4000) {
+ rpmTimer = 0; // no ratation detected
+ }
+ lastSensorHigh = sensorHigh;
+}
+
+
--- /dev/null
+#ifndef MOTOR_HPP
+#define MOTOR_HPP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+class Motor : public TestUnit {
+ public:
+ uint8_t enabled;
+ uint16_t rpmTimer;
+
+ public:
+ Motor () { enabled = 0; rpmTimer = 0; };
+ virtual void init ();
+ virtual void cleanup ();
+ virtual int8_t run (uint8_t subtest);
+ virtual PGM_P getName () { return PSTR("Motor"); }
+ void tick100us ();
+
+ private:
+ bool isSW3Pressed ();
+ void clearEnable ();
+ void setEnable ();
+ bool isFaultLow ();
+ bool isSensorHigh ();
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#include <stdio.h>
+#include <avr/io.h>
+#include <util/delay.h>
+
+#include "portexp.hpp"
+#include "../main.hpp"
+
+// Port-Expander MCP23S17
+
+// SN-Print Stecker IO16
+// MCP23S17 | IO16 (MEGA2560) | Ampel-Print | | MCP23S17 | IO16 (MEGA2560) | Ampel-Print |
+// ------------------------------------------ --------------------------------------------
+// GPA0 | IO16O7 (PA7) | Taster RU | | GPB0 | IO16U7 (PC7) | Taster LU |
+// GPA1 | IO16O6 (PA6) | Taster RO | | GPB1 | IO16U6 (PC6) | Taster LO |
+// GPA2 | IO16O5 (PA5) | U-Gruen | | GPB2 | IO16U5 (PC5) | R-Gruen |
+// GPA3 | IO16O4 (PA4) | U-Gelb | | GPB3 | IO16U4 (PC4) | R-Gelb |
+// GPA4 | IO16O3 (PA3) | U-Rot | | GPB4 | IO16U3 (PC3) | R-Rot |
+// GPA5 | IO16O2 (PA2) | L-Gruen | | GPB5 | IO16U2 (PC2) | O-Gruen |
+// GPA6 | IO16O1 (PA1) | L-Gelb | | GPB6 | IO16U1 (PC1) | O-Gelb |
+// GPA7 | IO16O0 (PA0) | L-Rot | | GPB7 | IO16U0 (PC0) | O-Rot |
+
+#ifdef __AVR_ATmega644P__
+
+ // Nano-644
+ // --------------------------------------------------------
+ // PA7 ... nCS
+ // PB5 ... MOSI
+ // PB6 ... MISO
+ // PB7 ... SCK
+
+ void PortExp::init () {
+ PRR &= (1 << PRSPI);
+ PORTA |= (1 << PA7);
+ DDRA |= (1 << PA7); // SPI nCS
+ // PORTB/DDRB must be configured before SPCR !!
+ PORTB |= (1 << PB4); // nSS must be HIGH, otherwise SPI master will not become active!!
+ DDRB |= (1 << PB7) | (1 << PB5) | (1 << PB4); // SPI SCK (=PB7) and SPI MOSI (=PB5)
+
+ // SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); // SPI enable , Master, f=12MHz/128=93,75kHz
+ SPCR = (1 << SPE) | (1 << MSTR); // SPI enable , Master, f=12MHz/4 = 3MHz
+ }
+
+ void PortExp::cleanup () {
+ DDRB &= ~(1 << PB6); // // SPI MISO (=PB6)
+ DDRB &= ~((1 << PB7) | (1 << PB5)); // SPI SCK (=PB7) and SPI MOSI (=PB5)
+ DDRA &= ~(1 << PA7);
+ PORTA &= ~(1 << PA7); // SPI nCS
+ SPCR = 0;
+ }
+
+ void PortExp::setChipEnable () {
+ PORTA &= ~(1 << PA7);
+ }
+
+ void PortExp::clearChipEnable () {
+ PORTA |= (1 << PA7);
+ }
+
+
+#endif
+
+#ifdef __AVR_ATmega328P__
+
+ // Arduino-Nano-5V
+ // ------------------------------------
+ // PC1 ... nCS (MANUAL (!) connection PA1 - PA7 required)
+ // PB3 ... MOSI
+ // PB4 ... MISO
+ // PB5 ... SCK
+
+ void PortExp::init () {
+ PRR &= (1 << PRSPI);
+ PORTC |= (1 << PC1);
+ DDRC |= (1 << PC1); // SPI nCS
+ // PORTB/DDRB must be configured before SPCR !!
+ PORTB |= (1 << PB2); // nSS must be HIGH, otherwise SPI master will not become active!!
+ DDRB |= (1 << PB5) | (1 << PB3) | (1 << PB2); // SPI SCK (=PB5), SPI MOSI (=PB3), SPI nSS (=PB2)
+
+ // SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); // SPI enable , Master, f=16MHz/128=125kHz
+ SPCR = (1 << SPE) | (1 << MSTR); // SPI enable , Master, f=12MHz/4 = 3MHz
+ }
+
+ void PortExp::cleanup () {
+ PORTC &= ~(1 << PC1);
+ DDRC &= ~(1 << PC1);
+ PORTB &= ~(1 << PB2);
+ DDRB &= ~((1 << PB5) | (1 << PB3) | (1 << PB2));
+ SPCR = 0;
+ }
+
+ void PortExp::setChipEnable () {
+ PORTC &= ~(1 << PC1);
+ }
+
+ void PortExp::clearChipEnable () {
+ PORTC |= (1 << PC1);
+ }
+
+#endif
+
+
+
+int8_t PortExp::writeByte (uint8_t addr, uint8_t b) {
+
+ setChipEnable();
+
+ SPDR = 0x40; // WRITE BYTE
+ while ((SPSR & (1 << SPIF)) == 0) {}
+ if (SPDR != 0) {
+ printf_P(PSTR("E1"));
+ clearChipEnable();
+ return -1;
+ }
+
+ SPDR = addr; // register address
+ while ((SPSR & (1 << SPIF)) == 0) {}
+ if (SPDR != 0) {
+ printf_P(PSTR("E2"));
+ clearChipEnable();
+ return -1;
+ }
+
+ SPDR = b; // value
+ while ((SPSR & (1 << SPIF)) == 0) {}
+ if (SPDR != 0) {
+ printf_P(PSTR("E3"));
+ clearChipEnable();
+ return -1;
+ }
+
+ clearChipEnable();
+
+ _delay_us(5);
+ return 0;
+}
+
+int8_t PortExp::run (uint8_t subtest) {
+ if (subtest == 0) {
+ while (wait(500) == EOF) {
+ printf_P(PSTR("\n => start ..."));
+ for (uint8_t i = 0; i < 8; i++) {
+ writeByte(0, ~(1 << i)); // IODIRA (Bank = 0)
+ // writeByte(0, 0x00); // IODIRA (Bank = 0) - all output
+ writeByte(0x12, (1 << i)); // GPIOA (Bank = 0)
+ printf_P(PSTR("\n Bank0 - GPA%d = 1"), i);
+ wait(200);
+ writeByte(0x12, 0); // GPIOA (Bank = 0)
+ printf_P(PSTR("\n Bank0 - GPA%d = 0"), i);
+ writeByte(0, 0xff); // IODIRA (Bank = 0)
+ wait(200);
+ }
+ for (uint8_t i = 0; i < 8; i++) {
+ writeByte(1, ~(1 << i)); // IODIRB (Bank = 0)
+ // writeByte(1, 0x00); // IODIRB (Bank = 0) - all output
+ writeByte(0x13, (1 << i)); // GPIOB (Bank = 0)
+ printf_P(PSTR("\n Bank0 - GPB%d = 1"), i);
+ wait(200);
+ writeByte(0x13, 0); // GPIOB (Bank = 0)
+ printf_P(PSTR("\n Bank0 - GPB%d = 0"), i);
+ writeByte(1, 0xff); // IODIRB (Bank = 0)
+ wait(200);
+ }
+ }
+ return 0;
+ }
+
+ return -1;
+}
+
--- /dev/null
+#ifndef PORTEXP_HPP
+#define PORTEXP_HPP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+class PortExp : public TestUnit {
+ public:
+ PortExp () {};
+ virtual void init ();
+ virtual void cleanup ();
+ virtual int8_t run (uint8_t subtest);
+ virtual PGM_P getName () { return PSTR("PortExp"); }
+
+ private:
+ void setChipEnable ();
+ void clearChipEnable ();
+ int8_t writeByte (uint8_t addr, uint8_t b);
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#include <stdio.h>
+#include <avr/io.h>
+
+#include "poti.hpp"
+#include "../main.hpp"
+
+void Poti::init () {
+ ADMUX = (1 << REFS0); // ADC0, VREF=AVCC=3.3V
+ ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128
+}
+
+void Poti::cleanup () {
+ ADMUX = 0;
+ ADCSRA = 0;
+}
+
+int8_t Poti::run (uint8_t subtest) {
+ switch (subtest) {
+ case 0: {
+ printf_P(PSTR("\n"));
+ while (wait(10) == EOF) {
+ printf_P(PSTR("\r => Measure ADC0: "));
+ ADCSRA |= (1 << ADSC); // start ADC
+ while (ADCSRA & (1 << ADSC)) {} // wait for result
+ printf_P(PSTR("%4d (0x%03x)"), ADC, ADC);
+ }
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+
--- /dev/null
+#ifndef POTI_HPP
+#define POTI_PP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+class Poti : public TestUnit {
+ public:
+ Poti () {};
+ virtual void init ();
+ virtual void cleanup ();
+ virtual int8_t run (uint8_t subtest);
+ virtual PGM_P getName () { return PSTR("Poti"); }
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#include <stdio.h>
+#include <avr/io.h>
+
+#include "r2r.hpp"
+#include "../main.hpp"
+
+#ifdef __AVR_ATmega644P__
+ // AVCC=3.3, POTI Vmax=3.3V
+ #define K 1.0
+#endif
+
+#ifdef __AVR_ATmega328P__
+ // AVCC=4.7V, POTI Vmax=3.3V
+ #define K (1023.0 / 738.0)
+#endif
+
+void R2r::init () {
+ ADMUX = (1 << REFS0) | 2; // ADC2, VREF=AVCC=3.3V
+ ADCSRA = (1 << ADEN) | 7; // ADC Enable, Prescaler 128
+}
+
+void R2r::cleanup () {
+ ADMUX = 0;
+ ADCSRA = 0;
+}
+
+int8_t R2r::run (uint8_t subtest) {
+ switch (subtest) {
+ case 0: {
+ printf_P(PSTR("\n"));
+ while (wait(10) == EOF) {
+ printf_P(PSTR("\r => Measure ADC2: "));
+ ADCSRA |= (1 << ADSC); // start ADC
+ while (ADCSRA & (1 << ADSC)) {} // wait for result
+ printf_P(PSTR("%4d (0x%03x)"), ADC, ADC);
+ uint8_t sw = (uint8_t)( ((float)(ADC) + 32.0) / 64.0 * K );
+ printf_P(PSTR(" SW9:6 = %d %d% d %d "), sw >> 3, (sw >> 2) & 0x01, (sw >> 1) & 0x01, sw & 0x01 );
+ }
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+
--- /dev/null
+#ifndef R2R_HPP
+#define R2R_PP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+class R2r : public TestUnit {
+ public:
+ R2r () {};
+ virtual void init ();
+ virtual void cleanup ();
+ virtual int8_t run (uint8_t subtest);
+ virtual PGM_P getName () { return PSTR("R2R"); }
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#include <stdio.h>
+#include <avr/io.h>
+
+#include "rgb.hpp"
+#include "../main.hpp"
+
+#ifdef __AVR_ATmega644P__
+
+ // Nano-644
+ // ---------------------------------------------------------------
+ // PB0 ..... Red (inverse logic -> 0 = ON)
+ // PB1 ..... Green (inverse logic -> 0 = ON)
+ // PB2 ..... Blue (inverse logic -> 0 = ON)
+
+ void Rgb::init () {
+ ledOff(RED);
+ ledOff(GREEN);
+ ledOff(BLUE);
+ DDRB |= (1 << PB2) | (1 << PB1) | (1 << PB0);
+ }
+
+ void Rgb::cleanup () {
+ ledOff(RED);
+ ledOff(GREEN);
+ ledOff(BLUE);
+ DDRB &= ~((1 << PB2) | (1 << PB1) | (1 << PB0));
+ }
+
+ void Rgb::setLed (LED led, bool on) {
+ if (on) {
+ switch(led) {
+ case RED: PORTB |= (1 << PB0); break;
+ case GREEN: PORTB |= (1 << PB1); break;
+ case BLUE: PORTB |= (1 << PB2); break;
+ }
+ } else {
+ switch(led) {
+ case RED: PORTB &= ~(1 << PB0); break;
+ case GREEN: PORTB &= ~(1 << PB1); break;
+ case BLUE: PORTB &= ~(1 << PB2); break;
+ }
+ }
+ }
+
+ void Rgb::ledToggle (LED led) {
+ switch(led) {
+ case RED: PORTB ^= (1 << PB0); break;
+ case GREEN: PORTB ^= (1 << PB1); break;
+ case BLUE: PORTB ^= (1 << PB2); break;
+ }
+ }
+
+
+#endif
+
+#ifdef __AVR_ATmega328P__
+
+ // Arduino-Nano-5V
+ // ---------------------------------------------------------------
+ // PD4 ..... Red (inverse logic -> 0 = ON)
+ // PB0 ..... Green (inverse logic -> 0 = ON)
+ // PD7 ..... Blue (inverse logic -> 0 = ON)
+
+ void Rgb::init () {
+ ledOff(RED);
+ ledOff(GREEN);
+ ledOff(BLUE);
+ DDRB |= (1 << PB0);
+ DDRD |= (1 << PD7) | (1 << PD4);
+ }
+
+ void Rgb::cleanup () {
+ ledOff(RED);
+ ledOff(GREEN);
+ ledOff(BLUE);
+ DDRB &= ~(1 << PB0);
+ DDRD &= ~((1 << PD7) | (1 << PD4));
+ }
+
+ void Rgb::setLed (LED led, bool on) {
+ if (on) {
+ switch (led) {
+ case RED: PORTD &= ~(1 << PD4); break;
+ case GREEN: PORTB &= ~(1 << PB0); break;
+ case BLUE: PORTD &= ~(1 << PD7); break;
+ }
+ } else {
+ switch (led) {
+ case RED: PORTD |= (1 << PD4); break;
+ case GREEN: PORTB |= (1 << PB0); break;
+ case BLUE: PORTD |= (1 << PD7); break;
+ }
+ }
+ }
+
+ void Rgb::ledToggle (LED led) {
+ switch (led) {
+ case RED: PORTD ^= (1 << PD4); break;
+ case GREEN: PORTB ^= ~(1 << PB0); break;
+ case BLUE: PORTD ^= (1 << PD7); break;
+ }
+ }
+
+#endif
+
+void Rgb::ledOn (LED led) {
+ setLed(led, true);
+}
+
+void Rgb::ledOff (LED led) {
+ setLed(led, false);
+}
+
+int8_t Rgb::run (uint8_t subtest) {
+ switch (subtest) {
+ case 0: {
+ ledOn(RED);
+ printf_P(PSTR("Red"));
+ wait(3000);
+ ledOff(RED);
+ return 0;
+ }
+
+ case 1: {
+ ledOn(GREEN);
+ printf_P(PSTR("Green"));
+ wait(3000);
+ ledOff(GREEN);
+ return 0;
+ }
+
+ case 2: {
+ ledOn(BLUE);
+ printf_P(PSTR("Blue"));
+ wait(3000);
+ ledOff(BLUE);
+ return 0;
+ }
+
+ case 3: {
+ ledOn(RED); ledOn(GREEN); ledOn(BLUE);
+ printf_P(PSTR("All"));
+ wait(3000);
+ ledOff(RED); ledOff(GREEN); ledOff(BLUE);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+
--- /dev/null
+#ifndef RGB_HPP
+#define RGB_PP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+class Rgb : public TestUnit {
+ public:
+ enum LED { RED, GREEN, BLUE };
+
+ public:
+ Rgb () {};
+ virtual void init ();
+ virtual void cleanup ();
+ virtual int8_t run (uint8_t subtest);
+ virtual PGM_P getName () { return PSTR("Rgb"); }
+
+ void setLed (LED led, bool on);
+ void ledOn (LED led);
+ void ledOff (LED led);
+ void ledToggle (LED led);
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#include <stdio.h>
+#include <avr/io.h>
+
+#include "seg7.hpp"
+#include "../main.hpp"
+
+#ifdef __AVR_ATmega644P__
+
+ // Nano-644
+ // ---------------------------------------------------------------
+
+ // PA0 ... Cathode Char 1
+ // PA1 ... Cathode Char 2
+ // PA2 ... Cathode Char 3
+ // PA3 ... Cathode Char 4
+
+ // PB0 ... Anode Segment A
+ // PB1 ... Anode Segment B
+ // PB2 ... Anode Segment C
+ // PB3 ... Anode Segment D
+ // PB4 ... Anode Segment E
+ // PB5 ... Anode Segment F
+ // PB6 ... Anode Segment G
+ // PB7 ... Anode DP
+
+ // PD5 ... nOE (Output Enable) for all LEDs
+ // PD6 ... Anode L1:2
+ // PD7 ... Anode L3
+
+void Seg7::init () {
+ setAnodes(0);
+ setCathodes(0);
+ DDRA |= (1 << PA3) | (1 << PA2) | (1 << PA1) | (1 << PA0);
+ DDRB = 0xff;
+ DDRD |= (1 << PD7) | (1 << PD6) | (1 << PD5);
+ }
+
+ void Seg7::cleanup () {
+ setAnodes(0);
+ setCathodes(0);
+ DDRA &= ~((1 << PA3) | (1 << PA2) | (1 << PA1) | (1 << PA0));
+ DDRB = 0x00;
+ DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD5));
+ }
+
+ void Seg7::setAnodes (uint16_t a) {
+ if (a & 0x0001) PORTD |= (1 << PD4); else PORTD &= ~(1 << PD4); // Anode Char A
+ if (a & 0x0002) PORTB |= (1 << PB0); else PORTB &= ~(1 << PB0); // Anode Char B
+ if (a & 0x0004) PORTD |= (1 << PD7); else PORTD &= ~(1 << PD7); // Anode Char C
+ if (a & 0x0008) PORTD |= (1 << PD6); else PORTD &= ~(1 << PD6); // Anode Char D
+ if (a & 0x0010) PORTB |= (1 << PB2); else PORTB &= ~(1 << PB2); // Anode Char E
+ if (a & 0x0020) PORTB |= (1 << PB3); else PORTB &= ~(1 << PB3); // Anode Char F
+ if (a & 0x0040) PORTB |= (1 << PB4); else PORTB &= ~(1 << PB4); // Anode Char G
+ if (a & 0x0080) PORTB |= (1 << PB5); else PORTB &= ~(1 << PB5); // Anode Char DP
+ if (a & 0x0100) PORTD |= (1 << PD3); else PORTD &= ~(1 << PD3); // Anode L1/L2
+ if (a & 0x0200) PORTD |= (1 << PD2); else PORTD &= ~(1 << PD2); // Anode L3
+ }
+
+ void Seg7::setCathodes (uint8_t c) {
+ if (c & 0x01) PORTC |= (1 << PC0); else PORTC &= ~(1 << PC0); // Chathode Char 1 (most left)
+ if (c & 0x02) PORTC |= (1 << PC1); else PORTC &= ~(1 << PC1); // Chathode Char 2
+ if (c & 0x04) PORTC |= (1 << PC2); else PORTC &= ~(1 << PC2); // Chathode Char 3
+ if (c & 0x08) PORTC |= (1 << PC3); else PORTC &= ~(1 << PC3); // Chathode Char 4 (most right)
+ }
+
+ void Seg7::setOE (bool enabled) {
+ if (enabled) {
+ PORTB &= ~(1 << PB1);
+ } else {
+ PORTB |= (1 << PB1);
+ }
+ }
+
+ void Seg7::init () {
+
+ PORTB = 0;
+ DDRB = 0xff;
+ PORTD &= ~((1 <<PORTD7) | (1 << PORTD6));
+ PORTD |= (1 << PORTD5);
+ DDRD |= (1 <<DDD7) | (1 << DDD6) | (1 << DDD5);
+ }
+
+ void Seg7::cleanup () {
+ PORTA &= ~((1 <<PORTA3) | (1 << PORTA2) | (1 << PORTA1) | (1 << PORTA0));
+ DDRA &= ~((1 <<DDA3) | (1 << DDA2) | (1 << DDA1) | (1 << DDA0));
+ PORTD &= ~((1 <<PORTD7) | (1 << PORTD6) | (1 << PORTD5));
+ DDRD &= ~((1 <<DDD7) | (1 << DDD6) | (1 << DDD5));
+ PORTB = 0;
+ DDRB = 0;
+ }
+#endif
+
+#ifdef __AVR_ATmega328P__
+
+ // Arduino-Nano-5V
+ // ---------------------------------------------------------------
+
+ // PC0 ... Cathode Char 1
+ // PC1 ... Cathode Char 2
+ // PC2 ... Cathode Char 3
+ // PC3 ... Cathode Char 4
+
+ // PD4 ... Anode Segment A
+ // PB0 ... Anode Segment B
+ // PD7 ... Anode Segment C
+ // PD6 ... Anode Segment D
+ // PB2 ... Anode Segment E
+ // PB3 ... Anode Segment F
+ // PB4 ... Anode Segment G
+ // PB5 ... Anode DP
+
+ // PB1 ... nOE (Output Enable) for all LEDs
+ // PD3 ... Anode L1:2
+ // PD2 ,,, Anode L3
+
+ void Seg7::init () {
+ enabled = 1;
+ setAnodes(0);
+ setCathodes(0);
+ DDRB |= (1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB1) | (1 << PB0) ;
+ DDRC |= (1 << PC3) | (1 << PC2) | (1 << PC1) | (1 << PC0);
+ DDRD |= (1 << PD7) | (1 << PD6) | (1 << PD4) | (1 << PD3) | (1 << PD2);
+
+ }
+
+ void Seg7::cleanup () {
+ enabled = 0;
+ setAnodes(0);
+ setCathodes(0);
+ DDRB &= ~((1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB1) | (1 << PB0));
+ DDRC &= ~((1 << PC3) | (1 << PC2) | (1 << PC1) | (1 << PC0));
+ DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD4) | (1 << PD3) | (1 << PD2));
+ }
+
+ void Seg7::setAnodes (uint16_t a) {
+ if (a & 0x0001) PORTD |= (1 << PD4); else PORTD &= ~(1 << PD4); // Anode Char A
+ if (a & 0x0002) PORTB |= (1 << PB0); else PORTB &= ~(1 << PB0); // Anode Char B
+ if (a & 0x0004) PORTD |= (1 << PD7); else PORTD &= ~(1 << PD7); // Anode Char C
+ if (a & 0x0008) PORTD |= (1 << PD6); else PORTD &= ~(1 << PD6); // Anode Char D
+ if (a & 0x0010) PORTB |= (1 << PB2); else PORTB &= ~(1 << PB2); // Anode Char E
+ if (a & 0x0020) PORTB |= (1 << PB3); else PORTB &= ~(1 << PB3); // Anode Char F
+ if (a & 0x0040) PORTB |= (1 << PB4); else PORTB &= ~(1 << PB4); // Anode Char G
+ if (a & 0x0080) PORTB |= (1 << PB5); else PORTB &= ~(1 << PB5); // Anode Char DP
+ if (a & 0x0100) PORTD |= (1 << PD3); else PORTD &= ~(1 << PD3); // Anode L1/L2
+ if (a & 0x0200) PORTD |= (1 << PD2); else PORTD &= ~(1 << PD2); // Anode L3
+ }
+
+ void Seg7::setCathodes (uint8_t c) {
+ if (c & 0x01) PORTC |= (1 << PC0); else PORTC &= ~(1 << PC0); // Chathode Char 1 (most left)
+ if (c & 0x02) PORTC |= (1 << PC1); else PORTC &= ~(1 << PC1); // Chathode Char 2
+ if (c & 0x04) PORTC |= (1 << PC2); else PORTC &= ~(1 << PC2); // Chathode Char 3
+ if (c & 0x08) PORTC |= (1 << PC3); else PORTC &= ~(1 << PC3); // Chathode Char 4 (most right)
+ }
+
+ void Seg7::setOE (bool enabled) {
+ if (enabled) {
+ PORTB &= ~(1 << PB1);
+ } else {
+ PORTB |= (1 << PB1);
+ }
+ }
+
+#endif
+
+const char *segName[] = { "A", "B", "C", "D", "E", "F", "G", "DP" };
+
+
+int8_t Seg7::run (uint8_t subtest) {
+ if (subtest == 0) {
+ setCathodes(0x0f); // all segment cathodes conected to GND
+ setAnodes(0x3ff); // all segments ON
+ setOE(true);
+ printf_P(PSTR("ON"));
+ wait(2000);
+ setAnodes(0);
+ return 0;
+
+ } else if (subtest == 1) {
+ printf_P(PSTR("OFF"));
+ wait(1000);
+ return 0;
+
+ } else if (subtest == 2) {
+ setAnodes(0x100); // L1/L2 ON
+ printf_P(PSTR("L1/L2 ON"));
+ wait(1000);
+ setAnodes(0);
+ return 0;
+
+ } else if (subtest == 3) {
+ setAnodes(0x200); // L3 ON
+ printf_P(PSTR("L1/L2 ON"));
+ wait(1000);
+ setAnodes(0);
+ return 0;
+
+ } else if (subtest < (4 + 4 * 8)) {
+ uint8_t chIndex = (subtest - 4) / 8;
+ uint8_t segIndex = (subtest - 4) % 8;
+ setCathodes(1 << chIndex);
+ setAnodes(1 << segIndex);
+ printf_P(PSTR("Char %d - %s"), chIndex, segName[segIndex]);
+ wait(400);
+ return 0;
+ }
+
+ return -1;
+}
+
+
--- /dev/null
+#ifndef SEG7_HPP
+#define SEG7_HPP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+class Seg7 : public TestUnit {
+ public:
+ bool enabled;
+
+ public:
+ Seg7 () { enabled = false; }
+ virtual void init ();
+ virtual void cleanup ();
+ virtual int8_t run (uint8_t subtest);
+ virtual PGM_P getName () { return PSTR("Seg7"); }
+
+ private:
+ void setAnodes (uint16_t);
+ void setCathodes (uint8_t mask);
+ void setOE (bool enabled);
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#include <stdio.h>
+#include <avr/io.h>
+#include <util/delay.h>
+
+#include "switch.hpp"
+#include "../main.hpp"
+
+#ifdef __AVR_ATmega644P__
+
+ // Nano-644
+ // ---------------------------------------------------------------
+ // PA0 ..... SW1
+ // PA1 ..... SW2
+ // PA2 ..... SW3
+ // PA3 ..... SW4
+
+ void Switch::init () {
+ DDRA &= ~((1 << PORTA3) | (1 << PORTA2) | (1 << PORTA1) | (1 << PORTA0));
+ PORTA |= (1 << PORTA3) | (1 << PORTA2) | (1 << PORTA1) | (1 << PORTA0);
+ }
+
+ void Switch::cleanup () {
+ PORTA &= ~((1 << PORTA3) | (1 << PORTA2) | (1 << PORTA1) | (1 << PORTA0));
+ DDRA &= ~((1 << PORTA3) | (1 << PORTA2) | (1 << PORTA1) | (1 << PORTA0));
+ }
+
+ bool Switch::isPressed (SWITCH sw) {
+ switch (sw) {
+ case SW1: return (PINA & ( 1 << PA0)) == 0;
+ case SW2: return (PINA & ( 1 << PA1)) == 0;
+ case SW3: return (PINA & ( 1 << PA2)) == 0;
+ case SW4: return (PINA & ( 1 << PA3)) == 0;
+ default: return false;
+ }
+ }
+
+#endif
+
+#ifdef __AVR_ATmega328P__
+
+ // Arduino-Nano-5V
+ // ---------------------------------------------------------------
+ // PC0 ..... SW1
+ // PC1 ..... SW2
+ // PC2 ..... SW3
+ // PC3 ..... SW4
+
+ void Switch::init () {
+ DDRC &= ~((1 << PORTC3) | (1 << PORTC2) | (1 << PORTC1) | (1 << PORTC0));
+ PORTC |= (1 << PORTC3) | (1 << PORTC2) | (1 << PORTC1) | (1 << PORTC0);
+ }
+
+ void Switch::cleanup () {
+ PORTC &= ~((1 << PORTC3) | (1 << PORTC2) | (1 << PORTC1) | (1 << PORTC0));
+ DDRC &= ~((1 << PORTC3) | (1 << PORTC2) | (1 << PORTC1) | (1 << PORTC0));
+ }
+
+ bool Switch::isPressed (SWITCH sw) {
+ switch (sw) {
+ case SW1: return (PINC & ( 1 << PC0)) == 0;
+ case SW2: return (PINC & ( 1 << PC1)) == 0;
+ case SW3: return (PINC & ( 1 << PC2)) == 0;
+ case SW4: return (PINC & ( 1 << PC3)) == 0;
+ default: return false;
+ }
+ }
+
+#endif
+
+int8_t Switch::run (uint8_t subtest) {
+ if (subtest < 16) {
+ SWITCH sw = (SWITCH)(subtest / 4);
+ switch (subtest % 4) {
+ case 1: {
+ if (!isPressed(sw)) {
+ printf_P(PSTR("Press SW%d"), sw + 1);
+ while (!isPressed(sw) && wait(0) == EOF) {}
+ wait(10);
+ }
+ return 0;
+ }
+
+ case 0: case 2: {
+ if (isPressed(sw)) {
+ printf_P(PSTR("Release SW%d "), sw + 1);
+ while (isPressed(sw) && wait(0) == EOF) {}
+ wait(10);
+ }
+ return 0;
+ }
+
+ case 3: {
+ return 0;
+ }
+ }
+
+ }
+
+ return -1;
+}
--- /dev/null
+#ifndef SWITCH_HPP
+#define SWITCH_HPP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+class Switch : public TestUnit {
+ typedef enum { SW1 = 0, SW2 = 1, SW3 = 2, SW4 = 3 } SWITCH;
+
+ public:
+ Switch () {};
+ virtual void init ();
+ virtual void cleanup ();
+ virtual int8_t run (uint8_t subtest);
+ virtual PGM_P getName () { return PSTR("Switch"); }
+ bool isPressed (SWITCH sw);
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#include <stdio.h>
+#include <avr/io.h>
+#include <util/delay.h>
+
+#include "uart1.hpp"
+#include "../main.hpp"
+
+#ifdef __AVR_ATmega328P__
+ void Uart1::init () {}
+ void Uart1::cleanup () {}
+ int8_t Uart1::run (uint8_t subtest) { return -1; }
+ void Uart1::handleRxByte (uint8_t b) {}
+#endif
+
+#ifdef __AVR_ATmega644P__
+
+int uart1_putchar(char c, FILE *stream) {
+ if (c == '\n') {
+ uart1_putchar('\r', stream);
+ }
+ loop_until_bit_is_set(UCSR1A, UDRE1);
+ UDR1 = c;
+ return 0;
+}
+
+static FILE mystderr = { 0, 0, _FDEV_SETUP_WRITE , 0, 0, uart1_putchar, NULL, 0 };
+
+void Uart1::cleanup () {
+ enabled = 0;
+ UCSR1A = 0;
+ UCSR1B = 0;
+ UCSR1C = 0;
+ UBRR1H = 0;
+ UBRR1L = 0;
+ stderr = NULL;
+}
+
+int8_t Uart1::run (uint8_t subtest) {
+ if (subtest == 0) {
+ // UART1 interface on Nano-644
+ PORTD |= (1 << PD2); // enable RxD1 pullup
+ UCSR1A = (1 << U2X1);
+ UCSR1B = (1 << RXCIE1) | (1 << RXEN1) | (1 <<TXEN1);
+ UCSR1C = (1 << UCSZ11) | ( 1<< UCSZ10);
+ UBRR1H = 0;
+ UBRR1L = F_CPU / 8 / 115200 - 1;
+ stderr = &mystderr;
+ enabled = 1;
+ printf_P(PSTR("init"));
+
+ } else if (subtest == 1) {
+ do {
+ printf_P(PSTR("\n => send text via UART1 now..."));
+ fprintf_P(stderr, PSTR("Hello UART1, ECHO-Modus active\n"));
+ } while (wait(5000) == EOF);
+
+ } else {
+ printf_P(PSTR("end"));
+ return -1;
+ }
+ wait(500);
+ return 0;
+}
+
+void Uart1::handleRxByte (uint8_t b) {
+ uart1_putchar(b, stderr);
+}
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef UART1_HPP
+#define UART1_HPP
+
+#include <stdint.h>
+#include "../main.hpp"
+#include <avr/pgmspace.h>
+
+class Uart1 : public TestUnit {
+ public:
+ uint8_t enabled;
+
+ public:
+ Uart1 () { enabled = 0; }
+ virtual void init ();
+ virtual void cleanup ();
+ virtual int8_t run (uint8_t subtest);
+ virtual PGM_P getName () { return PSTR("Uart1"); }
+ void handleRxByte (uint8_t);
+};
+
+#endif
\ No newline at end of file