/* Copyright (C) 2000 T. Scott Dattalo 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. */ /* led.cc This is an example module illustrating how gpsim modules may be created. Additional examples may also be found with the gpsim. This particular example creates a 7-segment, common cathode LED display. Pin Numbering of LED: -------------------- a --- f | g | b --- e | | c --- d cc = common cathode Electrical: ---------- a ---|>|---+ b ---|>|---+ c ---|>|---+ d ---|>|---+ e ---|>|---+ f ---|>|---+ g ---|>|---+ | cc How It Works: ------------ Once the Led module has been built (and optionally installed), you can include it in your .stc file. See the examples subdirectory. */ /* IN_MODULE should be defined for modules */ #define IN_MODULE #include #include #include #include #include "../config.h" // get the definition for HAVE_GUI #ifdef HAVE_GUI #include #include #include "../src/gpsim_interface.h" #include "../src/gpsim_time.h" #include "led.h" #include "../src/packages.h" namespace Leds { //-------------------------------------------------------------- // // Create an "interface" to gpsim // class LED_Interface : public Interface { private: Led_base *led; int lastport; public: virtual void SimulationHasStopped (gpointer object) { GuiUpdate(object); } virtual void GuiUpdate (gpointer object) { if(led) led->update(); /* { int portval = led->port->get_value(); if(lastport != portval) { lastport=portval; led->update(); } } */ } LED_Interface(Led_base *_led) : Interface((gpointer *) _led) { led = _led; lastport = -1; } }; class Led_Input : public IOPIN { public: Led_Input(const char *n, Led_base *pParent); virtual void setDrivenState(bool); private: Led_base *m_pParent; }; //------------------------------------------------------------------------ // Led_Input::Led_Input(const char *n, Led_base *pParent) : IOPIN(n), m_pParent(pParent) { } void Led_Input::setDrivenState(bool bNewState) { IOPIN::setDrivenState(bNewState); } //------------------------------------------------------------------------ void Led_7Segments::update() { update(darea, w_width,w_height); } void Led_7Segments::callback() { get_cycles().set_break_delta( get_interface().get_update_rate()+1, this); update(); } void Led_7Segments::update( GtkWidget *widget, guint new_width, guint new_height) { guint i; w_width = new_width; w_height = new_height; GdkDrawable *drawable = widget->window; if(!GTK_WIDGET_REALIZED(widget)) return; if(segment_gc==NULL) { segment_gc = gdk_gc_new(darea->window); gdk_gc_set_line_attributes(segment_gc, 5, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND); g_assert(segment_gc!=NULL); } // not a very O-O way of doing it... but here we go directly // to the I/O port and get the values of the segments int segment_states = getPinState(); GdkGC *gc = segment_gc; gdk_gc_set_foreground(gc, &led_background_color); gdk_draw_rectangle (drawable, gc, TRUE, 0, 0, w_width, w_height); // cout << "expose led, segment states = " << segment_states << '\n'; if( (segment_states & 1) == 0) { // common cathode, cathode must be low to turn //digits on. gdk_gc_set_foreground(gc,&led_segment_on_color); for(i=0; i<7; i++) { if(segment_states & (2<allocation.width; max_height = widget->allocation.height; led->update(widget,max_width,max_height); return TRUE; } static gint cursor_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) { if ((event->type == GDK_BUTTON_PRESS) && ((event->button.button == 1) || (event->button.button == 3))) { return TRUE; } return FALSE; } //------------------------------------------------------------------- // build_segments // // from Dclock.c (v.2.0) -- a digital clock widget. // Copyright (c) 1988 Dan Heller // Modifications 2/93 by Tim Edwards // And further modifications by Scott Dattalo // // Each segment on the LED is comprised of a 6 point polygon. // This routine will calculate what those points should be and // store them an arrary. void Led_7Segments::build_segments( int w, int h) { XfPoint *pts; float spacer, hskip, fslope, bslope, midpt, seg_width, segxw; float invcosphi, invsinphi, invcospsi, invsinpsi, slope; float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy5, dy6; float xfactor, temp_xpts[4]; w_width = w; w_height = h; // Hard code the display parameters... space_factor = (float)0.13; width_factor = (float)0.13; sxw = (float)0.13; angle = 6; /* define various useful constants */ segxw = sxw * w; slope = angle; seg_width = width_factor * w; spacer = (float)w * space_factor; hskip = (float)(seg_width * 0.125); fslope = 1 / (segxw/seg_width + 1/slope); bslope = -1 / (segxw/seg_width - 1/slope); midpt = (float)h / 2; /* define some trigonometric values */ /* phi is the forward angle separating two segments; psi is the reverse angle separating two segments. */ invsinphi = sqrt(1 + fslope * fslope) / fslope; invcosphi = sqrt(1 + 1/(fslope * fslope)) * fslope; invsinpsi = sqrt(1 + bslope * bslope) / -bslope; invcospsi = sqrt(1 + 1/(bslope * bslope)) * bslope; /* define offsets from easily-calculated points for 6 situations */ dx1 = hskip * invsinphi / (slope/fslope - 1); dy1 = hskip * invcosphi / (1 - fslope/slope); dx2 = hskip * invsinpsi / (1 - slope/bslope); dy2 = hskip * invcospsi / (bslope/slope - 1); dx3 = hskip * invsinphi; dx4 = hskip * invsinpsi; dx5 = hskip * invsinpsi / (1 - fslope/bslope); dy5 = hskip * invcospsi / (bslope/fslope - 1); dx6 = dy5; dy6 = dx5; /* calculate some simple reference points */ temp_xpts[0] = spacer + (h - seg_width)/slope; temp_xpts[1] = spacer + (h - seg_width/2)/slope + segxw/2; temp_xpts[2] = spacer + h/slope + segxw; temp_xpts[3] = temp_xpts[0] + segxw; xfactor = w - 2 * spacer - h / slope - segxw; /* cout << "temp_xpts[2] " << temp_xpts[2] << '\n'; cout << "dx3 " << dx3 << '\n'; cout << "fslope " << fslope << '\n'; */ /* calculate the digit positions */ pts = seg_pts[TOP]; pts[0].y = pts[1].y = 0; pts[0].x = temp_xpts[2] - dx3; pts[1].x = w - spacer - segxw + dx4; pts[2].y = pts[5].y = (seg_width / 2) - dy5 - dy6; pts[5].x = temp_xpts[1] + dx5 - dx6; pts[2].x = pts[5].x + xfactor; pts[3].y = pts[4].y = seg_width; pts[4].x = temp_xpts[3] + dx4; pts[3].x = temp_xpts[0] + xfactor - dx3; pts = &(seg_pts[MIDDLE][0]); pts[0].y = pts[1].y = midpt - seg_width/2; pts[0].x = spacer + (h - pts[0].y)/slope + segxw; pts[1].x = pts[0].x - segxw + xfactor; pts[2].y = pts[5].y = midpt; pts[3].y = pts[4].y = midpt + seg_width/2; pts[5].x = spacer + (h - pts[5].y)/slope + segxw/2; pts[2].x = pts[5].x + xfactor; pts[4].x = pts[0].x - seg_width/slope; pts[3].x = spacer + (h - pts[3].y)/slope + xfactor; pts = &(seg_pts[BOTTOM][0]); pts[3].y = pts[4].y = (float)h; pts[2].y = pts[5].y = h - (seg_width / 2) + dy5 + dy6; pts[0].y = pts[1].y = h - seg_width; pts[0].x = spacer + segxw + seg_width/slope + dx3; pts[1].x = spacer + (h - pts[1].y)/slope + xfactor - dx4; pts[4].x = spacer + segxw - dx4; pts[5].x = spacer + segxw/2 + (h - pts[5].y)/slope + dx6 - dx5; pts[2].x = pts[5].x + xfactor; pts[3].x = spacer + xfactor + dx3; pts = &(seg_pts[TOP_LEFT][0]); pts[0].y = seg_width / 2 - dy6 + dy5; pts[1].y = seg_width + dy2; pts[2].y = seg_pts[MIDDLE][0].y - 2 * dy1; pts[3].y = seg_pts[MIDDLE][5].y - 2 * dy6; pts[4].y = seg_pts[MIDDLE][0].y; pts[5].y = seg_width - dy1; pts[0].x = temp_xpts[1] - dx5 - dx6; pts[1].x = temp_xpts[3] - dx2; pts[2].x = seg_pts[MIDDLE][0].x + 2 * dx1; pts[3].x = seg_pts[MIDDLE][5].x - 2 * dx6; pts[4].x = spacer + (h - pts[4].y)/slope; pts[5].x = temp_xpts[0] + dx1; pts = &(seg_pts[BOT_LEFT][0]); pts[0].y = seg_pts[MIDDLE][5].y + 2 * dy5; pts[1].y = seg_pts[MIDDLE][4].y + 2 * dy2; pts[2].y = seg_pts[BOTTOM][0].y - dy1; pts[3].y = seg_pts[BOTTOM][5].y - 2 * dy6; pts[4].y = h - seg_width + dy2; pts[5].y = midpt + seg_width/2; pts[0].x = seg_pts[MIDDLE][5].x - 2 * dx5; pts[1].x = seg_pts[MIDDLE][4].x - 2 * dx2; pts[2].x = seg_pts[BOTTOM][0].x - dx3 + dx1; pts[3].x = seg_pts[BOTTOM][5].x - 2 * dx6; pts[4].x = spacer + seg_width / slope - dx2; pts[5].x = spacer + (midpt - seg_width/2) / slope; pts = &(seg_pts[TOP_RIGHT][0]); pts[0].y = seg_width/2 - dy5 + dy6; pts[1].y = seg_width - dy2; pts[2].y = midpt - seg_width/2; pts[3].y = midpt - 2 * dy5; pts[4].y = pts[2].y - 2 * dy2; pts[5].y = seg_width + dy1; pts[0].x = temp_xpts[1] + xfactor + dx5 + dx6; pts[1].x = temp_xpts[3] + xfactor + dx1; pts[2].x = seg_pts[MIDDLE][0].x + xfactor; pts[3].x = seg_pts[MIDDLE][5].x + xfactor + dx5 * 2; pts[4].x = seg_pts[TOP_LEFT][4].x + xfactor + dx2 * 2; pts[5].x = temp_xpts[0] + xfactor - dx1; pts = &(seg_pts[BOT_RIGHT][0]); pts[0].y = seg_pts[MIDDLE][2].y + 2 * dy6; pts[1].y = midpt + seg_width / 2; pts[2].y = h - seg_width + dy1; pts[3].y = h - (seg_width / 2) + dy6 - dy5; pts[4].y = h - seg_width - dy2; pts[5].y = seg_pts[MIDDLE][3].y + 2 * dy1; pts[0].x = seg_pts[MIDDLE][2].x + 2 * dx6; pts[1].x = seg_pts[MIDDLE][3].x + segxw; pts[2].x = seg_pts[BOTTOM][1].x + dx4 + segxw - dx1; pts[3].x = seg_pts[BOTTOM][2].x + 2 * dx5; pts[4].x = seg_pts[BOTTOM][1].x + dx4 + dx2; pts[5].x = seg_pts[MIDDLE][3].x - 2 * dx1; // Convert the floating point points into integers. int i,j; for(i=0; iset_pin_position(1,pos);pos+=dp; package->set_pin_position(2,pos);pos+=dp; package->set_pin_position(3,pos);pos+=dp; package->set_pin_position(4,pos);pos+=dp; package->set_pin_position(5,pos);pos+=dp; package->set_pin_position(6,pos);pos+=dp; package->set_pin_position(7,pos);pos+=dp; package->set_pin_position(8,pos);pos+=dp; // Here, we create and name the I/O pins. In gpsim, we will reference // the bit positions as LED.seg0, LED.seg1, ..., where LED is the // user-assigned name of the 7-segment LED m_pins[0] = new Led_Input( (name() + ".cc").c_str(), this); int i; char ch; for (ch='0',i = 1; i<8; i++,ch++) m_pins[i] = new Led_Input((name() + ".seg"+ch).c_str(), this); for (i=0; i<8; i++) assign_pin(i+1,m_pins[i]); initializeAttributes(); } //-------------------------------------------------------------- unsigned int Led_7Segments::getPinState() { unsigned int s=0; for (int i=0; i<8; i++) s = (s>>1) | (m_pins[i]->getDrivenState() ? 0x80 : 0); return s; } //-------------------------------------------------------------- // construct Module * Led_7Segments::construct(const char *_new_name=0) { Led_7Segments *l7sP = new Led_7Segments ; l7sP->new_name(_new_name); l7sP->create_iopin_map(); return l7sP; } //------------------------------------------------------------- // Led (simple) //------------------------------------------------------------- void Led::update() { update(darea, w_width,w_height); } void Led::callback() { get_cycles().set_break_delta( get_interface().get_update_rate()+1, this); update(); } void Led::update( GtkWidget *widget, guint new_width, guint new_height) { if(!get_interface().bUsingGUI()) return; w_width = new_width; w_height = new_height; GdkDrawable *drawable = widget->window; if(!GTK_WIDGET_REALIZED(widget)) return; if(gc==NULL) { gc = gdk_gc_new(darea->window); gdk_gc_set_line_attributes(gc, 5, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND); g_assert(gc!=NULL); } gdk_gc_set_foreground(gc,&led_segment_off_color); gdk_draw_rectangle (drawable, gc, TRUE, 0, 0, w_width, w_height); if(m_pin->getDrivenState()) { gdk_gc_set_foreground(gc,&led_segment_on_color); gdk_draw_arc(drawable, gc, TRUE, 0, 0, w_width, w_height, 0,64*360); } } static gint led_expose_event (GtkWidget *widget, GdkEvent *event, gpointer user_data) { Led *led; guint max_width; guint max_height; g_return_val_if_fail (widget != NULL, TRUE); g_return_val_if_fail (GTK_IS_DRAWING_AREA (widget), TRUE); // de-reference the user_data into an led object led = (Led *)user_data; max_width = widget->allocation.width; max_height = widget->allocation.height; led->update(widget,max_width,max_height); return TRUE; } void Led::build_window() { GtkWidget *main_vbox; main_vbox = gtk_vbox_new (FALSE, 5); gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 0); darea = gtk_drawing_area_new (); w_height=20; w_width=20; gtk_widget_set_usize (darea, w_height, w_width); gtk_signal_connect (GTK_OBJECT (darea), "expose_event", GTK_SIGNAL_FUNC (led_expose_event), this); gtk_widget_set_events (darea, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK); gtk_widget_show (darea); set_widget(darea); gc=NULL; // The 'on' color is bright red led_segment_on_color.red = 0xc000; led_segment_on_color.green = 0x0000; led_segment_on_color.blue = 0x0000; gdk_color_alloc(gdk_colormap_get_system(), &led_segment_on_color); // The `off' color is dark red led_segment_off_color.red = 0x4000; led_segment_off_color.green = 0x0000; led_segment_off_color.blue = 0x0000; gdk_color_alloc(gdk_colormap_get_system(), &led_segment_off_color); } //-------------------------------------------------------------- Led::Led() { new_name("LED"); if(get_interface().bUsingGUI()) build_window(); interface = new LED_Interface(this); get_interface().add_interface(interface); callback(); } Led::~Led() { delete m_pin; } //-------------------------------------------------------------- // 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 Led::create_iopin_map() { create_pkg(1); // Position pin on left side of package package->set_pin_position(1,0.5); // Define the LED Cathode. (The anode is implicitly tied to VCC) m_pin = new Led_Input((name() + ".in").c_str(), this); assign_pin(1, m_pin); initializeAttributes(); } //-------------------------------------------------------------- // construct Module * Led::construct(const char *_new_name=0) { Led *ledP = new Led; ledP->new_name(_new_name); ledP->create_iopin_map(); return ledP; } } #endif //HAVE_GUI