Added new Panel stuff
authorJim Morris <morris@wolfman.com>
Sun, 23 Jun 2013 09:34:29 +0000 (02:34 -0700)
committerJim Morris <morris@wolfman.com>
Sun, 23 Jun 2013 09:34:29 +0000 (02:34 -0700)
30 files changed:
ConfigSamples/Smoothieboard/config
src/libs/Kernel.h
src/main.cpp
src/modules/robot/Conveyor.cpp
src/modules/robot/Robot.cpp
src/modules/utils/panel/Button.h [new file with mode: 0644]
src/modules/utils/panel/Panel.cpp [new file with mode: 0644]
src/modules/utils/panel/Panel.h [new file with mode: 0644]
src/modules/utils/panel/PanelScreen.cpp [new file with mode: 0644]
src/modules/utils/panel/PanelScreen.h [new file with mode: 0644]
src/modules/utils/panel/panels/I2CLCD.h [new file with mode: 0644]
src/modules/utils/panel/panels/LcdBase.cpp [new file with mode: 0644]
src/modules/utils/panel/panels/LcdBase.h [new file with mode: 0644]
src/modules/utils/panel/panels/VikiLCD.cpp [new file with mode: 0644]
src/modules/utils/panel/panels/VikiLCD.h [new file with mode: 0644]
src/modules/utils/panel/screens/ControlScreen.cpp [new file with mode: 0644]
src/modules/utils/panel/screens/ControlScreen.h [new file with mode: 0644]
src/modules/utils/panel/screens/FileScreen.cpp [new file with mode: 0644]
src/modules/utils/panel/screens/FileScreen.h [new file with mode: 0644]
src/modules/utils/panel/screens/JogScreen.cpp [new file with mode: 0644]
src/modules/utils/panel/screens/JogScreen.h [new file with mode: 0644]
src/modules/utils/panel/screens/MainMenuScreen.cpp [new file with mode: 0644]
src/modules/utils/panel/screens/MainMenuScreen.h [new file with mode: 0644]
src/modules/utils/panel/screens/PrepareScreen.cpp [new file with mode: 0644]
src/modules/utils/panel/screens/PrepareScreen.h [new file with mode: 0644]
src/modules/utils/panel/screens/WatchScreen.cpp [new file with mode: 0644]
src/modules/utils/panel/screens/WatchScreen.h [new file with mode: 0644]
src/modules/utils/player/Player.cpp
src/modules/utils/player/Player.h
src/modules/utils/player/PlayerPublicAccess.h [new file with mode: 0644]

index 3c7e715..193a0a7 100644 (file)
@@ -126,12 +126,18 @@ gamma_homing_retract                         5000              # "
 pause_button_enable                          true             #
 
 # Panel
-panel.enable                                 false            #
-panel.up_button_pin                          0.1!             #
-panel.down_button_pin                        0.0!             #
-panel.click_button_pin                       0.18!            #
-panel.encoder_a_pin                          0.15!            #
-panel.encoder_b_pin                          0.17!            #
+panel.enable                                 false             # set to true to enabel the panel code
+panel.lcd                                    viki_lcd          # set type of panel also i2c_lcd is a generic i2c panel
+panel.encoder_a_pin                          0.15!^            # encoder pin if used
+panel.encoder_b_pin                          0.17!^            # encoder pin if used
+#panel.button_pause_pin                      0.18^             # pin used for pause button on VikiLcd
+#panel.up_button_pin                         0.1!              # up button if used
+#panel.down_button_pin                       0.0!              # down button if used
+#panel.click_button_pin                      0.18!             # click button if used
+
+panel.alpha_jog_feedrate                     6000              # x jogging feedrate in mm/min
+panel.beta_jog_feedrate                      6000              # y jogging feedrate in mm/min
+panel.gamma_jog_feedrate                     200               # z jogging feedrate in mm/min
 
 # Only needed on a smoothieboard
 currentcontrol_module_enable                 true             #
index d770699..1fd3dcb 100644 (file)
@@ -33,6 +33,7 @@ class Kernel {
     public:
         Kernel();
         static Kernel* instance; // the Singleton instance of Kernel usable anywhere
+
         void add_module(Module* module);
         void register_for_event(_EVENT_ENUM id_event, Module* module);
         void call_event(_EVENT_ENUM id_event);
index 563a30c..455e6b7 100644 (file)
@@ -19,6 +19,8 @@
 #include "modules/utils/player/Player.h"
 #include "modules/utils/pausebutton/PauseButton.h"
 #include "modules/utils/PlayLed/PlayLed.h"
+#include "modules/utils/panel/Panel.h"
+
 // #include "libs/ChaNFSSD/SDFileSystem.h"
 #include "libs/Config.h"
 #include "libs/nuts_bolts.h"
@@ -92,6 +94,7 @@ int main() {
     kernel->add_module( new PlayLed() );
     kernel->add_module( new Endstops() );
     kernel->add_module( new Player() );
+       kernel->add_module( new Panel() );
     kernel->add_module( new Touchprobe() );
 
     // Create and initialize USB stuff
index fed2faf..cbbf7b7 100644 (file)
@@ -95,7 +95,7 @@ void Conveyor::pop_and_process_new_block(int debug){
     // Tell all modules about it
     this->kernel->call_event(ON_BLOCK_BEGIN, this->current_block);
 
-    // In case the module was not taken
+       // In case the module was not taken
     if( this->current_block->times_taken < 1 ){
         Block* temp = this->current_block; 
         this->current_block = NULL; // It seems this was missing and adding it fixes things, if something breaks, this may be a suspect 
index 06a643a..cf0beb9 100644 (file)
@@ -116,7 +116,8 @@ void Robot::on_get_public_data(void* argument){
     if(!pdr->starts_with(robot_checksum)) return;
 
     if(pdr->second_element_is(speed_override_percent_checksum)) {
-        static double return_data= 100*60/seconds_per_minute;
+               static double return_data;
+               return_data= 100*this->seconds_per_minute/60;
         pdr->set_data_ptr(&return_data);
         pdr->set_taken();
         
@@ -138,7 +139,7 @@ void Robot::on_set_public_data(void* argument){
 
     if(pdr->second_element_is(speed_override_percent_checksum)) {
         double t= *static_cast<double*>(pdr->get_data_ptr());
-        seconds_per_minute= t * 0.6;
+        this->seconds_per_minute= t * 0.6;
         pdr->set_taken();
     }
 }
@@ -201,7 +202,7 @@ void Robot::on_gcode_received(void * argument){
                 gcode->add_nl = true;
                 gcode->mark_as_taken();
                 return;
-            case 114: gcode->stream->printf("C: X:%1.3f Y:%1.3f Z:%1.3f ",
+                       case 114: gcode->stream->printf("C: X:%1.3f Y:%1.3f Z:%1.3f ",
                                                  from_millimeters(this->current_position[0]),
                                                  from_millimeters(this->current_position[1]),
                                                  from_millimeters(this->current_position[2]));
diff --git a/src/modules/utils/panel/Button.h b/src/modules/utils/panel/Button.h
new file mode 100644 (file)
index 0000000..5c0e2c7
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef BUTTON_H
+#define BUTTON_H
+
+#include <stdlib.h>
+#include "libs/LPC17xx/sLPC17xx.h" // smoothed mbed.h lib
+#include "libs/Kernel.h"
+#include "libs/utils.h"
+#include "libs/Pin.h"
+#include <string>
+#include "libs/Hook.h"
+
+
+class Button{
+    public: 
+        Button(){
+            this->counter = 0;
+            this->value = false;
+            this->up_hook = NULL;
+            this->down_hook = NULL;
+            this->button_pin = NULL;
+        }
+
+        Button* pin(Pin* passed_pin){
+            this->button_pin = passed_pin;
+            return this;
+        }
+
+        void check_signal(){
+            check_signal(this->button_pin->get()?1:0);
+        }
+
+        void check_signal(int val){
+            bool start_value = this->value;
+            if( val ){
+                if( this->counter < 5  ){ this->counter++; }
+                if( this->counter == 5 ){ 
+                    this->value = true; 
+                }
+            }else{
+                if( this->counter > 0  ){ this->counter--; }
+                if( this->counter == 0 ){ 
+                    this->value = false; 
+                }
+            }
+
+            if( start_value != this->value ){
+                if( this->value ){
+                    if( this->up_hook != NULL ){
+                        this->up_hook->call();
+                    } 
+                }else{
+                    if( this->down_hook != NULL ){
+                        this->down_hook->call();
+                    } 
+                }
+            }
+
+        }
+
+        bool get(){
+            return this->value;
+        }
+
+
+        template<typename T> Button* up_attach( T *optr, uint32_t ( T::*fptr )( uint32_t ) ){
+            this->up_hook = new Hook(); 
+            this->up_hook->attach(optr, fptr);
+            return this;
+        }
+
+        template<typename T> Button* down_attach( T *optr, uint32_t ( T::*fptr )( uint32_t ) ){
+            this->down_hook = new Hook(); 
+            this->down_hook->attach(optr, fptr);
+            return this;
+        }
+
+    private:
+        Hook* up_hook;
+        Hook* down_hook;
+        bool value;
+        char counter;
+        Pin* button_pin;
+
+};
+
+
+
+
+
+#endif
diff --git a/src/modules/utils/panel/Panel.cpp b/src/modules/utils/panel/Panel.cpp
new file mode 100644 (file)
index 0000000..2063910
--- /dev/null
@@ -0,0 +1,309 @@
+/*  
+      This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
+      Smoothie 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 3 of the License, or (at your option) any later version.
+      Smoothie 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 Smoothie. If not, see <http://www.gnu.org/licenses/>. 
+*/
+
+#include "libs/Kernel.h"
+#include "Panel.h"
+#include "libs/nuts_bolts.h"
+#include "libs/utils.h"
+#include <string>
+using namespace std;
+#include "Button.h"
+#include "PanelScreen.h"
+#include "screens/MainMenuScreen.h"
+#include "modules/utils/player/PlayerPublicAccess.h"
+
+#include "panels/I2CLCD.h"
+#include "panels/VikiLCD.h"
+
+Panel::Panel(){
+    this->counter_changed = false;
+    this->click_changed = false;
+    this->refresh_flag = false;
+    this->enter_menu_mode();
+       this->menu_offset = 1;
+       this->lcd= NULL;
+       this->do_buttons = false;
+       this->idle_time= 0;
+}
+
+Panel::~Panel() {
+       delete this->lcd;
+}
+
+void Panel::on_module_loaded(){
+    // Exit if this module is not enabled
+       if( !this->kernel->config->value( panel_checksum, enable_checksum )->by_default(false)->as_bool() ){
+               delete this;
+               return;
+       } 
+
+    // Register for events
+    this->register_for_event(ON_IDLE);
+       this->register_for_event(ON_MAIN_LOOP);
+
+       // Initialise the LCD, see which LCD to use
+       if (this->lcd != NULL) delete this->lcd;
+       int lcd_cksm = get_checksum(this->kernel->config->value(panel_checksum, lcd_checksum)->by_default("i2c")->as_string());
+
+       // Note checksums are not const expressions when in debug mode, so don't use switch
+       if(lcd_cksm == i2c_lcd_checksum) {
+               this->lcd = new I2CLCD();
+       }else if(lcd_cksm == viki_lcd_checksum) {
+               this->lcd = new VikiLCD();
+       }else{
+               // no lcd type defined
+               return;
+       }
+
+       // some panels may need access to this global info
+       this->lcd->setPanel(this);
+
+       // load jogging feedrates in mm/min
+       jogging_speed_mm_min[0]= this->kernel->config->value( panel_checksum, jog_x_feedrate_checksum )->by_default(3000.0)->as_number();
+       jogging_speed_mm_min[1]= this->kernel->config->value( panel_checksum, jog_y_feedrate_checksum )->by_default(3000.0)->as_number();
+       jogging_speed_mm_min[2]= this->kernel->config->value( panel_checksum, jog_z_feedrate_checksum )->by_default(300.0)->as_number();
+               
+       this->encoder_click_resolution= this->lcd->getEncoderResolution();
+    this->lcd->init();
+       this->lcd->printf("Starting...");
+       
+       this->up_button.up_attach(      this, &Panel::on_up );
+       this->down_button.up_attach(    this, &Panel::on_down );
+       this->click_button.down_attach( this, &Panel::on_click_release );
+       this->back_button.up_attach(    this, &Panel::on_back );
+
+    this->kernel->slow_ticker->attach( 100,  this, &Panel::button_tick );
+    this->kernel->slow_ticker->attach( 1000, this, &Panel::encoder_check );
+
+    // Default top screen
+       this->top_screen = new MainMenuScreen();
+       this->top_screen->set_panel(this);
+    this->enter_screen(this->top_screen->watch_screen); // default first screen is watch screen even though its parent is Mainmenu
+       
+    // Refresh timer
+    this->kernel->slow_ticker->attach( 20, this, &Panel::refresh_tick );
+
+}
+
+// Enter a screen, we only care about it now
+void Panel::enter_screen(PanelScreen* screen){
+    screen->panel = this;
+    this->current_screen = screen;
+    this->reset_counter();
+    this->current_screen->on_enter();
+}
+
+// Reset the counter
+void Panel::reset_counter(){
+    *this->counter = 0;
+    this->counter_changed = false;
+}
+
+// Indicate the idle loop we want to call the refresh hook in the current screen
+uint32_t Panel::refresh_tick(uint32_t dummy){
+       this->refresh_flag = true;
+       this->idle_time++;
+       return 0;
+}
+
+// Encoder pins changed
+uint32_t Panel::encoder_check(uint32_t dummy){
+       // TODO if encoder reads go through i2c like on smoothie panel this needs to be
+       // optionally done in idle loop, however when reading encoder directly it needs to be done
+       // frequently, smoothie panel will return an actual delta count so won't miss any if polled slowly
+       static int encoder_counter = 0;
+    int change = lcd->readEncoderDelta();
+       encoder_counter += change;
+       // TODO divisor needs to be configurable
+       if( change != 0 /*&& encoder_counter % 2 == 0*/ ){
+               this->counter_changed = true;
+               (*this->counter) += change;
+               this->idle_time= 0;
+    }
+       return 0;
+}
+
+// Read and update each button
+uint32_t Panel::button_tick(uint32_t dummy){
+       this->do_buttons = true;
+       return 0;
+}
+
+// on main loop, we can send gcodes or do anything that waits in this loop
+void Panel::on_main_loop(void* argument){
+       this->current_screen->on_main_loop();
+       this->lcd->on_main_loop();
+}
+
+// On idle things, we don't want to do shit in interrupts
+// don't queue gcodes in this
+void Panel::on_idle(void* argument){
+
+       // after being idle for a while switch to Watch screen
+       if(this->idle_time > 20*5) { // 5 seconds
+               this->idle_time= 0;
+               if(this->top_screen->watch_screen != this->current_screen) {
+                       this->enter_screen(this->top_screen->watch_screen);
+                       // TODO do we need to reset any state?
+               }
+               
+               return;
+       }
+       
+       if(this->do_buttons) {
+               // we don't want to do I2C in interrupt mode
+               this->do_buttons = false;
+
+               // read the actual buttons
+               int but= lcd->readButtons();
+               if(but != 0) this->idle_time= 0;
+               
+               // fire events if the buttons are active and debounce is satisfied
+               this->up_button.check_signal(but&BUTTON_UP);
+               this->down_button.check_signal(but&BUTTON_DOWN);
+               this->back_button.check_signal(but&BUTTON_LEFT);
+               this->click_button.check_signal(but&BUTTON_SELECT);
+
+               // FIXME test
+               //if(but&BUTTON_AUX1) lcd->buzz(10, 500);
+       }
+       
+    // If we are in menu mode and the position has changed
+    if( this->mode == MENU_MODE && this->counter_change() ){
+        this->menu_update();
+    }
+
+    // If we are in control mode
+    if( this->mode == CONTROL_MODE && this->counter_change() ){
+               this->control_value_update();
+    }
+
+    // If we must refresh
+    if( this->refresh_flag ){
+        this->refresh_flag = false;
+        this->current_screen->on_refresh();
+               this->lcd->on_refresh();
+    }
+}
+
+// Hooks for button clicks
+uint32_t Panel::on_up(uint32_t dummy){
+       // this is simulating encoder clicks, but as one press should move menu one
+       // we need to increment twice as two clicks are needed to move the menu once
+       // this needs to be configurable and tied to menu increment
+       *this->counter -= 1;
+       this->counter_changed = true;
+       return 0;
+}
+uint32_t Panel::on_down(uint32_t dummy){
+       *this->counter += 1;
+       this->counter_changed = true;
+       return 0;
+}
+
+// on most menu screens will go back to previous higher menu
+uint32_t Panel::on_back(uint32_t dummy){
+       if(this->mode == MENU_MODE && this->current_screen->parent != NULL) {
+               this->enter_screen(this->current_screen->parent);
+       }
+       return 0;
+}
+
+uint32_t Panel::on_click_release(uint32_t dummy){
+       // TODO make configurable, including turning off
+       // buzz is ignored on panels that do not support buzz
+       lcd->buzz(60,300); // 50ms 300Hz
+       this->click_changed = true;
+       this->idle_time= 0;
+       return 0;
+}
+
+bool Panel::counter_change(){ if( this->counter_changed ){ this->counter_changed = false; return true; }else{ return false; } }
+bool Panel::click(){ if( this->click_changed ){ this->click_changed = false; return true; }else{ return false; } }
+
+
+// Enter menu mode
+void Panel::enter_menu_mode(){
+    this->mode = MENU_MODE;
+    this->counter = &this->menu_selected_line;
+    this->menu_changed = false;
+}
+
+void Panel::setup_menu(uint16_t rows, uint16_t lines){
+    this->menu_selected_line = 0;
+    this->menu_start_line = 0; 
+    this->menu_rows = rows;
+    this->menu_lines = lines;
+}
+
+uint16_t Panel::menu_current_line(){
+    return this->menu_selected_line >> this->menu_offset;
+}
+
+void Panel::menu_update(){
+
+    // Limits, up and down 
+    this->menu_selected_line = this->menu_selected_line % ( this->menu_rows<<this->menu_offset );
+    while( this->menu_selected_line < 0 ){ this->menu_selected_line += this->menu_rows << this->menu_offset; }
+
+    // What to display
+    this->menu_start_line = 0;
+    if( this->menu_rows > this->menu_lines ){
+        if( this->menu_current_line() >= 2 ){
+            this->menu_start_line = this->menu_current_line() - 1;
+        }
+        if( this->menu_current_line() > this->menu_rows - this->menu_lines ){
+            this->menu_start_line = this->menu_rows - this->menu_lines;
+        }
+    }
+
+    this->menu_changed = true;
+}
+
+bool Panel::menu_change(){
+    if( this->menu_changed ){ this->menu_changed = false; return true; }else{ return false; }
+}
+
+bool Panel::control_value_change(){
+       if( this->control_value_changed ){ this->control_value_changed = false; return true; }else{ return false; }
+}
+
+
+bool Panel::enter_control_mode(double passed_normal_increment, double passed_pressed_increment){
+    this->mode = CONTROL_MODE;
+    this->normal_increment  = passed_normal_increment;
+    this->pressed_increment = passed_pressed_increment;
+    this->counter = &this->control_normal_counter;
+    this->control_normal_counter = 0;
+    this->control_pressed_counter = 0;
+       this->control_base_value = 0;
+       return true;
+}
+
+void Panel::control_value_update(){
+       // TODO what do we do here?
+       this->control_value_changed = true;
+}
+
+void Panel::set_control_value(double value){
+       this->control_base_value = value;
+}
+
+double Panel::get_control_value(){
+       return this->control_base_value + (this->control_normal_counter*this->normal_increment/this->encoder_click_resolution);
+}
+
+bool Panel::is_playing() const {
+       void *returned_data;
+
+       bool ok= THEKERNEL->public_data->get_value( player_checksum, is_playing_checksum, &returned_data );
+       if(ok) {
+               bool b= *static_cast<bool*>(returned_data);
+               return b;
+       }
+       return false;
+}
\ No newline at end of file
diff --git a/src/modules/utils/panel/Panel.h b/src/modules/utils/panel/Panel.h
new file mode 100644 (file)
index 0000000..9944c25
--- /dev/null
@@ -0,0 +1,123 @@
+/*  
+      This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
+      Smoothie 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 3 of the License, or (at your option) any later version.
+      Smoothie 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 Smoothie. If not, see <http://www.gnu.org/licenses/>. 
+*/
+
+#ifndef PANEL_H
+#define PANEL_H
+
+#include "libs/Kernel.h"
+#include "libs/nuts_bolts.h"
+#include "libs/utils.h"
+#include "libs/Pin.h"
+#include "panels/LcdBase.h"
+#include "Button.h"
+#include "PanelScreen.h"
+#include "screens/MainMenuScreen.h"
+
+#define panel_checksum             CHECKSUM("panel")
+#define enable_checksum            CHECKSUM("enable")
+#define lcd_checksum               CHECKSUM("lcd")
+#define i2c_lcd_checksum           CHECKSUM("i2c_lcd")
+#define viki_lcd_checksum          CHECKSUM("viki_lcd")
+
+#define jog_x_feedrate_checksum    CHECKSUM("alpha_jog_feedrate")
+#define jog_y_feedrate_checksum    CHECKSUM("beta_jog_feedrate")
+#define jog_z_feedrate_checksum    CHECKSUM("gamma_jog_feedrate")
+
+#define MENU_MODE                  0
+#define CONTROL_MODE               1
+
+
+class Panel : public Module {
+    public:
+        Panel();
+        virtual ~Panel();
+
+        void on_module_loaded();
+        uint32_t button_tick(uint32_t dummy);
+        void on_idle(void* argument);
+        void on_main_loop(void* argument);
+        void enter_screen(PanelScreen* screen);
+        void reset_counter();
+
+        // Encoder and buttons
+        uint32_t on_up(uint32_t dummy);
+        uint32_t on_down(uint32_t dummy);
+        uint32_t on_back(uint32_t dummy);
+        uint32_t on_click_release(uint32_t dummy);
+        uint32_t refresh_tick(uint32_t dummy);
+        uint32_t encoder_check(uint32_t dummy);
+        bool counter_change();
+        bool click();
+        int get_encoder_resolution() const { return encoder_click_resolution; }
+        
+        // Menu
+        void enter_menu_mode();
+        void setup_menu(uint16_t rows, uint16_t lines);
+        void menu_update();
+        bool menu_change();
+        uint16_t menu_current_line();
+
+        // Control
+        bool enter_control_mode(double passed_normal_increment, double passed_pressed_increment);
+        void set_control_value(double value);
+        double get_control_value();
+        bool control_value_change();
+        void control_value_update();
+        double get_jogging_speed(char axis) { return jogging_speed_mm_min[axis-'X']; }
+
+        // file playing from sd
+        bool is_playing() const;
+        void set_playing_file(string f) { playing_file= f; }
+        string get_playing_file() { return playing_file; }
+        
+        // public as it is directly accessed by screens... not good
+        // TODO pass lcd into ctor of each sub screen
+        LcdBase* lcd;
+
+        // as panelscreen accesses private fields in Panel
+        friend class PanelScreen;
+    
+    private:
+        // Menu
+        char menu_offset;
+        int menu_selected_line;
+        int menu_start_line;
+        int menu_rows;
+        int menu_lines;
+        bool menu_changed;
+        bool control_value_changed;
+
+        // Control
+        double normal_increment;
+        double pressed_increment;
+        int control_normal_counter;
+        int control_pressed_counter;
+        double control_base_value;
+        
+        Button up_button;
+        Button down_button;
+        Button back_button;
+        Button click_button;
+
+        int* counter;
+        volatile bool counter_changed;
+        volatile bool click_changed;
+        volatile bool refresh_flag;
+        volatile bool do_buttons;
+        int idle_time;
+        int encoder_click_resolution;
+        char mode;
+
+        MainMenuScreen* top_screen;
+        PanelScreen* current_screen;
+
+        double jogging_speed_mm_min[3];
+
+        string playing_file;
+};
+
+#endif
diff --git a/src/modules/utils/panel/PanelScreen.cpp b/src/modules/utils/panel/PanelScreen.cpp
new file mode 100644 (file)
index 0000000..0f54d19
--- /dev/null
@@ -0,0 +1,57 @@
+/*  
+      This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
+      Smoothie 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 3 of the License, or (at your option) any later version.
+      Smoothie 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 Smoothie. If not, see <http://www.gnu.org/licenses/>. 
+*/
+
+#include "libs/Kernel.h"
+#include "Panel.h"
+#include "PanelScreen.h"
+#include "libs/nuts_bolts.h"
+#include "libs/utils.h"
+#include <string>
+using namespace std;
+
+PanelScreen::PanelScreen(){}
+
+void PanelScreen::on_refresh(){}
+void PanelScreen::on_main_loop(){}
+
+PanelScreen* PanelScreen::set_panel(Panel* parent){
+    this->panel = parent;
+    return this;
+}
+
+void PanelScreen::on_enter(){}
+
+void PanelScreen::refresh_menu(bool clear){
+    if(clear) this->panel->lcd->clear(); 
+    for(uint16_t i = this->panel->menu_start_line; i < this->panel->menu_start_line + min( this->panel->menu_rows, this->panel->menu_lines ); i++ ){
+        this->panel->lcd->setCursor(2, i - this->panel->menu_start_line );
+        this->display_menu_line(i);
+    }
+    this->panel->lcd->setCursor(0, this->panel->menu_current_line() - this->panel->menu_start_line );
+    this->panel->lcd->printf(">");
+}
+
+void PanelScreen::refresh_screen(bool clear){
+       if(clear) this->panel->lcd->clear(); 
+       for(uint16_t i = this->panel->menu_start_line; i < this->panel->menu_start_line + min( this->panel->menu_rows, this->panel->menu_lines ); i++ ){
+               this->panel->lcd->setCursor(0, i - this->panel->menu_start_line );
+               this->display_menu_line(i);
+       }
+}
+
+void PanelScreen::display_menu_line(uint16_t line){};
+
+
+PanelScreen* PanelScreen::set_parent(PanelScreen* passed_parent){
+    this->parent = passed_parent;
+    this->set_panel( passed_parent->panel );
+    return this;
+}
+
+
+
+
diff --git a/src/modules/utils/panel/PanelScreen.h b/src/modules/utils/panel/PanelScreen.h
new file mode 100644 (file)
index 0000000..be2a0d1
--- /dev/null
@@ -0,0 +1,42 @@
+/*  
+      This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
+      Smoothie 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 3 of the License, or (at your option) any later version.
+      Smoothie 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 Smoothie. If not, see <http://www.gnu.org/licenses/>. 
+*/
+
+#ifndef PANELSCREEN_H
+#define PANELSCREEN_H
+
+#include "libs/Kernel.h"
+#include "libs/nuts_bolts.h"
+#include "libs/utils.h"
+#include "libs/Pin.h"
+#include "LcdBase.h"
+#include "Panel.h"
+
+class Panel;
+class PanelScreen {
+    public:
+        PanelScreen();
+        virtual void on_refresh();       
+        virtual void on_main_loop();       
+        PanelScreen* set_panel(Panel* parent);
+        PanelScreen* set_parent(PanelScreen* passed_parent);
+        virtual void on_enter();
+        // if you completely rewrite the screen do not clear it, this avoids flicker
+        void refresh_screen(bool clear);
+        void refresh_menu(bool clear);
+        void refresh_menu(void){ refresh_menu(true); };
+        virtual void display_menu_line(uint16_t line);
+
+        Panel* panel;
+        PanelScreen* parent;
+};
+
+
+
+
+
+
+#endif
diff --git a/src/modules/utils/panel/panels/I2CLCD.h b/src/modules/utils/panel/panels/I2CLCD.h
new file mode 100644 (file)
index 0000000..5c9435e
--- /dev/null
@@ -0,0 +1,239 @@
+/*  
+      This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
+      Smoothie 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 3 of the License, or (at your option) any later version.
+      Smoothie 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 Smoothie. If not, see <http://www.gnu.org/licenses/>. 
+*/
+#ifndef I2CLCD_H
+#define I2CLCD_H
+
+#include "LcdBase.h"
+
+#include "I2C.h" // mbed.h lib
+#include "wait_api.h" // mbed.h lib
+#include "libs/Config.h"
+
+using namespace std;
+#include <vector>
+#include <string>
+#include <cstdio>
+#include <cstdarg>
+
+// commands
+#define LCD_CLEARDISPLAY 0x01
+#define LCD_RETURNHOME 0x02
+#define LCD_ENTRYMODESET 0x04
+#define LCD_DISPLAYCONTROL 0x08
+#define LCD_CURSORSHIFT 0x10
+#define LCD_FUNCTIONSET 0x20
+#define LCD_SETCGRAMADDR 0x40
+#define LCD_SETDDRAMADDR 0x80
+
+// flags for display entry mode
+#define LCD_ENTRYRIGHT 0x00
+#define LCD_ENTRYLEFT 0x02
+#define LCD_ENTRYSHIFTINCREMENT 0x01
+#define LCD_ENTRYSHIFTDECREMENT 0x00
+
+// flags for display on/off control
+#define LCD_DISPLAYON 0x04
+#define LCD_DISPLAYOFF 0x00
+#define LCD_CURSORON 0x02
+#define LCD_CURSOROFF 0x00
+#define LCD_BLINKON 0x01
+#define LCD_BLINKOFF 0x00
+
+// flags for display/cursor shift
+#define LCD_DISPLAYMOVE 0x08
+#define LCD_CURSORMOVE 0x00
+#define LCD_MOVERIGHT 0x04
+#define LCD_MOVELEFT 0x00
+
+// flags for function set
+#define LCD_8BITMODE 0x10
+#define LCD_4BITMODE 0x00
+#define LCD_2LINE 0x08
+#define LCD_1LINE 0x00
+#define LCD_5x10DOTS 0x04
+#define LCD_5x8DOTS 0x00
+
+// flags for backlight control
+#define LCD_BACKLIGHT 0x08
+#define LCD_NOBACKLIGHT 0x00
+
+#define En 1<<2 // Enable bit
+#define Rw 1<<1 // Read/Write bit
+#define Rs 1<<0 // Register select bit
+
+// config settings
+#define panel_checksum             CHECKSUM("panel")
+#define encoder_a_pin_checksum     CHECKSUM("encoder_a_pin")
+#define encoder_b_pin_checksum     CHECKSUM("encoder_b_pin")
+#define up_button_pin_checksum     CHECKSUM("up_button_pin")
+#define down_button_pin_checksum   CHECKSUM("down_button_pin")
+#define click_button_pin_checksum  CHECKSUM("click_button_pin")
+
+class I2CLCD : public LcdBase {
+    public:
+        I2CLCD() {
+            Kernel* kernel= THEKERNEL;
+            // Default values
+            this->i2c_address      = 0x27;
+            this->backlightval     = 0x00;
+            this->displaycontrol   = 0x00;
+            this->displayfunction  = 0x00;
+            this->displaymode      = 0x00;
+
+            // I2C com
+            this->i2c = new mbed::I2C(P0_27, P0_28);   
+        
+            // configure the pins to use
+            this->encoder_a_pin.from_string(kernel->config->value( panel_checksum, encoder_a_pin_checksum)->by_default("nc")->as_string())->as_input()->pull_up();
+            this->encoder_b_pin.from_string(kernel->config->value( panel_checksum, encoder_b_pin_checksum)->by_default("nc")->as_string())->as_input()->pull_up();
+            this->click_pin.from_string(kernel->config->value( panel_checksum, click_button_pin_checksum )->by_default("nc")->as_string())->as_input()->pull_up();
+            this->up_pin.from_string(kernel->config->value( panel_checksum, up_button_pin_checksum)->by_default("nc")->as_string())->as_input()->pull_up();
+            this->down_pin.from_string(kernel->config->value( panel_checksum, down_button_pin_checksum)->by_default("nc")->as_string())->as_input()->pull_up();
+
+        }
+        virtual ~I2CLCD() {
+            delete this->i2c;
+        }
+
+        int getEncoderResolution() {
+            return 1;
+        }
+        
+        uint8_t readButtons() {
+            uint8_t state= 0;
+            state |= (this->click_pin.get() ? BUTTON_SELECT : 0);
+            state |= (this->up_pin.get() ? BUTTON_UP : 0);
+            state |= (this->down_pin.get() ? BUTTON_DOWN : 0);
+            return state;
+        }
+
+        int readEncoderDelta() { 
+            static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
+            static uint8_t old_AB = 0;
+            old_AB <<= 2;                   //remember previous state
+            old_AB |= ( this->encoder_a_pin.get() + ( this->encoder_b_pin.get() * 2 ) );  //add current state 
+            return  enc_states[(old_AB&0x0f)];
+        }
+
+        void expanderWrite(char data){
+            this->i2c->start();
+            this->i2c->write(this->i2c_address<<1); 
+            this->i2c->write((char)((char)data | (char)backlightval));
+            this->i2c->stop();
+        }
+
+        void pulseEnable(char data){
+            this->expanderWrite(data | En);      // En high
+            wait_us(1);                          // enable pulse must be >450ns
+            this->expanderWrite(data & ~En);     // En low
+            wait_us(50);                         // commands need > 37us to settle
+        } 
+
+        void write4bits(char value) {
+            this->expanderWrite(value);
+            this->pulseEnable(value);
+        }
+
+        void send(char value, char mode) {
+            uint8_t highnib=value&0xf0;
+            uint8_t lownib=(value<<4)&0xf0;
+            this->write4bits((highnib)|mode);
+            this->write4bits((lownib)|mode); 
+        }
+
+        void command(char value) {
+            this->send(value, 0);
+        }
+
+        void write(char value){
+            this->send(value, Rs);
+        }
+
+        void home(){
+            this->command(LCD_RETURNHOME);  // set cursor position to zero
+            wait_us(2000);            // this command takes a long time!
+        }
+
+        void clear(){
+            this->command(LCD_CLEARDISPLAY);  // clear display, set cursor position to zero
+            wait_us(2000);              // this command takes a long time!
+        }
+
+        void display() {
+            this->displaycontrol |= LCD_DISPLAYON;
+            this->command(LCD_DISPLAYCONTROL | this->displaycontrol);
+        }
+
+        void setCursor(uint8_t col, uint8_t row){
+            int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
+            if ( row > 4 ) {
+                row = 4-1;    // we count rows starting w/0
+            }
+            this->command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
+        }
+
+        void init(){
+            // Setup
+            this->displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS;
+            this->backlightval = LCD_NOBACKLIGHT;
+            
+            // Now we pull both RS and R/W low to begin commands
+            wait_ms(50);
+            this->expanderWrite(this->backlightval);
+            wait_ms(1000);
+            
+            // we start in 8bit mode, try to set 4 bit mode
+            for( char i=0;i<3;i++){ 
+                this->write4bits(0x03 << 4);
+                wait_us(4500);
+            }  
+            
+            // finally, set to 4-bit interface
+            this->write4bits(0x02 << 4); 
+            
+            // set # lines, font size, etc.
+            this->command(LCD_FUNCTIONSET | this->displayfunction);  
+            
+            // turn the display on with no cursor or blinking default
+            this->displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
+            this->display();
+            
+            // clear it off
+            this->clear();
+            
+            // Initialize to default text direction (for roman languages)
+            this->displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
+            
+            // set the entry mode
+            this->command(LCD_ENTRYMODESET | displaymode);
+            
+            this->home();
+            wait(0.1);
+
+            this->backlightval=LCD_BACKLIGHT;
+            expanderWrite(0);
+
+        }
+
+    private:
+        char displaymode;
+        char displayfunction;
+        char displaycontrol;
+        char i2c_address;
+        char backlightval;
+
+        mbed::I2C* i2c;
+
+        Pin encoder_a_pin;
+        Pin encoder_b_pin;    
+        Pin click_pin;
+        Pin up_pin;
+        Pin down_pin;
+};
+
+
+#endif
diff --git a/src/modules/utils/panel/panels/LcdBase.cpp b/src/modules/utils/panel/panels/LcdBase.cpp
new file mode 100644 (file)
index 0000000..2727187
--- /dev/null
@@ -0,0 +1,25 @@
+#include "LcdBase.h"
+
+LcdBase::LcdBase() {}
+LcdBase::~LcdBase() {}
+
+
+int LcdBase::printf(const std::string format, ...){
+       wait_us(10); 
+       va_list args;
+       va_start(args, format);
+       int size = format.size() * 2;
+       char* buffer = new char[size];
+       while (vsprintf(buffer, format.c_str(), args) < 0){
+               delete[] buffer;
+               size *= 2;
+               buffer = new char[size];
+       }
+       string message = std::string(buffer);
+       va_end(args);
+       for(unsigned int i=0; i < message.size(); i++){
+               this->write(message.at(i)); 
+       }
+       delete[] buffer;
+       return 0;
+}
diff --git a/src/modules/utils/panel/panels/LcdBase.h b/src/modules/utils/panel/panels/LcdBase.h
new file mode 100644 (file)
index 0000000..8aa4025
--- /dev/null
@@ -0,0 +1,122 @@
+#ifndef LCDBASE_H
+#define LCDBASE_H
+
+#include "I2C.h" // mbed.h lib
+#include "wait_api.h" // mbed.h lib
+
+#include "libs/Module.h"
+#include "libs/Kernel.h"
+#include "libs/nuts_bolts.h"
+#include "libs/Config.h"
+
+using namespace std;
+#include <vector>
+#include <string>
+#include <cstdio>
+#include <cstdarg>
+
+// commands
+#define LCD_CLEARDISPLAY 0x01
+#define LCD_RETURNHOME 0x02
+#define LCD_ENTRYMODESET 0x04
+#define LCD_DISPLAYCONTROL 0x08
+#define LCD_CURSORSHIFT 0x10
+#define LCD_FUNCTIONSET 0x20
+#define LCD_SETCGRAMADDR 0x40
+#define LCD_SETDDRAMADDR 0x80
+
+// flags for display entry mode
+#define LCD_ENTRYRIGHT 0x00
+#define LCD_ENTRYLEFT 0x02
+#define LCD_ENTRYSHIFTINCREMENT 0x01
+#define LCD_ENTRYSHIFTDECREMENT 0x00
+
+// flags for display on/off control
+#define LCD_DISPLAYON 0x04
+#define LCD_DISPLAYOFF 0x00
+#define LCD_CURSORON 0x02
+#define LCD_CURSOROFF 0x00
+#define LCD_BLINKON 0x01
+#define LCD_BLINKOFF 0x00
+
+// flags for display/cursor shift
+#define LCD_DISPLAYMOVE 0x08
+#define LCD_CURSORMOVE 0x00
+#define LCD_MOVERIGHT 0x04
+#define LCD_MOVELEFT 0x00
+
+// flags for function set
+#define LCD_8BITMODE 0x10
+#define LCD_4BITMODE 0x00
+#define LCD_2LINE 0x08
+#define LCD_1LINE 0x00
+#define LCD_5x10DOTS 0x04
+#define LCD_5x8DOTS 0x00
+
+// flags for backlight control
+#define LCD_BACKLIGHT 0x08
+#define LCD_NOBACKLIGHT 0x00
+
+// for setBacklight(), sets specific leds on some panels
+#define LED_OFF 0x0
+#define LED_RED 0x1
+#define LED_YELLOW 0x3
+#define LED_GREEN 0x2
+#define LED_TEAL 0x6
+#define LED_BLUE 0x4
+#define LED_VIOLET 0x5
+#define LED_WHITE 0x7 
+
+// Standard directional button bits
+#define BUTTON_SELECT 0x01
+#define BUTTON_RIGHT  0x02
+#define BUTTON_DOWN   0x04
+#define BUTTON_UP     0x08
+#define BUTTON_LEFT   0x10
+#define BUTTON_AUX1   0x20
+#define BUTTON_AUX2   0x40
+#define BUTTON_AUX3   0x80
+
+class Panel;
+
+class LcdBase {
+    public:
+        LcdBase();
+        virtual ~LcdBase();
+        virtual void init()= 0;
+        int printf(const std::string format, ...);
+
+        void setPanel(Panel* p) { panel= p; }
+        
+        // Required LCD functions
+        virtual void write(char value)= 0;
+        virtual void home()= 0;
+        virtual void clear()= 0;
+        virtual void display()= 0;
+        virtual void setCursor(uint8_t col, uint8_t row)= 0;
+
+        // Returns button states including the encoder select button
+        virtual uint8_t readButtons()= 0;
+
+        // returns the current encoder position
+        virtual int readEncoderDelta()= 0;
+        
+        // the number of encoder clicks per detent. this is divided into
+        // accumulated clicks for control values so one detent is one
+        // increment, this varies depending on encoder type usually 1,2 or 4
+        virtual int getEncoderResolution()= 0;
+                                            
+        // optional
+        virtual void setBacklight(uint8_t status){};
+        virtual void buzz(long,uint16_t){};
+
+        // only used on certain panels
+        virtual void on_refresh(){};
+        virtual void on_main_loop(){};
+
+    protected:
+        Panel* panel;
+
+};
+
+#endif
\ No newline at end of file
diff --git a/src/modules/utils/panel/panels/VikiLCD.cpp b/src/modules/utils/panel/panels/VikiLCD.cpp
new file mode 100644 (file)
index 0000000..3de0399
--- /dev/null
@@ -0,0 +1,393 @@
+/*  
+This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
+Smoothie 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 3 of the License, or (at your option) any later version.
+Smoothie 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 Smoothie. If not, see <http://www.gnu.org/licenses/>. 
+*/
+#include "VikiLCD.h"
+
+// if this is defined we use the R/W poll mode instead of fixed delays
+// However at the slower I2C frequency required for Viki long cables it is slower than fixed delay
+// taken from LiquidCrystalFast.cpp and implemented for Viki LCD here by Jim Morris
+//#define USE_FASTMODE
+
+//MCP23017 - Adafruit RGB LCD Shield and VikiLCD
+// bit pattern for the burstBits function is
+//
+//  B7 B6 B5 B4 B3 B2 B1 B0 A7 A6 A5 A4 A3 A2 A1 A0 - MCP23017 
+//  RS RW EN D4 D5 D6 D7 LB LG LR BZ B4 B3 B2 B1 B0 
+//  15 14 13 12 11 10 9  8  7  6  5  4  3  2  1  0  
+#define M17_BIT_RS 0x8000
+#define M17_BIT_RW 0x4000
+#define M17_BIT_EN 0x2000
+#define M17_BIT_D4 0x1000
+#define M17_BIT_D5 0x0800
+#define M17_BIT_D6 0x0400
+#define M17_BIT_D7 0x0200
+#define M17_BIT_LB 0x0100
+#define M17_BIT_LG 0x0080
+#define M17_BIT_LR 0x0040
+#define M17_BIT_BZ 0x0020 //Added a buzzer on this pin
+#define M17_BIT_B4 0x0010
+#define M17_BIT_B3 0x0008
+#define M17_BIT_B2 0x0004
+#define M17_BIT_B1 0x0002
+#define M17_BIT_B0 0x0001
+
+VikiLCD::VikiLCD() {
+       // Default values
+       this->i2c_address      = MCP23017_ADDRESS;
+       this->backlightval     = 0x00;
+       this->displaycontrol   = 0x00;
+       this->displayfunction  = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS; // in case they forget to call begin() at least we have somethin
+       this->displaymode      = 0x00;
+       this->_numlines        = 4;
+       
+       // I2C com
+//     this->i2c = new mbed::I2C(P0_27, P0_28);
+       this->i2c = new mbed::I2C(p9, p10); // P0_0, P0_1
+
+       i2c->frequency(60000);
+       
+       // configure the pins to use
+       this->encoder_a_pin.from_string(THEKERNEL->config->value( panel_checksum, encoder_a_pin_checksum)->by_default("nc")->as_string())->as_input();
+
+       this->encoder_b_pin.from_string(THEKERNEL->config->value( panel_checksum, encoder_b_pin_checksum)->by_default("nc")->as_string())->as_input();
+
+       this->button_pause_pin.from_string(THEKERNEL->config->value( panel_checksum, button_pause_pin_checksum)->by_default("nc")->as_string())->as_input();
+
+       paused= false;
+       button_pause.pin(&this->button_pause_pin)->up_attach( this, &VikiLCD::on_pause_release);
+}
+
+VikiLCD::~VikiLCD() {
+       delete this->i2c;
+}
+       
+
+void VikiLCD::init(){
+       // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
+       // according to datasheet, we need at least 40ms after power rises above 2.7V
+       // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
+
+       char data[2];
+       
+       // Setup
+       this->displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS;
+       this->backlightval = LCD_NOBACKLIGHT;
+
+       wait_ms(50);
+
+       // now set up input/output pins in MCP23017
+       data[0]= MCP23017_IODIRA;
+       data[1]= 0x1F; // buttons input, all others output
+       i2c->write(this->i2c_address, data, 2);
+
+
+       // set the button pullups
+       data[0]= MCP23017_GPPUA;
+       data[1]= 0x1F;
+       i2c->write(this->i2c_address, data, 2);
+
+       data[0]= MCP23017_IODIRB;
+       data[1]= 0x00; // all pins output
+       i2c->write(this->i2c_address, data, 2);
+
+       // turn leds off
+       setBacklight(0);
+       
+       //put the LCD into 4 bit mode
+       // start with a non-standard command to make it realize we're speaking 4-bit here
+       // per LCD datasheet, first command is a single 4-bit burst, 0011.
+       //-----
+       //  we cannot assume that the LCD panel is powered at the same time as
+       //  the arduino, so we have to perform a software reset as per page 45
+       //  of the HD44780 datasheet - (kch)
+       //-----
+
+       // bit pattern for the burstBits function is
+       //
+       //  B7 B6 B5 B4 B3 B2 B1 B0 A7 A6 A5 A4 A3 A2 A1 A0 - MCP23017 
+       //  15 14 13 12 11 10 9  8  7  6  5  4  3  2  1  0  
+       //  RS RW EN D4 D5 D6 D7 B  G  R     B4 B3 B2 B1 B0 
+       for (uint8_t i=0;i < 3;i++) {
+               burstBits8b((M17_BIT_EN|M17_BIT_D5|M17_BIT_D4) >> 8);
+               burstBits8b((M17_BIT_D5|M17_BIT_D4) >> 8);
+       }
+       burstBits8b((M17_BIT_EN|M17_BIT_D5) >> 8);
+       burstBits8b(M17_BIT_D5 >> 8);
+
+
+       wait_ms(5); // this shouldn't be necessary, but sometimes 16MHz is stupid-fast.
+
+       command(LCD_FUNCTIONSET | displayfunction); // then send 0010NF00 (N=lines, F=font)
+       wait_ms(5); // for safe keeping...
+       command(LCD_FUNCTIONSET | displayfunction); // ... twice.
+       wait_ms(5); // done!
+
+       // turn on the LCD with our defaults. since these libs seem to use personal preference, I like a cursor.
+       displaycontrol = (LCD_DISPLAYON|LCD_BACKLIGHT);
+       display();
+       // clear it off
+       clear();
+
+       displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
+       // set the entry mode
+       command(LCD_ENTRYMODESET | displaymode);
+}
+
+// we use this to burst bits to the GPIO chip whenever we need to. avoids repetitive code.
+void VikiLCD::burstBits8b(uint8_t value) {
+       char data[2];
+       data[0] = MCP23017_GPIOB;
+       data[1]= value;
+       i2c->write(this->i2c_address, data, 2);
+}
+
+// value byte order is BA
+void VikiLCD::burstBits16(uint16_t value) {
+       char data[3];
+       data[0] = MCP23017_GPIOA;
+       data[1]= value&0xFF;
+       data[2]= value>>8;
+       i2c->write(this->i2c_address, data, 3);
+}
+
+// cycle the buzzer pin at a certain frequency (hz) for a certain duration (ms) 
+void VikiLCD::buzz(long duration, uint16_t freq) {
+       char data[2];
+       int currentRegister = 0;
+       // read gpio register
+       data[0] = MCP23017_GPIOA;
+       i2c->write(this->i2c_address, data, 1);
+       i2c->read(this->i2c_address, data, 1);       // Read from selected Register
+       currentRegister= data[0];
+       
+       duration *=1000; //convert from ms to us
+       long period = 1000000 / freq; // period in us
+       long elapsed_time = 0;
+       while (elapsed_time < duration) {
+               data[0]= MCP23017_GPIOA;
+               data[1]= currentRegister |= M17_BIT_BZ;
+               i2c->write(this->i2c_address, data, 2);
+
+               wait_us(period / 2);
+
+               data[0]= MCP23017_GPIOA;
+               data[1]= currentRegister &= ~M17_BIT_BZ;
+               i2c->write(this->i2c_address, data, 2);
+
+               wait_us(period / 2);
+               elapsed_time += (period);
+       }
+}
+
+uint8_t VikiLCD::readButtons(void) {
+       char data[2];
+       data[0] = MCP23017_GPIOA;
+       i2c->write(this->i2c_address, data, 1);
+       i2c->read(this->i2c_address, data, 1);       // Read from selected Register
+
+       // check the button pause
+       button_pause.check_signal();
+       
+       return (~data[0]) & ALL_BUTTON_BITS;
+}
+
+int VikiLCD::readEncoderDelta() {
+       static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
+       static uint8_t old_AB = 0;
+       old_AB <<= 2;                   //remember previous state
+       old_AB |= ( this->encoder_a_pin.get() + ( this->encoder_b_pin.get() * 2 ) );  //add current state 
+       return  enc_states[(old_AB&0x0f)];
+}
+
+void VikiLCD::clear()
+{
+       command(LCD_CLEARDISPLAY);  // clear display, set cursor position to zero
+#ifndef USE_FASTMODE
+       wait_us(2000);  // this command takes a long time!
+#endif
+}
+
+void VikiLCD::home()
+{
+       command(LCD_RETURNHOME);  // set cursor position to zero
+#ifndef USE_FASTMODE
+       wait_us(2000);  // this command takes a long time!
+#endif
+}
+
+void VikiLCD::setCursor(uint8_t col, uint8_t row)
+{
+       int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
+       if ( row > _numlines ) row = _numlines - 1;    // we count rows starting w/0
+       command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
+}
+
+// Turn the display on/off (quickly)
+void VikiLCD::noDisplay() {
+       displaycontrol &= ~LCD_DISPLAYON;
+       command(LCD_DISPLAYCONTROL | displaycontrol);
+}
+void VikiLCD::display() {
+       displaycontrol |= LCD_DISPLAYON;
+       command(LCD_DISPLAYCONTROL | displaycontrol);
+}
+
+// Turns the underline cursor on/off
+void VikiLCD::noCursor() {
+       displaycontrol &= ~LCD_CURSORON;
+       command(LCD_DISPLAYCONTROL | displaycontrol);
+}
+void VikiLCD::cursor() {
+       displaycontrol |= LCD_CURSORON;
+       command(LCD_DISPLAYCONTROL | displaycontrol);
+}
+
+// Turn on and off the blinking cursor
+void VikiLCD::noBlink() {
+       displaycontrol &= ~LCD_BLINKON;
+       command(LCD_DISPLAYCONTROL | displaycontrol);
+}
+void VikiLCD::blink() {
+       displaycontrol |= LCD_BLINKON;
+       command(LCD_DISPLAYCONTROL | displaycontrol);
+}
+
+// These commands scroll the display without changing the RAM
+void VikiLCD::scrollDisplayLeft(void) {
+       command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
+}
+void VikiLCD::scrollDisplayRight(void) {
+       command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
+}
+
+// This is for text that flows Left to Right
+void VikiLCD::leftToRight(void) {
+       displaymode |= LCD_ENTRYLEFT;
+       command(LCD_ENTRYMODESET | displaymode);
+}
+
+// This is for text that flows Right to Left
+void VikiLCD::rightToLeft(void) {
+       displaymode &= ~LCD_ENTRYLEFT;
+       command(LCD_ENTRYMODESET | displaymode);
+}
+
+// This will 'right justify' text from the cursor
+void VikiLCD::autoscroll(void) {
+       displaymode |= LCD_ENTRYSHIFTINCREMENT;
+       command(LCD_ENTRYMODESET | displaymode);
+}
+
+// This will 'left justify' text from the cursor
+void VikiLCD::noAutoscroll(void) {
+       displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
+       command(LCD_ENTRYMODESET | displaymode);
+}
+
+void VikiLCD::command(uint8_t value) {
+       send(value, 0);
+}
+
+void VikiLCD::write(char value) {
+       send(value, 1);
+}
+
+// Allows to set the backlight, if the LCD backpack is used
+void VikiLCD::setBacklight(uint8_t status) {
+       // LED turns on when bit is cleared
+       _backlightBits = M17_BIT_LB|M17_BIT_LG|M17_BIT_LR; // all off
+       if (status & LED_RED) _backlightBits &= ~M17_BIT_LR; // red on
+       if (status & LED_GREEN) _backlightBits &= ~M17_BIT_LG; // green on
+       if (status & LED_BLUE) _backlightBits &= ~M17_BIT_LB; // blue on
+
+       burstBits16(_backlightBits);
+}
+
+// write either command or data, burst it to the expander over I2C.
+void VikiLCD::send(uint8_t value, uint8_t mode) {
+#ifdef USE_FASTMODE
+       // polls for ready. not sure on I2C this is any faster
+       
+       // set Data pins as input
+       char data[2];
+       data[0]= MCP23017_IODIRB;
+       data[1]= 0x1E;
+       i2c->write(this->i2c_address, data, 2);
+       uint8_t b= _backlightBits >> 8;
+       burstBits8b((M17_BIT_RW>>8)|b); // RW hi,RS lo 
+       char busy;
+       data[0] = MCP23017_GPIOB;
+       do {
+               burstBits8b(((M17_BIT_RW|M17_BIT_EN)>>8)|b); // EN hi
+               i2c->write(this->i2c_address, data, 1);
+               i2c->read(this->i2c_address, &busy, 1); // Read D7
+               burstBits8b((M17_BIT_RW>>8)|b); // EN lo
+               burstBits8b(((M17_BIT_RW|M17_BIT_EN)>>8)|b); // EN hi
+               burstBits8b((M17_BIT_RW>>8)|b); // EN lo
+       } while ((busy&(M17_BIT_D7>>8)) != 0);
+
+       // reset data bits as output
+       data[0]= MCP23017_IODIRB;
+       data[1]= 0x00;
+       i2c->write(this->i2c_address, data, 2);
+       burstBits8b(b); // RW lo 
+
+#else
+//     wait_us(320);
+#endif
+       
+       // BURST SPEED, OH MY GOD
+       // the (now High Speed!) I/O expander pinout
+       //  B7 B6 B5 B4 B3 B2 B1 B0 A7 A6 A5 A4 A3 A2 A1 A0 - MCP23017 
+       //  15 14 13 12 11 10 9  8  7  6  5  4  3  2  1  0  
+       //  RS RW EN D4 D5 D6 D7 B  G  R     B4 B3 B2 B1 B0 
+
+       // n.b. RW bit stays LOW to write
+       uint8_t buf = _backlightBits >> 8;
+       // send high 4 bits
+       if (value & 0x10) buf |= M17_BIT_D4 >> 8;
+       if (value & 0x20) buf |= M17_BIT_D5 >> 8;
+       if (value & 0x40) buf |= M17_BIT_D6 >> 8;
+       if (value & 0x80) buf |= M17_BIT_D7 >> 8;
+       
+       if (mode) buf |= (M17_BIT_RS|M17_BIT_EN) >> 8; // RS+EN
+       else buf |= M17_BIT_EN >> 8; // EN
+
+       burstBits8b(buf);
+
+       // resend w/ EN turned off
+       buf &= ~(M17_BIT_EN >> 8);
+       burstBits8b(buf);
+
+       // send low 4 bits
+       buf = _backlightBits >> 8;
+       // send high 4 bits
+       if (value & 0x01) buf |= M17_BIT_D4 >> 8;
+       if (value & 0x02) buf |= M17_BIT_D5 >> 8;
+       if (value & 0x04) buf |= M17_BIT_D6 >> 8;
+       if (value & 0x08) buf |= M17_BIT_D7 >> 8;
+       
+       if (mode) buf |= (M17_BIT_RS|M17_BIT_EN) >> 8; // RS+EN
+       else buf |= M17_BIT_EN >> 8; // EN
+
+       burstBits8b(buf);
+
+       // resend w/ EN turned off
+       buf &= ~(M17_BIT_EN >> 8);
+       burstBits8b(buf);
+}
+
+// We pause the system
+uint32_t VikiLCD::on_pause_release(uint32_t dummy){
+       if(!paused) {
+               THEKERNEL->pauser->take();
+               paused= true;
+       }else{
+               THEKERNEL->pauser->release();
+               paused= false;
+       }
+       return 0;
+}
diff --git a/src/modules/utils/panel/panels/VikiLCD.h b/src/modules/utils/panel/panels/VikiLCD.h
new file mode 100644 (file)
index 0000000..bbfb918
--- /dev/null
@@ -0,0 +1,122 @@
+/*  
+      This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
+      Smoothie 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 3 of the License, or (at your option) any later version.
+      Smoothie 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 Smoothie. If not, see <http://www.gnu.org/licenses/>.
+
+Much of this was copied from LiquidTWI2
+  LiquidTWI2 High Performance i2c LCD driver for MCP23008 & MCP23017
+  hacked by Sam C. Lin / http://www.lincomatic.com
+  from 
+   LiquidTWI by Matt Falcon (FalconFour) / http://falconfour.com
+   logic gleaned from Adafruit RGB LCD Shield library
+*/
+
+#ifndef VIKILCD_H
+#define VIKILCD_H
+#include "LcdBase.h"
+#include "libs/Pin.h"
+#include "Button.h"
+   
+using namespace std;
+#include <vector>
+#include <string>
+#include <cstdio>
+#include <cstdarg>
+
+// VikiLcd specific settings
+
+// readButtons() will only return these bit values 
+#define ALL_BUTTON_BITS (BUTTON_UP|BUTTON_DOWN|BUTTON_LEFT|BUTTON_RIGHT|BUTTON_SELECT)
+
+
+#define MCP23017_ADDRESS 0x20<<1
+
+// registers
+#define MCP23017_IODIRA 0x00
+#define MCP23017_IPOLA 0x02
+#define MCP23017_GPINTENA 0x04
+#define MCP23017_DEFVALA 0x06
+#define MCP23017_INTCONA 0x08
+#define MCP23017_IOCONA 0x0A
+#define MCP23017_GPPUA 0x0C
+#define MCP23017_INTFA 0x0E
+#define MCP23017_INTCAPA 0x10
+#define MCP23017_GPIOA 0x12
+#define MCP23017_OLATA 0x14
+
+
+#define MCP23017_IODIRB 0x01
+#define MCP23017_IPOLB 0x03
+#define MCP23017_GPINTENB 0x05
+#define MCP23017_DEFVALB 0x07
+#define MCP23017_INTCONB 0x09
+#define MCP23017_IOCONB 0x0B
+#define MCP23017_GPPUB 0x0D
+#define MCP23017_INTFB 0x0F
+#define MCP23017_INTCAPB 0x11
+#define MCP23017_GPIOB 0x13
+#define MCP23017_OLATB 0x15
+
+// config settings for Viki LCD
+#define panel_checksum             CHECKSUM("panel")
+#define encoder_a_pin_checksum     CHECKSUM("encoder_a_pin")
+#define encoder_b_pin_checksum     CHECKSUM("encoder_b_pin")
+#define button_pause_pin_checksum  CHECKSUM("button_pause_pin")
+
+class VikiLCD : public LcdBase {
+    public:
+        VikiLCD();
+        virtual ~VikiLCD();
+        void home();
+        void clear();
+        void display();
+        void setCursor(uint8_t col, uint8_t row);
+        void init();
+        void write(char value);
+
+        // added viki commands
+        void setBacklight(uint8_t status); 
+
+        uint8_t readButtons();
+        int readEncoderDelta();
+        int getEncoderResolution() { return 2; }
+
+        void buzz(long,uint16_t);
+        void noCursor();
+        void cursor();
+        void noBlink();
+        void blink();
+        void scrollDisplayLeft();
+        void scrollDisplayRight();
+        void leftToRight();
+        void rightToLeft();
+        void autoscroll();
+        void noAutoscroll();
+        void noDisplay();
+        
+    private:
+        void send(uint8_t, uint8_t);
+        void command(uint8_t value);
+    
+        void burstBits16(uint16_t);
+        void burstBits8b(uint8_t);
+        char displaymode;
+        char displayfunction;
+        char displaycontrol;
+        char i2c_address;
+        char backlightval;
+        uint8_t _numlines,_currline;
+        uint16_t _backlightBits; // only for MCP23017
+        mbed::I2C* i2c;
+
+        Pin encoder_a_pin;
+        Pin encoder_b_pin;    
+        Pin button_pause_pin;
+        Button button_pause;
+        uint32_t on_pause_release(uint32_t dummy);
+        bool paused;
+};
+
+
+#endif
diff --git a/src/modules/utils/panel/screens/ControlScreen.cpp b/src/modules/utils/panel/screens/ControlScreen.cpp
new file mode 100644 (file)
index 0000000..f73d6c1
--- /dev/null
@@ -0,0 +1,132 @@
+/*  
+      This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
+      Smoothie 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 3 of the License, or (at your option) any later version.
+      Smoothie 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 Smoothie. If not, see <http://www.gnu.org/licenses/>. 
+*/
+
+#include "libs/Kernel.h"
+#include "libs/SerialMessage.h"
+#include "Panel.h"
+#include "PanelScreen.h"
+#include "MainMenuScreen.h"
+#include "ControlScreen.h"
+#include "libs/nuts_bolts.h"
+#include "libs/utils.h"
+#include <string>
+#include "modules/robot/RobotPublicAccess.h"
+using namespace std;
+
+#define JOGGING_SPEED_MM_MIN 1200
+
+ControlScreen::ControlScreen(){
+    this->control_mode = NULL_CONTROL_MODE;
+}
+
+void ControlScreen::on_enter(){
+    this->panel->enter_menu_mode();
+    this->panel->setup_menu(4, 4);
+       get_current_pos(this->pos);
+       this->refresh_menu();
+       this->pos_changed= false;
+}
+
+// called in on_idle()
+void ControlScreen::on_refresh(){
+    if( this->panel->menu_change() ){
+        this->refresh_menu();
+       }
+
+       if(this->control_mode == AXIS_CONTROL_MODE) {
+               
+               if( this->panel->click() ){
+                       this->enter_menu_control();
+                       this->refresh_menu();
+                       
+               }else if(this->panel->control_value_change()) {
+                       this->pos[this->controlled_axis-'X'] = this->panel->get_control_value();
+                       this->panel->lcd->setCursor(0,2);
+                       this->display_axis_line(this->controlled_axis);
+                       this->pos_changed= true; // make the gcode in main_loop
+               }
+               
+       }else{
+               if( this->panel->click() ){
+                       this->clicked_menu_entry(this->panel->menu_current_line());
+               }
+       }
+}
+
+// queuing gcodes needs to be done from main loop
+void ControlScreen::on_main_loop() {
+       // change actual axis value
+       if(!this->pos_changed) return;
+       this->pos_changed= false;
+       
+       set_current_pos(this->controlled_axis, this->pos[this->controlled_axis-'X']);
+}
+
+void ControlScreen::display_menu_line(uint16_t line){
+       // in menu mode
+    switch( line ){
+        case 0: this->panel->lcd->printf("Back");  break;  
+        case 1: this->display_axis_line('X'); break;  
+        case 2: this->display_axis_line('Y'); break;  
+        case 3: this->display_axis_line('Z'); break;  
+    }
+}
+
+void ControlScreen::display_axis_line(char axis){
+    this->panel->lcd->printf("Move %c    %8.3f", axis, this->pos[axis-'X']);
+}
+
+
+void ControlScreen::clicked_menu_entry(uint16_t line){
+    switch( line ){
+        case 0: this->panel->enter_screen(this->parent   ); break;
+        case 1: this->enter_axis_control('X'); break;
+        case 2: this->enter_axis_control('Y'); break;
+        case 3: this->enter_axis_control('Z'); break;
+    }
+}
+
+void ControlScreen::enter_axis_control(char axis){
+    this->control_mode = AXIS_CONTROL_MODE;
+    this->controlled_axis = axis;
+    this->panel->enter_control_mode(this->jog_increment, this->jog_increment/10);
+    this->panel->set_control_value(this->pos[axis-'X']);
+       this->panel->lcd->clear();
+       this->panel->lcd->setCursor(0,2);
+       this->display_axis_line(this->controlled_axis); 
+}
+
+void ControlScreen::enter_menu_control(){
+       this->control_mode = NULL_CONTROL_MODE;
+       this->panel->enter_menu_mode();
+}
+
+
+void ControlScreen::get_current_pos(double *cp){
+       void *returned_data;
+
+       bool ok= THEKERNEL->public_data->get_value( robot_checksum, current_position_checksum, &returned_data );
+       if(ok) {
+               double *p= static_cast<double *>(returned_data);
+               cp[0]= p[0];
+               cp[1]= p[1];
+               cp[2]= p[2];
+       }
+}
+void ControlScreen::set_current_pos(char axis, double p){      
+       // change pos by issuing a G0 Xnnn
+       char buf[32];
+       int n= snprintf(buf, sizeof(buf), "G0 %c%f F%d", axis, p, (int)round(panel->get_jogging_speed(axis)));
+       string g(buf, n);
+       send_gcode(g);
+}
+
+void ControlScreen::send_gcode(std::string g) {
+       Gcode gcode(g, &(StreamOutput::NullStream));
+       THEKERNEL->call_event(ON_GCODE_RECEIVED, &gcode );
+}
+
diff --git a/src/modules/utils/panel/screens/ControlScreen.h b/src/modules/utils/panel/screens/ControlScreen.h
new file mode 100644 (file)
index 0000000..93ae5d7
--- /dev/null
@@ -0,0 +1,53 @@
+/*  
+      This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
+      Smoothie 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 3 of the License, or (at your option) any later version.
+      Smoothie 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 Smoothie. If not, see <http://www.gnu.org/licenses/>. 
+*/
+
+#ifndef CONTROLSCREEN_H
+#define CONTROLSCREEN_H
+
+#include "libs/Kernel.h"
+#include "libs/nuts_bolts.h"
+#include "libs/utils.h"
+#include "libs/Pin.h"
+#include "LcdBase.h"
+#include "Panel.h"
+#include "PanelScreen.h"
+#include "MainMenuScreen.h"
+
+#define NULL_CONTROL_MODE        0
+#define AXIS_CONTROL_MODE        1
+#define INCREMENT_SELECTION_MODE 2
+
+class ControlScreen : public PanelScreen {
+    public:
+        ControlScreen();
+        void on_main_loop(); 
+        void on_refresh(); 
+        void on_enter();
+        void display_menu_line(uint16_t line);
+        void set_jog_increment(double i) { jog_increment= i; }
+        
+    private:
+        void clicked_menu_entry(uint16_t line);
+        void display_axis_line(char axis);
+        void send_gcode(std::string msg);
+        void enter_axis_control(char axis);
+        void enter_menu_control();
+        void get_current_pos(double *p);
+        void set_current_pos(char axis, double p);
+        char control_mode;
+        char controlled_axis;
+        double pos[3];
+        bool pos_changed;
+        double jog_increment;
+};
+
+
+
+
+
+
+#endif
diff --git a/src/modules/utils/panel/screens/FileScreen.cpp b/src/modules/utils/panel/screens/FileScreen.cpp
new file mode 100644 (file)
index 0000000..d0a2131
--- /dev/null
@@ -0,0 +1,180 @@
+/*  
+      This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
+      Smoothie 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 3 of the License, or (at your option) any later version.
+      Smoothie 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 Smoothie. If not, see <http://www.gnu.org/licenses/>. 
+*/
+
+#include "libs/Kernel.h"
+#include "Panel.h"
+#include "PanelScreen.h"
+#include "MainMenuScreen.h"
+#include "FileScreen.h"
+#include "libs/nuts_bolts.h"
+#include "libs/utils.h"
+#include <string>
+#include "libs/SerialMessage.h"
+
+#include "DirHandle.h"
+#include "mri.h"
+
+using namespace std;
+
+FileScreen::FileScreen(){
+       this->current_folder = "";
+       this->start_play= false;
+}
+
+// When entering this screen
+void FileScreen::on_enter(){
+    this->panel->lcd->clear();
+
+    // Default folder to enter
+    if( this->current_folder.compare("") == 0 ){
+        this->enter_folder("/");
+    }else{
+        this->enter_folder(this->current_folder);
+    }
+}
+
+// For every ( potential ) refresh of the screen
+void FileScreen::on_refresh(){
+    if( this->panel->menu_change() ){
+        this->panel->lcd->clear();
+        this->refresh_menu();
+    }
+    if( this->panel->click() ){
+        this->clicked_line(this->panel->menu_current_line());
+    }
+}
+
+// Enter a new folder
+void FileScreen::enter_folder(std::string folder){
+
+    // Rembember where we are
+    this->current_folder = folder;
+   
+    // We need the number of lines to setup the menu
+    uint16_t number_of_files_in_folder = this->count_folder_content(this->current_folder);
+
+    // Setup menu
+    this->panel->setup_menu(number_of_files_in_folder+1, 4);  // same number of files as menu items, 4 lines
+    this->panel->enter_menu_mode();
+
+    // Display menu
+    this->panel->lcd->clear();
+    this->refresh_menu();
+
+}
+
+// Called by the panel when refreshing the menu, display .. then all files in the current dir
+void FileScreen::display_menu_line(uint16_t line){
+    if( line == 0 ){
+        this->panel->lcd->printf("..");
+    }else{
+        this->panel->lcd->printf("%s", (this->file_at(line-1)).c_str() );
+    }
+}
+
+// When a line is clicked in the menu, act
+void FileScreen::clicked_line(uint16_t line){
+    if( line == 0 ){
+        if( this->current_folder.compare("/") == 0 ){
+            // Exit file navigation 
+            this->panel->enter_screen(this->parent);
+        }else{
+            // Go up one folder
+            this->current_folder = this->current_folder.substr(0,this->current_folder.find_last_of('/')+1);
+            if( this->current_folder[this->current_folder.length()-1] == '/' && this->current_folder.length() != 1 ){ this->current_folder.erase(this->current_folder.length()-1,1); }
+            this->enter_folder(this->current_folder);
+        }
+    }else{
+        //printf("enter file\r\n");
+        // Enter file
+        string path = this->current_folder;
+        if( path.compare("/") == 0 ){ path = ""; } 
+        path = path + "/" + this->file_at( line-1 ); 
+        if( this->is_a_folder( path ) ){
+                       this->enter_folder(path);
+                       return;
+        } 
+
+               // start printing that file...
+               this->play_path= path;
+               this->start_play= true;
+    }
+
+}
+
+// Check wether a line is a folder or a file
+bool FileScreen::is_a_folder( string path ){
+    // In the special case of /local/ ( the mbed flash chip ) we don't have sub-folders, everything is a file 
+    if( path.substr(0,7).compare("/local/") == 0 ){
+        return false; 
+    }
+    // Else, check if it's a folder or not
+    DIR *d;
+    d = opendir(path.c_str());
+    if(d == NULL) { 
+         return false; 
+    }else{
+        closedir(d);
+        return true; 
+    }
+}
+
+// Find the "line"th file in the current folder
+string FileScreen::file_at(uint16_t line){
+    DIR* d;
+    struct dirent* p;
+    uint16_t count = 0;
+    d = opendir(this->current_folder.c_str());
+    if(d != NULL) {
+        while((p = readdir(d)) != NULL) { 
+            if( count == line ){ 
+                string to_return =  lc(string(p->d_name)); 
+                //printf("line: %u string:%s\r\n", line, to_return.c_str()); 
+                if( to_return[to_return.length()-1] == '.' ){ to_return[to_return.length()-1] = 0x00; }
+                closedir(d);
+                return to_return;
+            }
+            count++;
+        }
+       }
+       
+    if(d != NULL) closedir(d);
+       return ""; 
+}
+
+// Count how many files there are in the current folder
+uint16_t FileScreen::count_folder_content(std::string folder){
+    DIR* d;
+    struct dirent* p;
+    uint16_t count = 0;
+    d = opendir(folder.c_str());
+    if(d != NULL) {
+        while((p = readdir(d)) != NULL) { 
+            count++; 
+        }
+        closedir(d);
+        return count;
+    } else {
+        return 0; 
+    }
+}
+void FileScreen::on_main_loop(){
+       if(this->start_play){
+               this->start_play= false;
+               play(this->play_path);
+               panel->set_playing_file(this->play_path);
+               this->panel->enter_screen(this->parent);
+               return;
+       }
+}
+
+void FileScreen::play(string path) {
+       struct SerialMessage message;
+       message.message = string("play ") + path + " -q";
+       message.stream = &(StreamOutput::NullStream);
+       THEKERNEL->call_event(ON_CONSOLE_LINE_RECEIVED, &message );
+}
diff --git a/src/modules/utils/panel/screens/FileScreen.h b/src/modules/utils/panel/screens/FileScreen.h
new file mode 100644 (file)
index 0000000..6afd239
--- /dev/null
@@ -0,0 +1,48 @@
+/*  
+      This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
+      Smoothie 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 3 of the License, or (at your option) any later version.
+      Smoothie 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 Smoothie. If not, see <http://www.gnu.org/licenses/>. 
+*/
+
+#ifndef FILESCREEN_H
+#define FILESCREEN_H
+
+#include "libs/Kernel.h"
+#include "libs/nuts_bolts.h"
+#include "libs/utils.h"
+#include "libs/Pin.h"
+#include "LcdBase.h"
+#include "Panel.h"
+#include "PanelScreen.h"
+
+#include <string>
+using namespace std;
+
+class FileScreen : public PanelScreen {
+    public:
+        FileScreen();
+        void on_enter();
+        void on_refresh(); 
+        void on_main_loop();
+        void enter_folder(std::string folder);
+        uint16_t count_folder_content(std::string folder);
+        void clicked_line(uint16_t line);
+        void display_menu_line(uint16_t line);
+        bool is_a_folder( string path );
+        string file_at(uint16_t line);
+
+        std::string current_folder;
+
+    private:
+        void play(string path);
+        bool start_play;
+        string play_path;
+};
+
+
+
+
+
+
+#endif
diff --git a/src/modules/utils/panel/screens/JogScreen.cpp b/src/modules/utils/panel/screens/JogScreen.cpp
new file mode 100644 (file)
index 0000000..b17d701
--- /dev/null
@@ -0,0 +1,63 @@
+/*  
+      This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
+      Smoothie 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 3 of the License, or (at your option) any later version.
+      Smoothie 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 Smoothie. If not, see <http://www.gnu.org/licenses/>. 
+*/
+
+#include "libs/Kernel.h"
+#include "libs/SerialMessage.h"
+#include "Panel.h"
+#include "PanelScreen.h"
+#include "MainMenuScreen.h"
+#include "JogScreen.h"
+#include "ControlScreen.h"
+#include "libs/nuts_bolts.h"
+#include "libs/utils.h"
+#include <string>
+
+using namespace std;
+
+
+JogScreen::JogScreen(){
+       this->control_screen = new ControlScreen();
+       this->control_screen->set_parent(this);
+}
+
+void JogScreen::on_enter(){
+       this->panel->enter_menu_mode();
+       this->panel->setup_menu(4, 4);  // 6 menu items, 4 lines
+       this->refresh_screen();
+}
+
+void JogScreen::on_refresh(){
+       if( this->panel->menu_change() ){
+               this->refresh_screen();
+       }
+       if( this->panel->click() ){
+               this->clicked_menu_entry(this->panel->menu_current_line());
+       }
+}
+
+void JogScreen::refresh_screen(){
+       this->refresh_menu();
+}
+
+void JogScreen::display_menu_line(uint16_t line){
+    switch( line ){
+               case 0: this->panel->lcd->printf("Back");  break;  
+               case 1: this->panel->lcd->printf("Move 10.0mm      \x7E"); break;  
+               case 2: this->panel->lcd->printf("Move  1.0mm      \x7E");  break;  
+               case 3: this->panel->lcd->printf("Move  0.1mm      \x7E");  break;  
+    }
+}
+
+void JogScreen::clicked_menu_entry(uint16_t line){
+    switch( line ){
+               case 0: this->panel->enter_screen(this->parent); return;
+               case 1: this->control_screen->set_jog_increment(10.0); break;
+               case 2: this->control_screen->set_jog_increment(1.0); break;
+               case 3: this->control_screen->set_jog_increment(0.1); break;
+    }
+       this->panel->enter_screen(this->control_screen);
+}
diff --git a/src/modules/utils/panel/screens/JogScreen.h b/src/modules/utils/panel/screens/JogScreen.h
new file mode 100644 (file)
index 0000000..5cf8135
--- /dev/null
@@ -0,0 +1,39 @@
+/*  
+      This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
+      Smoothie 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 3 of the License, or (at your option) any later version.
+      Smoothie 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 Smoothie. If not, see <http://www.gnu.org/licenses/>. 
+*/
+
+#ifndef JOGSCREEN_H
+#define JOGSCREEN_H
+
+#include "libs/Kernel.h"
+#include "libs/nuts_bolts.h"
+#include "libs/utils.h"
+#include "libs/Pin.h"
+#include "LcdBase.h"
+#include "Panel.h"
+#include "PanelScreen.h"
+#include "ControlScreen.h"
+
+
+class JogScreen : public PanelScreen {
+    public:
+        JogScreen();
+        void on_refresh();
+        void on_enter();
+        void refresh_screen(); 
+        void display_menu_line(uint16_t line);
+        void clicked_menu_entry(uint16_t line);
+
+    private:
+        ControlScreen *control_screen;
+};
+
+
+
+
+
+
+#endif
diff --git a/src/modules/utils/panel/screens/MainMenuScreen.cpp b/src/modules/utils/panel/screens/MainMenuScreen.cpp
new file mode 100644 (file)
index 0000000..1e66e2d
--- /dev/null
@@ -0,0 +1,84 @@
+/*  
+      This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
+      Smoothie 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 3 of the License, or (at your option) any later version.
+      Smoothie 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 Smoothie. If not, see <http://www.gnu.org/licenses/>. 
+*/
+
+#include "libs/Kernel.h"
+#include "Panel.h"
+#include "PanelScreen.h"
+#include "MainMenuScreen.h"
+#include "WatchScreen.h"
+#include "FileScreen.h"
+#include "ControlScreen.h"
+#include "PrepareScreen.h"
+#include "libs/nuts_bolts.h"
+#include "libs/utils.h"
+#include "modules/utils/player/PlayerPublicAccess.h"
+
+
+#include <string>
+using namespace std;
+
+MainMenuScreen::MainMenuScreen(){
+       // Children screens
+       this->jog_screen     = (new JogScreen()     )->set_parent(this);
+       this->watch_screen   = (new WatchScreen()   )->set_parent(this);
+       this->file_screen    = (new FileScreen()    )->set_parent(this);
+       this->prepare_screen = (new PrepareScreen() )->set_parent(this);
+       this->set_parent(this->watch_screen);
+}
+
+void MainMenuScreen::on_enter(){
+    this->panel->enter_menu_mode();
+    this->panel->setup_menu(6, 4);  // 6 menu items, 4 lines
+    this->refresh_screen();
+}
+
+void MainMenuScreen::on_refresh(){
+    if( this->panel->menu_change() ){
+        this->refresh_screen();
+    }
+    if( this->panel->click() ){
+        this->clicked_menu_entry(this->panel->menu_current_line());
+    }
+
+
+}
+
+void MainMenuScreen::refresh_screen(){
+    this->refresh_menu();
+}
+
+void MainMenuScreen::display_menu_line(uint16_t line){
+    switch( line ){
+        case 0: this->panel->lcd->printf("Watch"); break;  
+        case 1: this->panel->lcd->printf(panel->is_playing() ? "Abort" : "Play"); break; 
+        case 2: this->panel->lcd->printf("Jog"); break; 
+        case 3: this->panel->lcd->printf("Prepare"); break; 
+        case 4: this->panel->lcd->printf("Configure"); break; 
+        case 5: this->panel->lcd->printf("Tune"); break; 
+    }
+
+}
+
+void MainMenuScreen::clicked_menu_entry(uint16_t line){
+    switch( line ){
+        case 0: this->panel->enter_screen(this->watch_screen   ); break;
+               case 1: if(this->panel->is_playing())
+                                       abort_playing();
+                               else
+                                       this->panel->enter_screen(this->file_screen);
+                               break;
+        case 2: this->panel->enter_screen(this->jog_screen     ); break;
+        case 3: this->panel->enter_screen(this->prepare_screen ); break;
+    }
+}
+
+
+void MainMenuScreen::abort_playing() {
+       THEKERNEL->public_data->set_value(player_checksum, abort_play_checksum, NULL);
+       this->panel->enter_screen(this->watch_screen);
+}
+
diff --git a/src/modules/utils/panel/screens/MainMenuScreen.h b/src/modules/utils/panel/screens/MainMenuScreen.h
new file mode 100644 (file)
index 0000000..3ba61b7
--- /dev/null
@@ -0,0 +1,45 @@
+/*  
+      This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
+      Smoothie 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 3 of the License, or (at your option) any later version.
+      Smoothie 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 Smoothie. If not, see <http://www.gnu.org/licenses/>. 
+*/
+
+#ifndef MAINMENUSCREEN_H
+#define MAINMENUSCREEN_H
+
+#include "libs/Kernel.h"
+#include "libs/nuts_bolts.h"
+#include "libs/utils.h"
+#include "libs/Pin.h"
+#include "LcdBase.h"
+#include "Panel.h"
+#include "PanelScreen.h"
+#include "WatchScreen.h"
+#include "JogScreen.h"
+
+class MainMenuScreen : public PanelScreen {
+    public:
+        MainMenuScreen();
+        void on_refresh(); 
+        void on_enter();
+        void refresh_screen();
+        void display_menu_line(uint16_t line);
+        void clicked_menu_entry(uint16_t line);
+
+        PanelScreen* watch_screen;
+        PanelScreen* file_screen;
+        PanelScreen* jog_screen;
+        PanelScreen* prepare_screen;
+
+    private:
+        void abort_playing();
+
+};
+
+
+
+
+
+
+#endif
diff --git a/src/modules/utils/panel/screens/PrepareScreen.cpp b/src/modules/utils/panel/screens/PrepareScreen.cpp
new file mode 100644 (file)
index 0000000..f43762f
--- /dev/null
@@ -0,0 +1,82 @@
+/*  
+      This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
+      Smoothie 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 3 of the License, or (at your option) any later version.
+      Smoothie 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 Smoothie. If not, see <http://www.gnu.org/licenses/>. 
+*/
+
+#include "libs/Kernel.h"
+#include "Panel.h"
+#include "PanelScreen.h"
+#include "PrepareScreen.h"
+#include "libs/nuts_bolts.h"
+#include "libs/utils.h"
+#include <string>
+#include "libs/SerialMessage.h"
+using namespace std;
+
+PrepareScreen::PrepareScreen(){
+       // Children screens
+//     this->extruder_screen = (new ExtruderScreen()  )->set_parent(this);
+//     this->temp_screen     = (new TempScreen()      )->set_parent(this);
+}
+
+void PrepareScreen::on_enter(){
+    this->panel->enter_menu_mode();
+    this->panel->setup_menu(7, 4);  // 7 menu items, 4 lines
+    this->refresh_screen();
+}
+
+void PrepareScreen::on_refresh(){
+    if( this->panel->menu_change() ){
+        this->refresh_screen();
+    }
+    if( this->panel->click() ){
+        this->clicked_menu_entry(this->panel->menu_current_line());
+    }
+}
+
+void PrepareScreen::refresh_screen(){
+    this->refresh_menu();
+}
+
+void PrepareScreen::display_menu_line(uint16_t line){
+    switch( line ){
+        case 0: this->panel->lcd->printf("Back"           ); break;  
+        case 1: this->panel->lcd->printf("Home All Axis"  ); break; 
+        case 2: this->panel->lcd->printf("Set Home"       ); break; 
+        case 3: this->panel->lcd->printf("Pre Heat"       ); break; 
+               case 4: this->panel->lcd->printf("Cool Down"      ); break; 
+        case 5: this->panel->lcd->printf("Extrude"        ); break; 
+        case 6: this->panel->lcd->printf("Set Temperature"); break; 
+    }
+}
+
+void PrepareScreen::clicked_menu_entry(uint16_t line){
+    switch( line ){
+               case 0: this->panel->enter_screen(this->parent           ); break;
+               case 1: send_gcode("G28"); break;
+               case 2: send_gcode("G92 X0 Y0 Z0"); break;
+        case 3: this->preheat(); break;
+        case 4: this->cooldown(); break;
+        case 5: this->panel->enter_screen(this->extruder_screen  ); break;
+        case 6: this->panel->enter_screen(this->temp_screen      ); break;
+    }
+
+
+}
+
+
+void PrepareScreen::preheat() {
+}
+
+void PrepareScreen::cooldown() {
+}
+
+void PrepareScreen::send_gcode(const char* gcstr) {
+       string gcode(gcstr);
+       struct SerialMessage message;
+       message.message = gcode;
+       message.stream = &(StreamOutput::NullStream);
+       THEKERNEL->call_event(ON_CONSOLE_LINE_RECEIVED, &message );
+}
diff --git a/src/modules/utils/panel/screens/PrepareScreen.h b/src/modules/utils/panel/screens/PrepareScreen.h
new file mode 100644 (file)
index 0000000..07489c2
--- /dev/null
@@ -0,0 +1,37 @@
+/*  
+      This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
+      Smoothie 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 3 of the License, or (at your option) any later version.
+      Smoothie 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 Smoothie. If not, see <http://www.gnu.org/licenses/>. 
+*/
+
+#ifndef PREPARESCREEN_H
+#define PREPARESCREEN_H
+
+#include "libs/Kernel.h"
+#include "libs/nuts_bolts.h"
+#include "libs/utils.h"
+#include "libs/Pin.h"
+#include "LcdBase.h"
+#include "Panel.h"
+#include "PanelScreen.h"
+
+class PrepareScreen : public PanelScreen {
+    public:
+        PrepareScreen();
+
+        void on_refresh(); 
+        void on_enter();
+        void refresh_screen();
+        void display_menu_line(uint16_t line);
+        void clicked_menu_entry(uint16_t line);
+
+    private:
+        PanelScreen* extruder_screen;
+        PanelScreen* temp_screen;
+        void preheat();
+        void cooldown();
+        void send_gcode(const char* gcstr);
+};
+
+#endif
diff --git a/src/modules/utils/panel/screens/WatchScreen.cpp b/src/modules/utils/panel/screens/WatchScreen.cpp
new file mode 100644 (file)
index 0000000..006f302
--- /dev/null
@@ -0,0 +1,137 @@
+/*  
+      This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
+      Smoothie 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 3 of the License, or (at your option) any later version.
+      Smoothie 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 Smoothie. If not, see <http://www.gnu.org/licenses/>. 
+*/
+
+#include "libs/Kernel.h"
+#include "Panel.h"
+#include "PanelScreen.h"
+#include "MainMenuScreen.h"
+#include "WatchScreen.h"
+#include "libs/nuts_bolts.h"
+#include "libs/utils.h"
+#include "modules/tools/temperaturecontrol/TemperatureControlPublicAccess.h"
+#include "modules/robot/RobotPublicAccess.h"
+#include "modules/utils/player/PlayerPublicAccess.h"
+
+#include <string>
+using namespace std;
+
+WatchScreen::WatchScreen(){}
+
+void WatchScreen::on_enter(){
+       this->panel->lcd->clear();
+       this->panel->setup_menu(4, 4);
+       get_temp_data();
+       get_current_pos(this->pos);
+       get_sd_play_info();
+       this->current_speed= get_current_speed();
+       this->refresh_screen(false);
+       this->panel->enter_control_mode(1,0.5);
+       this->panel->set_control_value(this->current_speed);
+}
+
+void WatchScreen::on_refresh(){
+    // Exit if the button is clicked 
+    if( this->panel->click() ){
+        this->panel->enter_screen(this->parent);
+        return;
+       }
+
+       // see if speed is being changed
+       if(this->panel->control_value_change()) {
+               this->current_speed= this->panel->get_control_value();
+               // change actual speed
+               set_current_speed();
+               this->refresh_screen(false);
+       }
+       
+    // Update Only every 20 refreshes, 1 a second
+    static int update_counts = 0;
+    update_counts++;
+       if( update_counts % 20 == 0 ){
+               get_sd_play_info();
+               get_current_pos(this->pos);
+               get_temp_data();
+               this->current_speed= get_current_speed();
+               this->refresh_screen(false);
+    }
+}
+
+// fetch the data we are displaying
+void WatchScreen::get_temp_data() {
+       void *returned_data;
+       bool ok;
+
+       ok= THEKERNEL->public_data->get_value( temperature_control_checksum, bed_checksum, current_temperature_checksum, &returned_data );
+       if(ok) {
+               struct pad_temperature temp=  *static_cast<struct pad_temperature*>(returned_data);
+               this->bedtemp= round(temp.current_temperature);
+               this->bedtarget= round(temp.target_temperature);
+               //this->bedpwm= temp.pwm;
+       }
+
+       ok= THEKERNEL->public_data->get_value( temperature_control_checksum, hotend_checksum, current_temperature_checksum, &returned_data );
+       if(ok) {
+               struct pad_temperature temp=  *static_cast<struct pad_temperature*>(returned_data);
+               this->hotendtemp= round(temp.current_temperature);
+               this->hotendtarget= round(temp.target_temperature);
+               //this->hotendpwm= temp.pwm;
+       }
+}
+
+// fetch the data we are displaying
+double WatchScreen::get_current_speed() {
+       void *returned_data;
+       
+       bool ok= THEKERNEL->public_data->get_value( robot_checksum, speed_override_percent_checksum, &returned_data );
+       if(ok) {
+               double cs= *static_cast<double *>(returned_data);
+               return cs;
+       }
+       return 0.0;
+}
+
+void WatchScreen::set_current_speed() {
+       bool ok= THEKERNEL->public_data->set_value( robot_checksum, speed_override_percent_checksum, &this->current_speed );
+       if(!ok) this->current_speed= 0;
+               
+}
+
+void WatchScreen::get_current_pos(double *cp){
+       void *returned_data;
+
+       bool ok= THEKERNEL->public_data->get_value( robot_checksum, current_position_checksum, &returned_data );
+       if(ok) {
+               double *p= static_cast<double *>(returned_data);
+               cp[0]= p[0];
+               cp[1]= p[1];
+               cp[2]= p[2];
+       }
+}
+
+void WatchScreen::get_sd_play_info(){
+       void *returned_data;
+       bool ok= THEKERNEL->public_data->get_value( player_checksum, get_progress_checksum, &returned_data );
+       if(ok) {
+               struct pad_progress p=  *static_cast<struct pad_progress*>(returned_data);
+               this->elapsed_time= p.elapsed_secs;
+               this->sd_pcnt_played= p.percent_complete;
+       }else{
+               this->elapsed_time= 0;
+               this->sd_pcnt_played= 0;
+       }
+}
+
+void WatchScreen::display_menu_line(uint16_t line){
+       // in menu mode
+       switch( line ){
+               case 0: this->panel->lcd->printf("H%03d/%03dc B%03d/%03dc", this->hotendtemp, this->hotendtarget, this->bedtemp, this->bedtarget); break;
+               case 1: this->panel->lcd->printf("X%4d Y%4d Z%7.2f", (int)round(this->pos[0]), (int)round(this->pos[1]), this->pos[2]); break;
+               case 2: this->panel->lcd->printf("%3d%% %2d:%02d %3d%% sd", (int)round(this->current_speed), this->elapsed_time/60, this->elapsed_time%60, this->sd_pcnt_played); break;
+               case 3: this->panel->lcd->printf("%19s", panel->is_playing() ? panel->get_playing_file().substr(4, 19).c_str() : "Smoothie ready"); break;
+       }
+
+}
diff --git a/src/modules/utils/panel/screens/WatchScreen.h b/src/modules/utils/panel/screens/WatchScreen.h
new file mode 100644 (file)
index 0000000..34dea5a
--- /dev/null
@@ -0,0 +1,48 @@
+/*  
+      This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
+      Smoothie 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 3 of the License, or (at your option) any later version.
+      Smoothie 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 Smoothie. If not, see <http://www.gnu.org/licenses/>. 
+*/
+
+#ifndef WATCHSCREEN_H
+#define WATCHSCREEN_H
+
+#include "libs/Kernel.h"
+#include "libs/nuts_bolts.h"
+#include "libs/utils.h"
+#include "libs/Pin.h"
+#include "LcdBase.h"
+#include "Panel.h"
+#include "PanelScreen.h"
+
+class WatchScreen : public PanelScreen {
+    public:
+        WatchScreen();
+        void on_refresh(); 
+        void on_enter();
+        void display_menu_line(uint16_t line);
+
+    private:
+        void get_temp_data();
+        double get_current_speed();
+        void set_current_speed();
+        void get_current_pos(double *cp);
+        void get_sd_play_info();
+        
+        int hotendtemp;
+        int hotendtarget;
+        int bedtemp;
+        int bedtarget;
+        double current_speed;
+        double pos[3];
+        int elapsed_time;
+        int sd_pcnt_played;
+};
+
+
+
+
+
+
+#endif
index 00bc0ae..70f4a08 100644 (file)
@@ -14,6 +14,8 @@
 #include "libs/StreamOutput.h"
 #include "modules/robot/Conveyor.h"
 #include "DirHandle.h"
+#include "PublicDataRequest.h"
+#include "PlayerPublicAccess.h"
 
 void Player::on_module_loaded(){
     this->playing_file = false;
@@ -21,6 +23,8 @@ void Player::on_module_loaded(){
     this->register_for_event(ON_CONSOLE_LINE_RECEIVED);
     this->register_for_event(ON_MAIN_LOOP);
     this->register_for_event(ON_SECOND_TICK);
+       this->register_for_event(ON_GET_PUBLIC_DATA);
+       this->register_for_event(ON_SET_PUBLIC_DATA);
 
     this->on_boot_gcode = this->kernel->config->value(on_boot_gcode_checksum)->by_default("/sd/on_boot.gcode -q")->as_string();
     this->on_boot_gcode_enable = this->kernel->config->value(on_boot_gcode_enable_checksum)->by_default(true)->as_bool();
@@ -187,6 +191,48 @@ void Player::on_main_loop(void* argument){
     }
 }
 
+void Player::on_get_public_data(void* argument) {
+       PublicDataRequest* pdr = static_cast<PublicDataRequest*>(argument);
+
+       if(!pdr->starts_with(player_checksum)) return;
+
+       if(pdr->second_element_is(is_playing_checksum)) {
+               static bool bool_data;
+               bool_data= this->playing_file;
+               pdr->set_data_ptr(&bool_data);
+               pdr->set_taken();
+               
+       }else if(pdr->second_element_is(get_progress_checksum)) {
+               static struct pad_progress p;
+               if(file_size > 0 && playing_file) {
+                       p.elapsed_secs= this->elapsed_secs;
+                       p.percent_complete= (this->file_size - (this->file_size - this->played_cnt)) * 100 / this->file_size;
+                       pdr->set_data_ptr(&p);
+                       pdr->set_taken();
+               }
+       }
+}
+
+void Player::on_set_public_data(void* argument) {
+       PublicDataRequest* pdr = static_cast<PublicDataRequest*>(argument);
+
+       if(!pdr->starts_with(player_checksum)) return;
+
+       if(pdr->second_element_is(abort_play_checksum)) {
+               if(playing_file) {
+                       playing_file = false;
+                       played_cnt= 0;
+                       file_size= 0;
+                       fclose(current_file_handler);
+                       pdr->set_taken();
+               }
+       }
+}
+
+
+
+
+
 /*
 void Player::on_main_loop(void* argument){
     if( !this->on_booted ){
index 716f214..41247e6 100644 (file)
@@ -29,6 +29,9 @@ class Player : public Module {
         void on_console_line_received( void* argument );
         void on_main_loop( void* argument );
         void on_second_tick(void* argument);
+        void on_get_public_data(void* argument);
+        void on_set_public_data(void* argument);
+
         string absolute_from_relative( string path );
         void cd_command(   string parameters, StreamOutput* stream );
         void play_command( string parameters, StreamOutput* stream );
diff --git a/src/modules/utils/player/PlayerPublicAccess.h b/src/modules/utils/player/PlayerPublicAccess.h
new file mode 100644 (file)
index 0000000..1f0a354
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef PLAYERPUBLICACCESS_H
+#define PLAYERPUBLICACCESS_H
+
+#define player_checksum           CHECKSUM("player")
+#define is_playing_checksum       CHECKSUM("is_playing")
+#define abort_play_checksum       CHECKSUM("abort_play")
+#define get_progress_checksum     CHECKSUM("progress")
+
+struct pad_progress {
+    int percent_complete;
+    int elapsed_secs;
+};
+#endif
\ No newline at end of file