Subversion Repositories HomeAutomation

Rev

Rev 1987 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | SVN | RSS feed

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