1 //
2 // srecord - Manipulate EPROM load files
3 // Copyright (C) 2011 Peter Miller
4 //
5 // This program is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU Lesser General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or (at
8 // 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 GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 //
18 
19 #include <cstring>
20 
21 #include <srecord/output/file/ppb.h>
22 #include <srecord/record.h>
23 
24 
~output_file_ppb()25 srecord::output_file_ppb::~output_file_ppb()
26 {
27     if (!seen_some_data)
28         fatal_error("no data records");
29     if (buffer_length > 0)
30         buffer_flush();
31     packet(0, 0, 0);
32 }
33 
34 
output_file_ppb(const std::string & a_file_name)35 srecord::output_file_ppb::output_file_ppb(
36     const std::string &a_file_name
37 ) :
38     srecord::output_file(a_file_name),
39     address(-1uL),
40     buffer_length(0),
41     seen_some_data(false)
42 {
43 }
44 
45 
46 srecord::output::pointer
create(const std::string & a_file_name)47 srecord::output_file_ppb::create(const std::string &a_file_name)
48 {
49     return pointer(new srecord::output_file_ppb(a_file_name));
50 }
51 
52 
53 void
write(const srecord::record & record)54 srecord::output_file_ppb::write(const srecord::record &record)
55 {
56     switch (record.get_type())
57     {
58     default:
59         // ignore
60         break;
61 
62     case srecord::record::type_header:
63         // ignore
64         break;
65 
66     case srecord::record::type_data:
67         for (size_t j = 0; j < record.get_length(); ++j)
68         {
69             unsigned char data = record.get_data(j);
70             unsigned long data_address = record.get_address() + j;
71 
72             if (data_address != address)
73             {
74                 buffer_flush();
75                 address = data_address;
76             }
77             buffer[buffer_length++] = data;
78             ++address;
79             if (buffer_length >= sizeof(buffer))
80                 buffer_flush();
81             seen_some_data = true;
82         }
83         break;
84 
85     case srecord::record::type_execution_start_address:
86         // ignore
87         break;
88     }
89 }
90 
91 
92 void
line_length_set(int)93 srecord::output_file_ppb::line_length_set(int)
94 {
95     // Ignore.
96 }
97 
98 
99 bool
preferred_block_size_set(int nbytes)100 srecord::output_file_ppb::preferred_block_size_set(int nbytes)
101 {
102     return (nbytes >= 2 && nbytes <= record::max_data_length);
103 }
104 
105 
106 void
address_length_set(int)107 srecord::output_file_ppb::address_length_set(int)
108 {
109     // Ignore
110 }
111 
112 
113 int
preferred_block_size_get(void) const114 srecord::output_file_ppb::preferred_block_size_get(void)
115     const
116 {
117     // Use the largest we can get.
118     return srecord::record::max_data_length;
119 }
120 
121 
122 const char *
format_name(void) const123 srecord::output_file_ppb::format_name(void)
124     const
125 {
126     return "Stag Prom Programmer Binary";
127 }
128 
129 
130 void
put_bin_4be(unsigned long value)131 srecord::output_file_ppb::put_bin_4be(unsigned long value)
132 {
133     put_char(value >> 24);
134     put_char(value >> 16);
135     put_char(value >> 8);
136     put_char(value);
137 }
138 
139 
140 void
packet(unsigned long address,const unsigned char * data,size_t data_size)141 srecord::output_file_ppb::packet(unsigned long address,
142     const unsigned char *data, size_t data_size)
143 {
144     enum { SOH = 1 };
145     enum { CSLEN = 1024 };
146 
147     put_char(SOH);
148     put_bin_4be(data_size);
149     put_bin_4be(address);
150     unsigned char chksum = 0;
151     for (size_t j = 0; j < data_size; ++j)
152     {
153         if (j > 0 && (j % CSLEN) == 0)
154             put_char(-chksum);
155         put_char(data[j]);
156         chksum += data[j];
157     }
158     put_char(-chksum);
159 }
160 
161 
162 void
buffer_flush(void)163 srecord::output_file_ppb::buffer_flush(void)
164 {
165     if (buffer_length > 0)
166     {
167         packet(address - buffer_length, buffer, buffer_length);
168         buffer_length = 0;
169     }
170 }
171 
172 
173 bool
is_binary(void) const174 srecord::output_file_ppb::is_binary(void)
175     const
176 {
177     return true;
178 }
179 
180 
181 // vim: set ts=8 sw=4 et :
182