Subversion Repositories HomeAutomation

Rev

Rev 1665 | Rev 1911 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. /*
  2.  *
  3.  *  Copyright (C) 2010  Mattias Runge
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2 of the License, or
  8.  *  (at your option) any later version.
  9.  *
  10.  *  This program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *  GNU General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU General Public License along
  16.  *  with this program; if not, write to the Free Software Foundation, Inc.,
  17.  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18.  *
  19.  */
  20.  
  21. #include "Node.h"
  22.  
  23. #include <boost/date_time/posix_time/posix_time.hpp>
  24. #include <boost/lexical_cast.hpp>
  25.  
  26. #include "Manager.h"
  27. #include "can/Message.h"
  28. #include "broker/Manager.h"
  29.  
  30. namespace atom {
  31. namespace control {
  32.  
  33. Node::TransitionList Node::transitions_;
  34. std::map<Node::State, std::string> Node::state_names_;
  35. std::map<Node::Event, std::string> Node::event_names_;
  36.    
  37. Node::Node(Node::Id id) : LOG("control::Node")
  38. {
  39.     this->state_ = STATE_NORM_OFFLINE;
  40.     this->id_ = boost::algorithm::to_lower_copy((std::string)id);
  41.     this->information_.has_application_ = false;
  42.     this->information_.bios_version_ = 0;
  43.     this->information_.device_type_ = "N/A";
  44.     this->information_.last_active_ = 0;
  45.     this->information_.valid_ = false;
  46.    
  47.     this->current_offset_ = 0;
  48.     this->expected_ack_data_ = 0;
  49.     this->program_start_time_ = 0;
  50. }
  51.  
  52. Node::~Node()
  53. {
  54.  
  55. }
  56.  
  57. void Node::ConnectSlots(const SignalOnNewState::slot_type& slot_on_new_state)
  58. {
  59.     this->signal_on_new_state_.connect(slot_on_new_state);
  60. }
  61.  
  62. Node::Id Node::GetId()
  63. {
  64.     return this->id_;
  65. }
  66.  
  67. Node::Information Node::GetInformation()
  68. {
  69.     return this->information_;
  70. }
  71.  
  72. void Node::SetupStateMachine()
  73. {
  74.     // Normal flow
  75.     Node::AddTransition(STATE_NORM_OFFLINE,          EVENT_BIOS_START,        STATE_NORM_ONLINE);
  76.     Node::AddTransition(STATE_NORM_OFFLINE,          EVENT_APP_START,         STATE_NORM_LIST);
  77.     Node::AddTransition(STATE_NORM_OFFLINE,          EVENT_HEARTBEAT,         STATE_NORM_LIST);
  78.     Node::AddTransition(STATE_NORM_OFFLINE,          EVENT_PROGRAM_BIOS,      STATE_BPGM_OFFLINE);
  79.     Node::AddTransition(STATE_NORM_OFFLINE,          EVENT_PROGRAM_APP,       STATE_APGM_OFFLINE);
  80.     Node::AddTransition(STATE_NORM_OFFLINE,          EVENT_RESET,             STATE_NO_CHANGE);
  81.    
  82.     Node::AddTransition(STATE_NORM_ONLINE,           EVENT_BIOS_START,        STATE_NORM_ONLINE);
  83.     Node::AddTransition(STATE_NORM_ONLINE,           EVENT_APP_START,         STATE_NORM_LIST);
  84.     Node::AddTransition(STATE_NORM_ONLINE,           EVENT_HEARTBEAT,         STATE_NORM_LIST);
  85.     Node::AddTransition(STATE_NORM_ONLINE,           EVENT_PROGRAM_BIOS,      STATE_BPGM_OFFLINE);
  86.     Node::AddTransition(STATE_NORM_ONLINE,           EVENT_PROGRAM_APP,       STATE_APGM_OFFLINE);
  87.     Node::AddTransition(STATE_NORM_ONLINE,           EVENT_RESET,             STATE_NORM_OFFLINE);
  88.    
  89.     Node::AddTransition(STATE_NORM_LIST,             EVENT_BIOS_START,        STATE_NORM_ONLINE);
  90.     Node::AddTransition(STATE_NORM_LIST,             EVENT_APP_START,         STATE_NORM_LIST);
  91.     Node::AddTransition(STATE_NORM_LIST,             EVENT_HEARTBEAT,         STATE_NO_CHANGE);
  92.     Node::AddTransition(STATE_NORM_LIST,             EVENT_LIST_DONE,         STATE_NORM_INITIALIZED);
  93.     Node::AddTransition(STATE_NORM_LIST,             EVENT_PROGRAM_BIOS,      STATE_BPGM_OFFLINE);
  94.     Node::AddTransition(STATE_NORM_LIST,             EVENT_PROGRAM_APP,       STATE_APGM_OFFLINE);
  95.     Node::AddTransition(STATE_NORM_LIST,             EVENT_RESET,             STATE_NORM_OFFLINE);
  96.    
  97.     Node::AddTransition(STATE_NORM_INITIALIZED,      EVENT_BIOS_START,        STATE_NORM_ONLINE);
  98.     Node::AddTransition(STATE_NORM_INITIALIZED,      EVENT_APP_START,         STATE_NORM_LIST);
  99.     Node::AddTransition(STATE_NORM_INITIALIZED,      EVENT_HEARTBEAT,         STATE_NO_CHANGE);
  100.     Node::AddTransition(STATE_NORM_INITIALIZED,      EVENT_PROGRAM_BIOS,      STATE_BPGM_OFFLINE);
  101.     Node::AddTransition(STATE_NORM_INITIALIZED,      EVENT_PROGRAM_APP,       STATE_APGM_OFFLINE);
  102.     Node::AddTransition(STATE_NORM_INITIALIZED,      EVENT_RESET,             STATE_NORM_OFFLINE);
  103.    
  104.    
  105.     // Program bios flow
  106.     Node::AddTransition(STATE_BPGM_OFFLINE,          EVENT_BIOS_START,        STATE_BPGM_START);
  107.    
  108.     Node::AddTransition(STATE_BPGM_START,            EVENT_PGM_ACK,           STATE_BPGM_DATA);
  109.     Node::AddTransition(STATE_BPGM_START,            EVENT_PGM_NACK,          STATE_NORM_OFFLINE); // Return to normal flow
  110.  
  111.     Node::AddTransition(STATE_BPGM_DATA,             EVENT_PGM_ACK,           STATE_BPGM_DATA); // If there is no more data to send STATE_PGM_END will be set instead
  112.     Node::AddTransition(STATE_BPGM_DATA,             EVENT_PGM_NACK,          STATE_NORM_OFFLINE); // Return to normal flow
  113.    
  114.     Node::AddTransition(STATE_BPGM_END,              EVENT_PGM_ACK,           STATE_BPGM_COPY);
  115.     Node::AddTransition(STATE_BPGM_END,              EVENT_PGM_NACK,          STATE_NORM_OFFLINE); // Return to normal flow
  116.    
  117.     Node::AddTransition(STATE_BPGM_COPY,             EVENT_BIOS_START,        STATE_APGM_OFFLINE); // Remove application after bios upgrade
  118.        
  119.    
  120.     // Program application flow
  121.     Node::AddTransition(STATE_APGM_OFFLINE,          EVENT_BIOS_START,        STATE_APGM_START);
  122.    
  123.     Node::AddTransition(STATE_APGM_START,            EVENT_PGM_ACK,           STATE_APGM_DATA);
  124.     Node::AddTransition(STATE_APGM_START,            EVENT_PGM_NACK,          STATE_NORM_OFFLINE); // Return to normal flow
  125.    
  126.     Node::AddTransition(STATE_APGM_DATA,             EVENT_PGM_ACK,           STATE_APGM_DATA); // If there is no more data to send STATE_PGM_END will be set instead
  127.     Node::AddTransition(STATE_APGM_DATA,             EVENT_PGM_NACK,          STATE_NORM_OFFLINE); // Return to normal flow
  128.    
  129.     Node::AddTransition(STATE_APGM_END,              EVENT_PGM_ACK,           STATE_NORM_OFFLINE); // Return to normal flow
  130.     Node::AddTransition(STATE_APGM_END,              EVENT_PGM_NACK,          STATE_NORM_OFFLINE); // Return to normal flow
  131.    
  132.    
  133.     Node::state_names_[STATE_INVALID] = "STATE_INVALID";
  134.     Node::state_names_[STATE_NO_CHANGE] = "STATE_NO_CHANGE";
  135.     Node::state_names_[STATE_NORM_OFFLINE] = "STATE_NORM_OFFLINE";
  136.     Node::state_names_[STATE_NORM_ONLINE] = "STATE_NORM_ONLINE";
  137.     Node::state_names_[STATE_NORM_LIST] = "STATE_NORM_LIST";
  138.     Node::state_names_[STATE_NORM_INITIALIZED] = "STATE_NORM_INITIALIZED";
  139.     Node::state_names_[STATE_BPGM_OFFLINE] = "STATE_BPGM_OFFLINE";
  140.     Node::state_names_[STATE_BPGM_START] = "STATE_BPGM_START";
  141.     Node::state_names_[STATE_BPGM_DATA] = "STATE_BPGM_DATA";
  142.     Node::state_names_[STATE_BPGM_END] = "STATE_BPGM_END";
  143.     Node::state_names_[STATE_BPGM_COPY] = "STATE_BPGM_COPY";
  144.     Node::state_names_[STATE_APGM_OFFLINE] = "STATE_APGM_OFFLINE";
  145.     Node::state_names_[STATE_APGM_START] = "STATE_APGM_START";
  146.     Node::state_names_[STATE_APGM_DATA] = "STATE_APGM_DATA";
  147.     Node::state_names_[STATE_APGM_END] = "STATE_APGM_END";
  148.    
  149.     Node::event_names_[EVENT_BIOS_START] = "EVENT_BIOS_START";
  150.     Node::event_names_[EVENT_APP_START] = "EVENT_APP_START";
  151.     Node::event_names_[EVENT_HEARTBEAT] = "EVENT_HEARTBEAT";
  152.     Node::event_names_[EVENT_PGM_ACK] = "EVENT_PGM_ACK";
  153.     Node::event_names_[EVENT_PGM_NACK] = "EVENT_PGM_NACK";
  154.     Node::event_names_[EVENT_LIST_DONE] = "EVENT_LIST_DONE";
  155.     Node::event_names_[EVENT_PROGRAM_BIOS] = "EVENT_PROGRAM_BIOS";
  156.     Node::event_names_[EVENT_PROGRAM_APP] = "EVENT_PROGRAM_APP";
  157.     Node::event_names_[EVENT_RESET] = "EVENT_RESET";
  158. }
  159.  
  160. void Node::AddTransition(Node::State current_state, Node::Event event, State target_state)
  161. {
  162.     Node::transitions_[current_state][event] = target_state;
  163. }
  164.  
  165. Node::State Node::GetTransitionTarget(Node::Event event)
  166. {
  167.     Node::TransitionList::iterator it1 = Node::transitions_.find(this->state_);
  168.    
  169.     if (it1 == Node::transitions_.end())
  170.     {
  171.         LOG.Warning("No transitions found for current state " + boost::lexical_cast<std::string>(this->state_));
  172.         return STATE_INVALID;
  173.     }
  174.    
  175.     Node::Transition::iterator it2 = it1->second.find(event);
  176.    
  177.     if (it2 == it1->second.end())
  178.     {
  179.         LOG.Warning("No transitions found for current state " + boost::lexical_cast<std::string>(this->state_) + " for event " + boost::lexical_cast<std::string>(event));
  180.         return STATE_INVALID;
  181.     }
  182.    
  183.     return it2->second;
  184. }
  185.  
  186. void Node::Trigger(Node::Event event, common::StringMap variables)
  187. {
  188.     this->ResetTimeout();
  189.    
  190.     State target_state = this->GetTransitionTarget(event);
  191.    
  192.     LOG.Debug("Trigger called on " + this->id_ + ", current state: " + Node::state_names_[this->state_] + ", event: " + Node::event_names_[event] + ", target state: "  + Node::state_names_[target_state]);
  193.    
  194.     if (event == EVENT_BIOS_START)
  195.     {
  196.         this->information_.has_application_ = boost::lexical_cast<int>(variables["HasApplication"]) > 0;
  197.         this->information_.bios_version_ = boost::lexical_cast<unsigned int>(variables["BiosVersion"]);
  198.         this->information_.device_type_ = variables["DeviceType"];
  199.         this->information_.valid_ = true;
  200.     }
  201.    
  202.     if (target_state == STATE_INVALID)
  203.     {
  204.         this->SendReset();
  205.         target_state = STATE_NORM_OFFLINE;
  206.     }
  207.     else if (target_state == STATE_NO_CHANGE)
  208.     {
  209.         return;
  210.     }
  211.    
  212.     if ((this->state_ == STATE_APGM_END || this->state_ == STATE_BPGM_END) && event == EVENT_PGM_ACK)
  213.     {
  214.         unsigned int checksum = boost::lexical_cast<unsigned int>(variables["Data"]);
  215.        
  216.         if (this->expected_ack_data_ != checksum)
  217.         {
  218.             LOG.Warning("Checksum received in ACK was incorrect got " + boost::lexical_cast<std::string>(checksum) + " expected " + boost::lexical_cast<std::string>(this->expected_ack_data_) + ", aborting...");
  219.         }
  220.         else if (this->state_ == STATE_BPGM_END)
  221.         {
  222.             float speed = (float)this->code_->GetLength() / (float)(time(NULL) - this->program_start_time_);
  223.            
  224.             LOG.Info("Data was successfully transferred to " + this->id_ + ", speed was " + boost::lexical_cast<std::string>(speed) + " B/s");
  225.            
  226.             LOG.Debug("Sending application programming copy to node " + this->id_);
  227.             can::Message* payload = new can::Message("nmt", "", "", 0, "Pgm_Copy");
  228.            
  229.             unsigned int source0 = GET_LOW_BYTE_16(this->start_offset_);
  230.             unsigned int source1 = GET_HIGH_BYTE_16(this->start_offset_);
  231.            
  232.             unsigned int destination0 = GET_LOW_BYTE_16(this->code_->GetAddressLower());
  233.             unsigned int destination1 = GET_HIGH_BYTE_16(this->code_->GetAddressLower());
  234.            
  235.             unsigned int length0 = GET_LOW_BYTE_16(this->code_->GetLength());
  236.             unsigned int length1 = GET_HIGH_BYTE_16(this->code_->GetLength());
  237.            
  238.             payload->SetVariable("Source0", boost::lexical_cast<std::string>(source0));
  239.             payload->SetVariable("Source1", boost::lexical_cast<std::string>(source1));
  240.             payload->SetVariable("Destination0", boost::lexical_cast<std::string>(destination0));
  241.             payload->SetVariable("Destination1", boost::lexical_cast<std::string>(destination1));
  242.             payload->SetVariable("Length0", boost::lexical_cast<std::string>(length0));
  243.             payload->SetVariable("Length1", boost::lexical_cast<std::string>(length1));
  244.            
  245.             broker::Manager::Instance()->Post(broker::Message::Pointer(new broker::Message(broker::Message::CAN_MESSAGE, broker::Message::PayloadPointer(payload), Manager::Instance().get())));
  246.         }
  247.         else
  248.         {
  249.             float speed = (float)this->code_->GetLength() / (float)(time(NULL) - this->program_start_time_);
  250.            
  251.             LOG.Info("Programming was completed successfully on " + this->id_ + ", speed was " + boost::lexical_cast<std::string>(speed) + " B/s");
  252.         }
  253.     }
  254.    
  255.     if (target_state == STATE_NORM_LIST)
  256.     {
  257.         this->SendListRequest();
  258.     }
  259.     else if (target_state == STATE_BPGM_OFFLINE || target_state == STATE_APGM_OFFLINE)
  260.     {
  261.         if (event != EVENT_BIOS_START)
  262.         {
  263.             this->SendReset();
  264.         }
  265.     }
  266.     else if (target_state == STATE_APGM_START || target_state == STATE_BPGM_START)
  267.     {
  268.         if (!this->code_->IsValid())
  269.         {
  270.             LOG.Error("Code is not valid, aborting...");
  271.             target_state = STATE_NORM_OFFLINE;
  272.         }
  273.         else
  274.         {
  275.             LOG.Debug("Sending programming start to node " + this->id_);
  276.             can::Message* payload = new can::Message("nmt", "", "", 0, "Pgm_Start");
  277.             payload->SetVariable("HardwareId", boost::lexical_cast<std::string>(common::FromHex(this->id_)));
  278.            
  279.             this->start_offset_ = target_state == STATE_BPGM_START ? 0 : this->code_->GetAddressLower();
  280.            
  281.             unsigned int address0 = GET_LOW_BYTE_16(this->start_offset_);
  282.             unsigned int address1 = GET_HIGH_BYTE_16(this->start_offset_);
  283.            
  284.             this->expected_ack_data_ = SWAP_BYTE_ORDER_16(this->start_offset_);
  285.            
  286.             payload->SetVariable("Address0", boost::lexical_cast<std::string>(address0));
  287.             payload->SetVariable("Address1", boost::lexical_cast<std::string>(address1));
  288.             payload->SetVariable("Address2", "0"); // Not used?
  289.             payload->SetVariable("Address3", "0"); // Not used?
  290.            
  291.             this->current_offset_ = 0;
  292.            
  293.             broker::Manager::Instance()->Post(broker::Message::Pointer(new broker::Message(broker::Message::CAN_MESSAGE, broker::Message::PayloadPointer(payload), Manager::Instance().get())));
  294.            
  295.             this->program_start_time_ = time(NULL);
  296.         }
  297.     }
  298.     else if (target_state == STATE_APGM_DATA || target_state == STATE_BPGM_DATA)
  299.     {
  300.         unsigned int offset = boost::lexical_cast<unsigned int>(variables["Data"]);
  301.        
  302.         if ( this->expected_ack_data_ != offset)
  303.         {
  304.             LOG.Warning("Offset received in ACK was incorrect got " + boost::lexical_cast<std::string>(offset) + " expected " + boost::lexical_cast<std::string>(this->expected_ack_data_) + ", aborting...");
  305.             target_state = STATE_NORM_OFFLINE;
  306.         }
  307.         else if (this->current_offset_ >= this->code_->GetLength())
  308.         {
  309.             LOG.Debug("Sending programming end to node " + this->id_);
  310.            
  311.             unsigned int checksum = this->code_->GetChecksum();
  312.             this->expected_ack_data_ = SWAP_BYTE_ORDER_16(checksum);
  313.            
  314.             can::Message* payload = new can::Message("nmt", "", "", 0, "Pgm_End");
  315.             broker::Manager::Instance()->Post(broker::Message::Pointer(new broker::Message(broker::Message::CAN_MESSAGE, broker::Message::PayloadPointer(payload), Manager::Instance().get())));
  316.            
  317.             target_state = target_state == STATE_BPGM_DATA ? STATE_BPGM_END : STATE_APGM_END;
  318.         }
  319.         else
  320.         {
  321.             LOG.Debug("Sending programming data to node " + this->id_);
  322.             can::Message* payload = new can::Message("nmt", "", "", 0, "Pgm_Data_48");
  323.            
  324.             unsigned int offset0 = GET_LOW_BYTE_16(this->start_offset_ + this->current_offset_);
  325.             unsigned int offset1 = GET_HIGH_BYTE_16(this->start_offset_ + this->current_offset_);
  326.            
  327.             this->expected_ack_data_ = SWAP_BYTE_ORDER_16(this->start_offset_ + this->current_offset_);
  328.            
  329.             payload->SetVariable("Offset0", boost::lexical_cast<std::string>(offset0));
  330.             payload->SetVariable("Offset1", boost::lexical_cast<std::string>(offset1));
  331.            
  332.             for (int n = 0; (this->current_offset_ < this->code_->GetLength()) && (n < 6); n++)
  333.             {
  334.                 //LOG.Debug("Data" + boost::lexical_cast<std::string>(n) + "=" +  boost::lexical_cast<std::string>((unsigned int)this->code_->GetByte(this->code_->GetAddressLower() + this->current_offset_)));
  335.                 payload->SetVariable("Data" + boost::lexical_cast<std::string>(n), boost::lexical_cast<std::string>((unsigned int)this->code_->GetByte(this->code_->GetAddressLower() + this->current_offset_)));
  336.                 this->current_offset_++;
  337.             }
  338.            
  339.             broker::Manager::Instance()->Post(broker::Message::Pointer(new broker::Message(broker::Message::CAN_MESSAGE, broker::Message::PayloadPointer(payload), Manager::Instance().get())));
  340.         }
  341.     }
  342.     else if (target_state == STATE_BPGM_COPY)
  343.     {
  344.         LOG.Debug("Preparing to send null application to node " + this->id_);
  345.        
  346.         this->code_->Reset();
  347.        
  348.         this->code_->AddByte(0xFF);
  349.         this->code_->AddByte(0xFF);
  350.     }
  351.     else if (target_state == STATE_NORM_OFFLINE)
  352.     {
  353.         this->information_.valid_ = false;
  354.         this->SendReset();
  355.     }
  356.    
  357.    
  358.     if (this->state_ != target_state)
  359.     {
  360.         this->signal_on_new_state_(this->id_, this->state_, target_state);
  361.     }
  362.    
  363.     this->state_ = target_state;
  364. }
  365.  
  366. bool Node::CheckTimeout()
  367. {
  368.     if (this->state_ == STATE_NORM_OFFLINE)
  369.     {
  370.         return true;
  371.     }
  372.    
  373.     if (this->code_.use_count() == 0 && this->information_.last_active_ + 10 < time(NULL))
  374.     {
  375.         this->state_ = STATE_NORM_OFFLINE;
  376.         return false;
  377.     }
  378.    
  379.     return true;
  380. }
  381.  
  382. void Node::ResetTimeout()
  383. {
  384.     this->information_.last_active_ = time(NULL);
  385. }
  386.  
  387. void Node::Reset()
  388. {
  389.     common::StringMap variables;
  390.    
  391.     this->Trigger(EVENT_RESET, variables);
  392. }
  393.  
  394. void Node::ProgramApplication(Code::Pointer code)
  395. {
  396.     this->code_ = code;
  397.    
  398.     common::StringMap variables;
  399.    
  400.     this->Trigger(EVENT_PROGRAM_APP, variables);
  401. }
  402.  
  403. void Node::ProgramBios(Code::Pointer code)
  404. {
  405.     this->code_ = code;
  406.    
  407.     common::StringMap variables;
  408.    
  409.     this->Trigger(EVENT_PROGRAM_BIOS, variables);
  410. }
  411.  
  412. void Node::SendReset()
  413. {
  414.     LOG.Info("Sending node reset to " + this->id_);
  415.     can::Message* payload = new can::Message("nmt", "", "", 0, "Reset");
  416.     payload->SetVariable("HardwareId", boost::lexical_cast<std::string>(common::FromHex(this->id_)));
  417.    
  418.     broker::Manager::Instance()->Post(broker::Message::Pointer(new broker::Message(broker::Message::CAN_MESSAGE, broker::Message::PayloadPointer(payload), Manager::Instance().get())));
  419. }
  420.  
  421. void Node::SendListRequest()
  422. {
  423.     LOG.Debug("Sending module listing on node " + this->id_);
  424.     can::Message* payload = new can::Message("mnmt", "To_Owner", "", 0, "List");
  425.     payload->SetVariable("HardwareId", boost::lexical_cast<std::string>(common::FromHex(this->id_)));
  426.    
  427.     broker::Manager::Instance()->Post(broker::Message::Pointer(new broker::Message(broker::Message::CAN_MESSAGE, broker::Message::PayloadPointer(payload), Manager::Instance().get())));
  428. }
  429.  
  430. }; // namespace control
  431. }; // namespace atom
  432.