#include "units/motor.hpp"
#include "units/portexp.hpp"
#include "units/lcd.hpp"
+#include "units/modbus.hpp"
extern "C" {
void __cxa_pure_virtual () {
return 0;
}
- static FILE mystdout = { 0, 0, _FDEV_SETUP_WRITE , 0, 0, uart_putchar, NULL, 0 } ;
- static FILE mystderr = { 0, 0, _FDEV_SETUP_WRITE , 0, 0, uart_putchar, NULL, 0 } ;
+
+ uint8_t volatile uartBuffer[32];
+ uint8_t volatile rIndex = 0;
+ uint8_t volatile wIndex = 0;
+
+ int uart_getchar (FILE *stream) {
+ // if (rIndex == wIndex) {
+ // // nothing in buffer
+ // return EOF;
+ // }
+ // printf(" r%d", rIndex);
+ while (rIndex == wIndex) {
+ // wait for character
+ }
+
+ // don't use "char c" because german special characters would lead to negative return -> stream error
+ // char c = uartBuffer[rIndex++];
+
+ uint8_t c = uartBuffer[rIndex++];
+ // printf("(%02x) ", c);
+ if (c == '\r') {
+ c = '\n';
+ }
+ putchar(c); // echo on terminal
+ return c;
+ }
+
+ static FILE mystdout = { 0, 0, _FDEV_SETUP_WRITE , 0, 0, uart_putchar, NULL, 0 };
+ static FILE mystderr = { 0, 0, _FDEV_SETUP_WRITE , 0, 0, uart_putchar, NULL, 0 };
+ static FILE mystdin = { 0, 0, _FDEV_SETUP_READ , 0, 0, NULL, uart_getchar, 0 };
static volatile uint32_t timer1ms = 0;
static volatile int keyUart0 = EOF;
Motor motor;
PortExp portExp;
Lcd lcd;
+ Modbus modbus;
}
stdout = &mystdout;
stderr = &mystderr;
+ stdin = &mystdin;
sei();
- printf("\n\nTEST Nano-X-Base\n");
- printf("======================================");
-
-
- TestUnit *unit[] = { &led, &sw, &rgb, &seg7, &poti, &encoder, &r2r, &motor, &portExp, &lcd };
-
- for (uint8_t i = 0; i < sizeof(unit) / sizeof(unit[0]); i++) {
+ TestUnit *unit[] = { &led, &sw, &rgb, &seg7, &poti, &encoder, &r2r, &motor, &portExp, &lcd, &modbus };
+
+ while (1) {
+ uint16_t i;
+ char s[4];
+ do {
+ printf("\n\n=============================\n\n");
+ printf("Available units:\n\n");
+ for (i = 0; i < sizeof(unit) / sizeof(unit[0]); i++) {
+ TestUnit *pu = unit[i];
+ printf("%3x ... %s\n", i, pu->getName());
+ }
+ printf("\nSelect unit: ");
+ rIndex = 0; wIndex = 0;
+ fgets(s, sizeof(s), stdin);
+ } while (sscanf(s, "%x", &i) != 1 || i < 0 || i >= sizeof(unit) / sizeof(unit[0]) );
+
TestUnit *pu = unit[i];
printf("\n\n[%s]: ", pu->getName());
- printf("Press >ESC< to skip unit, any other key to start\n");
- wait(0xffffffff);
- if (keyUart0 == 27) {
- keyUart0 = EOF;
- continue;
- }
keyUart0 = EOF;
for (uint8_t subtest = 0; subtest < 0xff; subtest++) {
}
pu->cleanup();
}
-
- printf("\n\nTest finished. \n");
- return 0;
}
ISR (USART0_RX_vect) {
uint8_t b = UDR0;
keyUart0 = b;
+ uartBuffer[wIndex++] = b;
+ // printf(" w%d(%02x)", wIndex, b);
+ if (wIndex == rIndex) {
+ // buffer overflow, kick out oldest byte
+ rIndex++;
+ }
+}
+
+ISR (USART1_RX_vect) {
+ uint8_t b = UDR1;
+ if (modbus.enabled) {
+ modbus.handleRxByte(b);
+ }
}
ISR (TIMER2_COMPA_vect) { // every 100us
--- /dev/null
+#include <stdio.h>
+#include <avr/io.h>
+#include <util/delay.h>
+
+#include "modbus.hpp"
+#include "../main.hpp"
+
+// 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::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("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(" 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("0x%02x received", received[0]);
+ receivedBytes = 0;
+ } else {
+ printf("no byte received");
+ }
+ printf(" ... 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("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("\n => Sending:");
+ for (uint8_t i = 0; i < sizeof(frame); i++) {
+ printf(" 0x%02x", frame[i]);
+ }
+ int k = wait(100);
+
+ printf("\n RxD1:");
+ if (receivedBytes == 0) {
+ printf("?");
+ } else {
+ for (uint8_t i = 0; i < receivedBytes; i++) {
+ if (i == sizeof(frame)) {
+ printf(" ");
+ }
+ printf(" 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(" -> %4.8fV\n", (double)f.value);
+ }
+ if (k != EOF) {
+ break;
+ }
+
+ } while (wait(1000) == EOF);
+
+ } else {
+ printf("end");
+ return -1;
+ }
+ wait(500);
+ return 0;
+}
+
+void Modbus::handleRxByte (uint8_t b) {
+ if (receivedBytes < sizeof(received)) {
+ received[receivedBytes++] = b;
+ }
+}