]> git.tdb.fi Git - r2c2.git/commitdiff
Add a program for serial port control and associated Arduino firmware
authorMikko Rasa <tdb@tdb.fi>
Sat, 3 Apr 2010 09:49:02 +0000 (09:49 +0000)
committerMikko Rasa <tdb@tdb.fi>
Sat, 3 Apr 2010 09:49:02 +0000 (09:49 +0000)
Make network client handle error packets
Add function to get all trains from the client

Build
firmware/Makefile [new file with mode: 0644]
firmware/ctrl.c [new file with mode: 0644]
source/network/client.cpp
source/network/client.h
source/serial/serial.cpp [new file with mode: 0644]
source/serial/serial.h [new file with mode: 0644]

diff --git a/Build b/Build
index a69a03da0906407452619ed64d8af0a0b8c60feb..9be8021817cb64ba9e1242a9a78a2389f616e908 100644 (file)
--- a/Build
+++ b/Build
@@ -77,4 +77,14 @@ package "märklin"
                        library "marklinnet";
                };
        };
+
+       program "serial"
+       {
+               source "source/serial";
+               build_info
+               {
+                       incpath "source";
+                       library "marklinnet";
+               };
+       };
 };
diff --git a/firmware/Makefile b/firmware/Makefile
new file mode 100644 (file)
index 0000000..68d6f4c
--- /dev/null
@@ -0,0 +1,23 @@
+# $Id$
+
+MCU = atmega328p
+CLOCK = 16000000
+CFLAGS = -Wall -Os -ffunction-sections -fdata-sections -mmcu=$(MCU) -DF_CPU=$(CLOCK)
+LDFLAGS = -Os -Wl,--gc-sections -mmcu=$(MCU)
+
+help:
+       @echo "Targets:"
+       @echo "  %.hex:    Build firmware from %.c"
+       @echo "  upload-%: Upload firmware to AVR"
+
+%.hex: %.elf
+       avr-objcopy -O ihex $< $@
+
+%.elf: %.o
+       avr-gcc $(LDFLAGS) -o $@ $<
+
+%.o: %.c
+       avr-gcc -c $(CFLAGS) -o $@ $<
+
+upload-%: %.hex
+       avrdude -p$(MCU) -cstk500v1 -P/dev/ttyUSB0 -b57600 -D -Uflash:w:$<:i
diff --git a/firmware/ctrl.c b/firmware/ctrl.c
new file mode 100644 (file)
index 0000000..523c702
--- /dev/null
@@ -0,0 +1,228 @@
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+
+#define BIT(n) (1<<(n))
+#define NOP() __asm__("nop");
+
+uint8_t digits[11] =
+{
+       0x3F,
+       0x06,
+       0x5B,
+       0x4F,
+       0x66,
+       0x6D,
+       0x7D,
+       0x07,
+       0x7F,
+       0x6F,
+       0x40
+};
+
+uint16_t read_input(void);
+uint16_t read_input_filtered(void);
+void write_serial(uint8_t);
+void write_7seg(uint8_t);
+
+uint8_t speed = 0;
+uint16_t funcs = 0;
+volatile uint8_t ticks = 0;
+volatile uint8_t rx_buf[3];
+volatile uint8_t rx_fill = 0;
+
+ISR(TIMER1_COMPA_vect)
+{
+       if(ticks<255)
+               ++ticks;
+}
+
+ISR(USART_RX_vect)
+{
+       uint8_t c = UDR0;
+       if(rx_fill==0)
+       {
+               if(c=='A' || c=='S')
+                       rx_buf[rx_fill++] = c;
+       }
+       else
+       {
+               rx_buf[rx_fill++] = c;
+               if(rx_buf[0]=='A' && rx_fill==3)
+               {
+                       uint8_t n = (rx_buf[1]-'0')*10+(rx_buf[2]-'0');
+                       write_7seg(n/10);
+                       write_7seg(n%10);
+                       rx_fill = 0;
+               }
+               else if(rx_buf[0]=='S' && rx_fill==3)
+               {
+                       speed = (rx_buf[1]-'0')*10+(rx_buf[2]-'0');
+                       rx_fill = 0;
+               }
+       }
+}
+
+int main()
+{
+       uint16_t state = 0;
+
+       DDRD = 0x02;   // 00000010
+       PORTD = 0xFC;  // 11111100
+       DDRB = 0x3F;   // 00111111
+       PORTB = 0x0F;  // 00001111
+
+       write_7seg(10);
+       write_7seg(10);
+
+       // 9600 baud, 8N1
+       UBRR0H = 0;
+       UBRR0L = 103;
+       UCSR0C = BIT(UCSZ00) | BIT(UCSZ01);
+       UCSR0B = BIT(RXEN0) | BIT(TXEN0) | BIT(RXCIE0);
+
+       TCCR1A = 0;
+       TCCR1B = BIT(WGM12) | BIT(CS12);
+       OCR1AH = 24;
+       OCR1AL = 106;
+       TIMSK1 = BIT(OCIE1A);
+
+       sei();
+
+       while(1)
+       {
+               uint16_t toggled;
+               uint8_t i;
+               uint16_t input;
+
+               input = read_input_filtered();
+               input ^= 0xFFFC;
+
+               toggled = state^input;
+               state = input;
+
+               if((toggled&3)==2 && (state&1))
+               {
+                       uint8_t action = 0;
+                       if(state&2)
+                       {
+                               if(speed<14)
+                               {
+                                       ++speed;
+                                       action = 1;
+                               }
+                       }
+                       else
+                       {
+                               if(speed>0)
+                               {
+                                       --speed;
+                                       action = 1;
+                               }
+                               else if(ticks>10)
+                                       action = 2;
+                       }
+
+                       if(action==1)
+                       {
+                               write_serial('S');
+                               write_serial('0'+speed/10);
+                               write_serial('0'+speed%10);
+                       }
+                       else if(action==2)
+                               write_serial('R');
+
+                       ticks = 0;
+               }
+
+               for(i=0; i<14; ++i)
+               {
+                       uint16_t bit = 4<<i;
+                       if(toggled&~state&bit)
+                       {
+                               if(i==0)
+                                       write_serial('N');
+                               else if(i==1)
+                                       write_serial('P');
+                               else
+                               {
+                                       uint8_t f = i-2;
+                                       uint16_t fbit = 1<<f;
+                                       funcs ^= fbit;
+                                       write_serial((funcs&fbit) ? 'H' : 'L');
+                                       write_serial('0'+f);
+                               }
+                       }
+               }
+       }
+}
+
+uint16_t read_input(void)
+{
+       uint8_t row;
+       uint16_t input = 0;
+
+       for(row=0; row<4; ++row)
+       {
+               uint8_t pins;
+
+               PORTB = (PORTB|0x0F)&~(1<<row);
+               NOP();
+               NOP();
+               NOP();
+               NOP();
+               NOP();
+               NOP();
+               pins = PIND>>2;
+               input |= pins&3;
+               input |= (pins&0x3C)<<(row*4);
+       }
+
+       return input;
+}
+
+uint16_t read_input_filtered(void)
+{
+       uint16_t valid = 0xFFFF;
+       uint16_t prev;
+       uint16_t input;
+       uint8_t i;
+
+       prev = read_input();
+       for(i=0; i<20; ++i)
+       {
+               input = read_input();
+               valid &= ~(input^prev);
+               prev = input;
+       }
+
+       return input&valid;
+}
+
+void write_serial(uint8_t c)
+{
+       while(!(UCSR0A&(1<<UDRE0))) ;
+       UDR0 = c;
+}
+
+void write_7seg(uint8_t n)
+{
+       uint8_t segs = ~digits[n];
+       uint8_t i;
+       for(i=0; i<8; ++i)
+       {
+               PORTB &= ~0x20;
+               if(segs&0x80)
+                       PORTB |= 0x10;
+               else
+                       PORTB &= ~0x10;
+               PORTB |= 0x20;
+               segs <<= 1;
+       }
+}
index 8e31cfe54c59b9cfe5e501722b31c112e36ea3c7..2e003842e9c007e9c75334bd80e4765fb0ba143a 100644 (file)
@@ -43,9 +43,9 @@ void Client::connect(const Net::SockAddr &addr)
        comm = new Net::Communicator(*socket, proto, *this);
 }
 
-NetTrain &Client::get_train(unsigned addr)
+NetTrain &Client::get_train(unsigned addr) const
 {
-       map<unsigned, NetTrain *>::iterator i = trains.find(addr);
+       map<unsigned, NetTrain *>::const_iterator i = trains.find(addr);
        if(i==trains.end())
                throw KeyError("Unknown train");
        return *i->second;
@@ -83,4 +83,9 @@ void Client::receive(const TrainRoutePacket &pkt)
        get_train(pkt.address).process_packet(pkt);
 }
 
+void Client::receive(const ErrorPacket &pkt)
+{
+       signal_error.emit(pkt.message);
+}
+
 } // namespace Marklin
index 3a9cbc0717a659cc042e8874b6333d5f099b0f89..39c7eb035c16ae82bacab2a12f2f7c803e34276c 100644 (file)
@@ -22,10 +22,12 @@ class Client: public Msp::Net::PacketReceiver<TrainInfoPacket>,
        Msp::Net::PacketReceiver<TrainFunctionPacket>,
        Msp::Net::PacketReceiver<TrainStatusPacket>,
        Msp::Net::PacketReceiver<RouteInfoPacket>,
-       Msp::Net::PacketReceiver<TrainRoutePacket>
+       Msp::Net::PacketReceiver<TrainRoutePacket>,
+       Msp::Net::PacketReceiver<ErrorPacket>
 {
 public:
        sigc::signal<void, NetTrain &> signal_train_added;
+       sigc::signal<void, const std::string &> signal_error;
 
 private:
        const Catalogue &catalogue;
@@ -49,7 +51,8 @@ public:
 
        const Catalogue &get_catalogue() const { return catalogue; }
        const std::list<std::string> &get_routes() const { return routes; }
-       NetTrain &get_train(unsigned);
+       NetTrain &get_train(unsigned) const;
+       const std::map<unsigned, NetTrain *> &get_trains() const { return trains; }
 
 private:
        virtual void receive(const TrainInfoPacket &);
@@ -58,6 +61,7 @@ private:
        virtual void receive(const TrainStatusPacket &);
        virtual void receive(const RouteInfoPacket &);
        virtual void receive(const TrainRoutePacket &);
+       virtual void receive(const ErrorPacket &);
 };
 
 } // namespace Marklin
diff --git a/source/serial/serial.cpp b/source/serial/serial.cpp
new file mode 100644 (file)
index 0000000..2766752
--- /dev/null
@@ -0,0 +1,130 @@
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <msp/net/resolve.h>
+#include "serial.h"
+
+#include <msp/io/print.h>
+
+using namespace std;
+using namespace Msp;
+using namespace Marklin;
+       
+Application::RegApp<Serial> Serial::reg;
+
+Serial::Serial(int, char **argv):
+       client(catalogue),
+       serial_port(argv[2]),
+       train(0),
+       rx_fill(0)
+{
+       DataFile::load(catalogue, "locos.dat");
+
+       client.use_event_dispatcher(event_disp);
+       client.signal_train_added.connect(sigc::mem_fun(this, &Serial::train_added));
+       client.signal_error.connect(sigc::mem_fun(this, &Serial::error));
+
+       string addr_str = argv[1];
+       if(addr_str.find(':')==string::npos)
+               addr_str += ":8315";
+       Net::SockAddr *addr = Net::resolve(addr_str);
+       client.connect(*addr);
+       delete addr;
+
+       serial_port.set_parameters("9600,8N1");
+       event_disp.add(serial_port);
+       serial_port.signal_data_available.connect(sigc::mem_fun(this, &Serial::data_available));
+}
+
+void Serial::tick()
+{
+       event_disp.tick();
+}
+
+void Serial::train_added(NetTrain &t)
+{
+       if(!train)
+               set_train(&t);
+}
+
+void Serial::error(const string &e)
+{
+       IO::print("%s\n", e);
+}
+
+void Serial::set_train(NetTrain *t)
+{
+       train = t;
+       serial_port.write(format("A%02d", train->get_address()));
+}
+
+void Serial::next_train()
+{
+       const map<unsigned, NetTrain *> &trains = client.get_trains();
+
+       map<unsigned, NetTrain *>::const_iterator i = trains.find(train->get_address());
+       ++i;
+       if(i==trains.end())
+               i = trains.begin();
+
+       set_train(i->second);
+}
+
+void Serial::prev_train()
+{
+       const map<unsigned, NetTrain *> &trains = client.get_trains();
+
+       map<unsigned, NetTrain *>::const_iterator i = trains.find(train->get_address());
+       if(i==trains.begin())
+               i = trains.end();
+       --i;
+
+       set_train(i->second);
+}
+
+void Serial::data_available()
+{
+       char c;
+       serial_port.read(&c, 1);
+       if(rx_fill==0)
+       {
+               if(c=='S' || c=='H' || c=='L')
+                       rx_buf[rx_fill++] = c;
+               else if(c=='R')
+               {
+                       IO::print("Reverse\n");
+                       train->set_reverse(!train->get_reverse());
+               }
+               else if(c=='N')
+                       next_train();
+               else if(c=='P')
+                       prev_train();
+       }
+       else
+       {
+               rx_buf[rx_fill++] = c;
+               if(rx_buf[0]=='H' && rx_fill==2)
+               {
+                       train->set_function(rx_buf[1]-'0', true);
+                       IO::print("Func %d on\n", rx_buf[1]-'0');
+                       rx_fill = 0;
+               }
+               else if(rx_buf[0]=='L' && rx_fill==2)
+               {
+                       train->set_function(rx_buf[1]-'0', false);
+                       IO::print("Func %d off\n", rx_buf[1]-'0');
+                       rx_fill = 0;
+               }
+               else if(rx_buf[0]=='S' && rx_fill==3)
+               {
+                       unsigned speed = (rx_buf[1]-'0')*10+(rx_buf[2]-'0');
+                       IO::print("Set speed %d\n", speed);
+                       train->set_speed(speed);
+                       rx_fill = 0;
+               }
+       }
+}
diff --git a/source/serial/serial.h b/source/serial/serial.h
new file mode 100644 (file)
index 0000000..b5427e4
--- /dev/null
@@ -0,0 +1,41 @@
+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2010  Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#ifndef SERIAL_H_
+#define SERIAL_H_
+
+#include <msp/core/application.h>
+#include <msp/io/serial.h>
+#include "network/client.h"
+
+class Serial: public Msp::Application
+{
+private:
+       Msp::IO::EventDispatcher event_disp;
+       Marklin::Catalogue catalogue;
+       Marklin::Client client;
+       Msp::IO::Serial serial_port;
+       Marklin::NetTrain *train;
+       char rx_buf[3];
+       unsigned rx_fill;
+
+       static Msp::Application::RegApp<Serial> reg;
+
+public:
+       Serial(int, char **);
+
+private:
+       virtual void tick();
+       void train_added(Marklin::NetTrain &);
+       void error(const std::string &);
+       void set_train(Marklin::NetTrain *);
+       void next_train();
+       void prev_train();
+       void data_available();
+};
+
+#endif