Subversion Repositories HomeAutomation

Rev

Rev 2004 | 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 "Code.h"
  22.  
  23. #include <fstream>
  24. #include <string>
  25. #include <streambuf>
  26. #include <stdexcept>
  27. #include <algorithm>
  28.  
  29. #include <boost/algorithm/string.hpp>
  30.  
  31. #include "common/common.h"
  32. #include "common/log.h"
  33.  
  34. namespace atom {
  35. namespace control {
  36.  
  37. #define MAX_BUFFER_SIZE  5200000
  38.  
  39. // Intel HEX record types
  40. #define INTELHEX_RT_DATA 0x00
  41. #define INTELHEX_RT_END  0x01
  42.  
  43. static const std::string log_module_ = "control::code";
  44.  
  45. Code::Code()
  46. {
  47.   LOG_DEBUG_ENTER;
  48.  
  49.   this->Reset(false);
  50.   //this->data_.insert(this->data_.begin(), 0xFF, MAX_BUFFER_SIZE);
  51.  
  52.   LOG_DEBUG_EXIT;
  53. }
  54.  
  55. Code::~Code()
  56. {
  57.   LOG_DEBUG_ENTER;
  58.   LOG_DEBUG_EXIT;
  59. }
  60.  
  61. void Code::Reset(bool fill)
  62. {
  63.   LOG_DEBUG_ENTER;
  64.  
  65.   this->address_lower_  = MAX_BUFFER_SIZE;
  66.   this->address_upper_  = 0;
  67.   this->is_valid_       = false;
  68.  
  69.   common::Byteset empty_vector;
  70.   this->data_.swap(empty_vector);
  71.  
  72.   if (fill)
  73.   {
  74.     this->data_.reserve(MAX_BUFFER_SIZE);
  75.     std::fill(this->data_.begin(), this->data_.begin() + MAX_BUFFER_SIZE, 0xFF);
  76.   }
  77.  
  78.   LOG_DEBUG_EXIT;
  79. }
  80.  
  81. void Code::CalculateChecksum()
  82. {
  83.   LOG_DEBUG_ENTER;
  84.  
  85.   this->checksum_ = 0;
  86.  
  87.   for (unsigned int n = this->address_lower_; n <= this->address_upper_; n++)
  88.   {
  89.     this->checksum_ ^= this->data_[n];
  90.  
  91.     for (unsigned int c = 0; c < 8; c++)
  92.     {
  93.       if ((this->checksum_ & 1) != 0)
  94.       {
  95.         this->checksum_ = (this->checksum_ >> 1) ^ 0xA001;
  96.       }
  97.       else
  98.       {
  99.         this->checksum_ = (this->checksum_ >> 1);
  100.       }
  101.     }
  102.   }
  103.  
  104.   this->checksum_ &= 0xFFFF;
  105.  
  106.   LOG_DEBUG_EXIT;
  107. }
  108.  
  109. void Code::AddByte(unsigned char byte)
  110. {
  111.   LOG_DEBUG_ENTER;
  112.  
  113.   this->data_.push_back(byte);
  114.  
  115.   this->address_lower_  = 0;
  116.   this->address_upper_  = this->data_.size();
  117.   this->is_valid_       = true;
  118.  
  119.   this->CalculateChecksum();
  120.  
  121.   LOG_DEBUG_EXIT;
  122. }
  123.  
  124. bool Code::LoadIntelHexFile(std::string filename)
  125. {
  126.   LOG_DEBUG_ENTER;
  127.  
  128.   std::ifstream file(filename.data());
  129.  
  130.   if (!file.is_open())
  131.   {
  132.     return false;
  133.   }
  134.  
  135.   std::string buffer((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
  136.  
  137.   file.close();
  138.  
  139.   bool result = this->ParseIntelHex(buffer);
  140.  
  141.   LOG_DEBUG_EXIT;
  142.  
  143.   return result;
  144. }
  145.  
  146. bool Code::ParseIntelHex(std::string data)
  147. {
  148.   LOG_DEBUG_ENTER;
  149.  
  150.   common::StringList lines;
  151.  
  152.   boost::algorithm::split(lines, data, boost::is_any_of("\n"), boost::algorithm::token_compress_on);
  153.  
  154.   this->Reset(true);
  155.  
  156.   unsigned int byte_count;
  157.   unsigned int addess;
  158.   unsigned int record_type;
  159.  
  160.   for (unsigned int n = 0; n < lines.size(); n++)
  161.   {
  162.     log::Debug(log_module_, "line[" + boost::lexical_cast<std::string> (n) + "]=" + lines[n]);
  163.    
  164.     if (lines[n].length() >= 11 && lines[n][0] == ':')
  165.     {
  166.       //log::Debug(log_module_, "A:" + lines[n].substr(1, 2));
  167.       byte_count = boost::lexical_cast<common::HexTo<unsigned int> >("0x" + lines[n].substr(1, 2)); //common::FromHex(lines[n].substr(1, 2));
  168.       log::Debug(log_module_, "byte_count=" + boost::lexical_cast<std::string>(byte_count));
  169.      
  170.       //log::Debug(log_module_, "B:" + lines[n].substr(3, 4));
  171.       addess = boost::lexical_cast<common::HexTo<unsigned int> >("0x" + lines[n].substr(3, 4)) & 0xFFFF; //common::FromHex(lines[n].substr(3, 4)) & 0xFFFF;
  172.       log::Debug(log_module_, "addess=" +  boost::lexical_cast<std::string> (addess));
  173.      
  174.       record_type = boost::lexical_cast<common::HexTo<unsigned int> >("0x" + lines[n].substr(7, 2)); //common::FromHex(lines[n].substr(7, 2));
  175.  
  176.       switch (record_type)
  177.       {
  178.         case INTELHEX_RT_DATA:
  179.         {
  180.           this->address_lower_ = std::min(this->address_lower_, addess);
  181.           this->address_upper_ = std::max(this->address_upper_, addess + byte_count - 1);
  182.  
  183.           for (unsigned int c = 0; c < byte_count; c++)
  184.           {
  185.             //log::Debug(log_module_, "D:" + lines[n].substr(c * 2 + 9, 2));
  186.             this->data_[addess + c] = boost::lexical_cast<common::HexTo<unsigned int> >("0x" + lines[n].substr(c * 2 + 9, 2));
  187.             //this->data[addess + c] = (unsigned char)common::FromHex(lines[n].substr(c * 2 + 9, 2));
  188.           }
  189.  
  190.           break;
  191.         }
  192.         case INTELHEX_RT_END:
  193.         {
  194.           this->is_valid_ = true;
  195.           break;
  196.         }
  197.       }
  198.     }
  199.   }
  200.  
  201.   if (this->is_valid_)
  202.   {
  203.     this->CalculateChecksum();
  204.  
  205.     log::Info(log_module_, "Successfully parsed Intel HEX file.");
  206.   }
  207.  
  208.   LOG_DEBUG_EXIT;
  209.  
  210.   return this->is_valid_;
  211. }
  212.  
  213. unsigned int Code::GetAddressLower()
  214. {
  215.   LOG_DEBUG_ENTER;
  216.   LOG_DEBUG_EXIT;
  217.  
  218.   return this->address_lower_;
  219. }
  220.  
  221. unsigned int Code::GetAddressUpper()
  222. {
  223.   LOG_DEBUG_ENTER;
  224.   LOG_DEBUG_EXIT;
  225.  
  226.   return this->address_upper_;
  227. }
  228.  
  229. unsigned char Code::GetByte(unsigned int address)
  230. {
  231.   LOG_DEBUG_ENTER;
  232.   LOG_DEBUG_EXIT;
  233.  
  234.   return this->data_[address];
  235. }
  236.  
  237. unsigned int Code::GetChecksum()
  238. {
  239.   LOG_DEBUG_ENTER;
  240.   LOG_DEBUG_EXIT;
  241.  
  242.   return this->checksum_;
  243. }
  244.  
  245. unsigned int Code::GetLength()
  246. {
  247.   LOG_DEBUG_ENTER;
  248.   LOG_DEBUG_EXIT;
  249.  
  250.   return this->address_upper_ - this->address_lower_ + 1;
  251. }
  252.  
  253. bool Code::IsValid()
  254. {
  255.   LOG_DEBUG_ENTER;
  256.   LOG_DEBUG_EXIT;
  257.  
  258.   return this->is_valid_;
  259. }
  260.  
  261. }; // namespace control
  262. }; // namespace atom
  263.