1 /*  Copyright (C) 2012 Eduard Timotei Budulea
2     Copyright (C) 2013 Roy R. Rankin
3 
4     This program is free software: you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation, either version 3 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 #include "config.h"
18 #include "rom1w.h"
19 
20 
21 class ROMCodeAttribute : public Integer {
22 
23 public:
24 
ROMCodeAttribute()25   ROMCodeAttribute()
26     : Integer("ROMCode",0x06050403020110LL,"Device ROM code")
27   {
28 	// Add CRC
29 	gint64 v = getVal();
30 	set(v);
31   }
32 
33 
set(gint64 i)34   void set(gint64 i)
35   {
36     gint64 id = (i & 0xffffffffffff00LL) | 0x10;
37     gint64 crc;
38     crc = Rom1W::calculateCRC8((const unsigned char *)&id, 7);
39     id |= crc << 56;
40     Integer::set(id);
41   }
42 
get(char * buffer,int buf_size)43  virtual void get(char *buffer, int buf_size)
44  {
45      if(buffer)
46      {
47 	 gint64 i;
48 	 i = getVal();;
49          snprintf(buffer,buf_size,"0x%" PRINTF_GINT64_MODIFIER "x",i);
50   }
51 
52 }
53 
54 
toString()55  virtual string toString()
56   {
57     return Integer::toString("0x%" PRINTF_INT64_MODIFIER "x");
58   }
59 
60 };
gotReset()61 void Rom1W::gotReset() {
62 
63     if(verbose) cout << name() << " got rom reset" << endl;
64     romState = &Rom1W::readRomCommand;
65     bitRemaining = 8;
66     isReading = true;
67 }
68 
getBit(int bitIndex,unsigned char * buffer)69 static bool getBit(int bitIndex, unsigned char * buffer) {
70     return 0 != (buffer[bitIndex / 8] & (1 << (7 - bitIndex % 8)));
71 }
72 
gotBitStart()73 Rom1W::NextAction Rom1W::gotBitStart() {
74     if(verbose)cout << name() << " gotBitStart" << endl;
75     if (--bitRemaining < 0) return (this->*romState)();
76     if (isReading) return READ;
77     bool write1 = getBit(bitRemaining, octetBuffer);
78     if(verbose)
79         cout << name() << " writing bit = " << write1 << " remaining " << bitRemaining <<endl;
80     return write1 ? WRITE1 : WRITE0;
81 }
82 
readBit(bool value)83 void Rom1W::readBit(bool value) {
84     if(verbose)
85       cout << name() << " " << __FUNCTION__ << " got readbit = " << value << endl;
86     if (value)
87         octetBuffer[bitRemaining / 8] |= 1 << (7 - bitRemaining % 8);
88     else
89         octetBuffer[bitRemaining / 8] &= ~(1 << (7 - bitRemaining % 8));
90 
91     if (verbose && (bitRemaining % 8) == 0)
92     {
93 	printf("%s read byte %0x index %d\n", name().c_str(), octetBuffer[bitRemaining / 8], (bitRemaining / 8));
94     }
95 }
96 
int64ToBuff(long long unsigned int num,unsigned char * buff)97 static void int64ToBuff(long long unsigned int num, unsigned char * buff) {
98     for (int i = 0; i < 8; ++i)
99         buff[i] = num >> ((7 - i) * 8);
100 }
101 
readRomCommand()102 Rom1W::NextAction Rom1W::readRomCommand() {
103     if(verbose)
104        cout << name() << " "<<__FUNCTION__ << " got " << hex << (int)octetBuffer[0] << endl;
105     gint64 intaddr;
106     switch (octetBuffer[0]) {
107     case 0x33:	// Skip ROM
108         isSelected = false;
109         romState = &Rom1W::readRom;
110 	intaddr = attr_ROMCode->getVal();
111         int64ToBuff(intaddr, octetBuffer);
112         bitRemaining = 64;
113         isReading = false;
114         return IDLE;
115 
116     case 0x55:	// Match ROM
117         isSelected = false;
118         romState = &Rom1W::matchRom;
119         bitRemaining = 64;
120         isReading = true;
121         return READ;
122 
123     case 0xEC:	// Alarm Search
124 	// Fall through to Search ROM
125 
126     case 0xF0:	// Search ROM
127         isSelected = (octetBuffer[0]==0xF0 || isAlarm())?true:false;
128         romState = &Rom1W::searchRom;
129 	intaddr = attr_ROMCode->getVal();
130         int64ToBuff(intaddr, octetBuffer + 1);
131         if (octetBuffer[8] & 1)
132             octetBuffer[0] = 0x40;
133         else
134             octetBuffer[0] = 0x80;
135         octetBuffer[9] = 63;
136         bitRemaining = 2;
137         isReading = false;
138         return IDLE;
139 
140     case 0xCC:	// Skip ROM
141         isSelected = false;
142 	if(verbose)
143 	    cout << name() << " Skip rom function command\n";
144         break;
145 
146     case 0xA5:
147         if (isSelected) break;
148     default:
149         return RESET;
150     }
151     return readRom();
152 }
153 
readRom()154 Rom1W::NextAction Rom1W::readRom() {
155     if(verbose) cout << name() << " called " << __FUNCTION__ << endl;
156     resetEngine();
157     romState = &Rom1W::deviceData;
158     return IDLE;
159 }
160 
matchRom()161 Rom1W::NextAction Rom1W::matchRom() {
162     if(verbose) cout << name() << " called " << __FUNCTION__ << endl;
163     unsigned char myaddr[8];
164     gint64 intaddr;
165     intaddr = attr_ROMCode->getVal();
166     int64ToBuff(intaddr, myaddr);
167     if (memcmp(myaddr, octetBuffer, 8))
168     {
169 	if(verbose)
170         {
171          cout << name() << " " << hex << intaddr << " no match\n got ";
172 	 for(int i=0; i < 8; i++)
173 		printf("%x", octetBuffer[i]);
174 	 cout <<endl;
175 	}
176 	return ignoreData();
177     }
178     if(verbose) cout << name() << " " << hex << intaddr << " match\n";
179     isSelected = true;
180     return readRom();
181 }
182 
searchRom()183 Rom1W::NextAction Rom1W::searchRom() {
184     if(verbose)
185         cout << name() << " called " << __FUNCTION__ << " isReading " << isReading <<endl;
186     if (isReading) {
187         bool myBit = getBit(octetBuffer[9], octetBuffer + 1);
188         if (myBit != (0 != (0x80 & octetBuffer[0])))
189 	{
190 	     isSelected = false;
191 	}
192         if (!octetBuffer[9]) 	// read all bits
193 	{
194 	    if(isSelected)
195 	    {
196 		if(verbose)
197 		    printf("%s searchRom selected\n", name().c_str());
198                 return RESET;
199 	    }
200 	    else
201 	    {
202 		if (verbose)
203 		    printf("%s searchRom not selected\n", name().c_str());
204 		return RESET;
205 	    }
206         }
207         if (getBit(--octetBuffer[9], octetBuffer + 1))
208             octetBuffer[0] = 0x40;
209         else
210             octetBuffer[0] = 0x80;
211 	if (!isSelected)
212 	    octetBuffer[0] = 0xC0;	// do not pull down the bus
213         bitRemaining = 2;
214         isReading = false;
215         return IDLE;
216     }
217     isReading = true;
218     bitRemaining = 1;
219     return IDLE;
220 }
221 
deviceData()222 Rom1W::NextAction Rom1W::deviceData() {
223     if(verbose)
224         cout << name() << " called " << __FUNCTION__ << endl;
225     doneBits();
226     return RESET;
227 }
228 //
229 // Just read data until a reset pulse happens
ignoreData()230 Rom1W::NextAction Rom1W::ignoreData() {
231     if (verbose)
232         cout << name() << " called " << __FUNCTION__ << endl;
233     romState = &Rom1W::ignoreData;
234     bitRemaining = 64;
235     isReading = true;
236     return READ;
237 }
238 //
239 // Allow reading of device status
240 //
statusPoll()241 Rom1W::NextAction Rom1W::statusPoll() {
242     if(verbose)
243         cout << name() << " called " << __FUNCTION__ << endl;
244     bitRemaining = 8;
245     octetBuffer[0] = isReady?0xff:0x00;
246     isReading = false;
247     return IDLE;
248 }
249 
250 // This is called to setup polling of device status.
251 // delay is the cycle counter after which the poll will return 1's
set_status_poll(guint64 delay)252 void Rom1W::set_status_poll(guint64 delay)
253 {
254     isReady = false;
255     bitRemaining = 8;
256     isReading = false;
257     octetBuffer[0] = 0x00;
258     romState = &Rom1W::statusPoll;
259     if (delay > get_cycles().get())
260     {
261 	if (poll_break)
262 	    get_cycles().clear_break(poll_break);
263 	get_cycles().set_break(delay, this);
264 	if(verbose)
265 	    printf("%s to poll busy for %.3f mS\n",
266 	       name().c_str(), (delay - get_cycles().get())*4./(20. * 1000.));
267         poll_break = delay;
268     }
269 }
270 
271 // Rom1W::callback catches breaks from both Bit1W and Rom1W
272 // and uses last break setting (bit_break-Bit1W and poll_break-Rom1W)
273 // to determine what action to take
callback()274 void Rom1W::callback()
275 {
276     guint64 now = get_cycles().get();
277     if (now == poll_break)
278     {
279         isReady = true;
280         octetBuffer[0] = 0xff;
281         poll_break = 0;
282     }
283     if(now == bit_break)
284 	LowLevel1W::callback();
285 }
286 
Rom1W(const char * _name,const char * desc)287 Rom1W::Rom1W(const char *_name, const char *desc):
288     LowLevel1W(_name, desc), isSelected(false), bitRemaining(0),
289     isReading(false), romState(&Rom1W::deviceData)
290 {
291     poll_break = 0;
292 	attr_ROMCode = new ROMCodeAttribute();
293 	addSymbol(attr_ROMCode);
294 }
295 
~Rom1W()296 Rom1W::~Rom1W() {
297 	removeSymbol(attr_ROMCode);
298 	delete attr_ROMCode;
299 }
300 
301 static const guint8 crc8Table[256] = {0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,
302     157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,
303     35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98,
304     190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,
305     70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7,
306     219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154,
307     101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,
308     248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185,
309     140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205,
310     17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80,
311     175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238,
312     50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115,
313     202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139,
314     87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,
315     233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168,
316     116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53};
317 
calculateCRC8(const unsigned char * buffer,int bufferLen)318 guint8 Rom1W::calculateCRC8(const unsigned char *buffer, int bufferLen) {
319     guint8 crc = 0;
320     for (int i = 0; i < bufferLen; ++i)
321         crc = crc8Table[crc ^ buffer[i]];
322     return crc;
323 }
324