/* Copyright (C) 2004 Chris Emerson (Based on the push_button Copyright (C) 2002 Carlos Ghirardelli) This file is part of gpsim. gpsim is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. gpsim 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 General Public License for more details. You should have received a copy of the GNU General Public License along with gpsim; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* encoder.cc */ /* IN_MODULE should be defined for modules */ #define IN_MODULE #include #include #include #include #include #include #include #include #include #include #include "../config.h" // get the definition for HAVE_GUI #ifdef HAVE_GUI #include #include "../src/gpsim_time.h" #include "../src/packages.h" #include "encoder.h" #define PIN_A (0x01) #define PIN_B (0x02) //-------------------------------------------------------------- // create_iopin_map // // This is where the information for the Module's package is defined. // Specifically, the I/O pins of the module are created. void Encoder::create_iopin_map(void) { // Define the physical package. // The Package class, which is a parent of all of the modules, // is responsible for allocating memory for the I/O pins. // create_pkg(2); // Define the I/O pins and assign them to the package. // There are two things happening here. First, there is // a new I/O pin that is being created. For the binary // indicator, both pins are inputs. The second thing is // that the pins are "assigned" to the package. If we // need to reference these newly created I/O pins (like // below) then we can call the member function 'get_pin'. a_pin = new IO_bi_directional((name() + ".a").c_str()); assign_pin(1, a_pin); package->set_pin_position(1,(float)0.0); b_pin = new IO_bi_directional((name() + ".b").c_str()); assign_pin(1, b_pin); package->set_pin_position(2,(float)0.9999); // Create an entry in the symbol table for the new I/O pins. // This is how the pins are accessed at the higher levels (like // in the CLI). if(a_pin) { get_symbol_table().add_stimulus(a_pin); a_pin->update_direction(1,true); if(a_pin->snode) a_pin->snode->update(); } if(b_pin) { get_symbol_table().add_stimulus(b_pin); b_pin->update_direction(1,true); if(b_pin->snode) b_pin->snode->update(); } } //-------------------------------------------------------------- // GUI static void cw_cb (GtkButton *button, Encoder *enc) { enc->send_cw(); } static void ccw_cb (GtkButton *button, Encoder *enc) { enc->send_ccw(); } void Encoder::create_widget(Encoder *enc) { GtkWidget *box1; GtkWidget *buttonl, *buttonr; box1 = gtk_hbox_new (FALSE, 0); buttonl = gtk_button_new_with_label ("ccw"); buttonr = gtk_button_new_with_label (" cw"); gtk_container_set_border_width (GTK_CONTAINER (buttonl), 5); gtk_container_set_border_width (GTK_CONTAINER (buttonr), 5); gtk_signal_connect (GTK_OBJECT (buttonl), "pressed", GTK_SIGNAL_FUNC (ccw_cb), (gpointer)enc); gtk_signal_connect (GTK_OBJECT (buttonr), "pressed", GTK_SIGNAL_FUNC (cw_cb), (gpointer)enc); gtk_widget_show(buttonl); gtk_widget_show(buttonr); gtk_box_pack_start (GTK_BOX (box1), buttonl, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (box1), buttonr, FALSE, FALSE, 0); // Tell gpsim which widget to use in breadboard. enc->set_widget(box1); } //-------------------------------------------------------------- // construct Module * Encoder::construct(const char *_new_name=NULL) { Encoder *enc_p = new Encoder ; enc_p->new_name(_new_name); enc_p->create_iopin_map(); enc_p->create_widget(enc_p); return enc_p; } Encoder::Encoder(void) : rs(rot_detent) { name_str = strdup("Encoder"); } Encoder::~Encoder(void) { delete a_pin; delete b_pin; } void Encoder::send_cw(void) { switch (rs) { case rot_detent: rs = rot_moving_cw; toggle_a(); /* A toggles before B going clockwise */ schedule_tick(); break; default: // XXX: ought to do something here as well break; } } void Encoder::send_ccw(void) { switch (rs) { case rot_detent: rs = rot_moving_ccw; toggle_b(); schedule_tick(); break; default: // XXX: ought to do something here as well break; } } void Encoder::toggle_a() { a_pin->toggle(); } void Encoder::toggle_b() { b_pin->toggle(); } void Encoder::schedule_tick() { /* XXX: make the time delay configurable */ if (!get_cycles().set_break_delta(100, this)) { std::cerr << "Encoder: error setting breakpoint." << std::endl; } } void Encoder::callback() { switch (rs) { case rot_detent: assert(false); break; case rot_moving_cw: toggle_b(); rs = rot_detent; break; case rot_moving_ccw: toggle_a(); rs = rot_detent; break; default: abort(); } } #endif // HAVE_GUI