66ea440243e172b2102c361dd0c3d83eecec5f68
[owTools.git] / src / owInterface.cpp
1 // Copyright (c) 2017, Tobias Mueller tm(at)tm3d.de
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //  * Redistributions of source code must retain the above copyright
9 //    notice, this list of conditions and the following disclaimer.
10 //  * Redistributions in binary form must reproduce the above copyright
11 //    notice, this list of conditions and the following disclaimer in the
12 //    documentation and/or other materials provided with the
13 //    distribution.
14 //  * All advertising materials mentioning features or use of this
15 //    software must display the following acknowledgement: This product
16 //    includes software developed by tm3d.de and its contributors.
17 //  * Neither the name of tm3d.de nor the names of its contributors may
18 //    be used to endorse or promote products derived from this software
19 //    without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
33
34 #include "owInterface.h"
35 #include <unistd.h>
36 #include <math.h>
37 #include "hexfile.h"
38
39 static short oddparity[16] = { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 };
40 static unsigned char owi_dscrc_table[] = {
41         0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65,
42       157,195, 33,127,252,162, 64, 30, 95,  1,227,189, 62, 96,130,220,
43        35,125,159,193, 66, 28,254,160,225,191, 93,  3,128,222, 60, 98,
44       190,224,  2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255,
45        70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89,  7,
46       219,133,103, 57,186,228,  6, 88, 25, 71,165,251,120, 38,196,154,
47       101, 59,217,135,  4, 90,184,230,167,249, 27, 69,198,152,122, 36,
48       248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91,  5,231,185,
49       140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205,
50        17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80,
51       175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238,
52        50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115,
53       202,148,118, 40,171,245, 23, 73,  8, 86,180,234,105, 55,213,139,
54        87,  9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22,
55       233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168,
56       116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53};
57
58       
59 uint8_t owInterface::docrc8(uint8_t value) {
60    // See Application Note 27
61    
62    // TEST BUILD
63    crc8 = owi_dscrc_table[crc8 ^ value];
64    return crc8;
65 }
66  
67 uint16_t owInterface::docrc16(uint16_t cdata) {
68    cdata = (cdata ^ (crc16 & 0xff)) & 0xff;
69    crc16 >>= 8;
70
71    if (oddparity[cdata & 0xf] ^ oddparity[cdata >> 4])
72      crc16 ^= 0xc001;
73
74    cdata <<= 6;
75    crc16   ^= cdata;
76    cdata <<= 1;
77    crc16   ^= cdata;
78
79    return crc16;
80                 
81         
82 }
83
84 uint8_t owInterface::calcCRC8(std::vector<uint8_t> data) {
85          crc8 = 0;
86           for(uint8_t v: data) 
87                         docrc8(v);
88         return crc8; //0 bei erfolg oder crc wenn crc nicht babei
89 }
90
91 uint16_t owInterface::calcCRC16(std::vector<uint8_t> data) {
92         crc16=0;
93         for(uint8_t v:data) {
94                 docrc16(v);
95         }
96         return crc16;
97 }
98
99 int owInterface::testCRC16(std::vector<uint8_t> data)  {
100         return calcCRC16(data)==0xB001;
101 }
102                 
103 void owInterface::resetFlasher() { // go back from Bootloader
104         std::vector<uint8_t> data;
105         data.push_back(0x89);
106         Wait_Free();
107         snum_t snum;
108         snum.num=0xfa55aa55aa55aaa3;
109         MatchRom(snum);
110         if (log->last()==OWLOG_ERROR) {Free(); return;}
111         Communicate(&data, 1, 0);
112         
113         Free();
114         if (log->last()==OWLOG_ERROR) return;
115         usleep(50);     
116 }
117
118 void owInterface::resetID() {
119         std::vector<uint8_t> data;
120         data.push_back(0x8B);
121         Wait_Free();
122         snum_t snum;
123         snum.num=0xfa55aa55aa55aaa3;
124         MatchRom(snum);
125         if (log->last()==OWLOG_ERROR) {Free(); return;}
126         Communicate(&data, 1, 0);
127         Free();
128 }
129
130 int owInterface::programmPage(int pagenr, std::vector<uint8_t> page, int pagesize) {
131         snum_t snum;
132         snum.num=0xfa55aa55aa55aaa3;
133 //      printf("programm page %i",pagenr);
134         
135         
136         int diff = pagesize - page.size();
137         if (diff>0) {
138                 for (int i = 0; i < (diff); i++) page.push_back(0xFF);
139         }
140         std::vector<uint8_t> cl;
141         std::vector<uint8_t> clb; //backup 
142         cl.push_back(0x0F);  //code for Flashing
143         cl.push_back((pagenr*pagesize) & 0xFF); //adress in byte
144         cl.push_back((pagenr*pagesize) >> 8);
145         cl.insert(cl.end(),page.begin(),page.end()); //page
146         clb=cl;         //make backup
147         Wait_Free();
148         MatchRom(snum); 
149         if (log->last()==OWLOG_ERROR) {Free();return -3;}
150         Communicate(&cl, 3+pagesize, 0); //send (resive page)
151         Free();
152         if (log->last()==OWLOG_ERROR) return -3;
153         int err=0;
154         for(int k=0;k<maxrepeat;k++) { //repeat for readback error 
155                 cl.clear();
156                 cl.push_back(0xAA); //code for readback scratchpad
157                 Wait_Free();
158                 MatchRom(snum);
159                 if (log->last()==OWLOG_ERROR) {Free();return -3;}
160                 Communicate(&cl, 1, 2+pagesize); // read back scratchpad
161                 Free();
162                 if (log->last()==OWLOG_ERROR) return -3;
163                 err=0;
164                 for (int i = 0; i < pagesize+2; i++) {
165                         if (clb[i + 1] != cl[i + 1]) {  //test
166                                 usleep(50000);
167                                 err=1;
168                                 break;
169                         }
170                 }
171                 if (err==0) break;
172         }
173         if (err==1) {
174                 usleep(50000);
175                 return -1;  //error in scratchpad
176         }
177         cl.clear();
178         cl.push_back(0x55);//Programm
179         Wait_Free();
180         MatchRom(snum);
181         if (log->last()==OWLOG_ERROR) {Free();return -3;}
182         Communicate(&cl, 1, 0);
183         Free();
184         if (log->last()==OWLOG_ERROR) return -3;
185         usleep(50000);
186         cl.clear();
187         cl.push_back(0xB8);//recal programm memory to scratchpad
188         cl.push_back((pagenr*pagesize) & 0xFF);
189         cl.push_back((pagenr*pagesize) >> 8);
190         Wait_Free();
191         MatchRom(snum);
192         if (log->last()==OWLOG_ERROR) {Free();return -3;}
193         Communicate(&cl, 3, 0); //Copy programm memory to scratch
194         Free();
195         if (log->last()==OWLOG_ERROR) return -3;
196         usleep(50000);
197         
198         for(int k=0;k<maxrepeat;k++) { //repead for reading scratch error
199                 cl.clear();
200                 cl.push_back(0xAA);
201                 Wait_Free();
202                 MatchRom(snum);
203                 if (log->last()==OWLOG_ERROR) {Free();return -3;}
204                 Communicate(&cl, 1, 2 + pagesize); //Reread scratch
205                 Free();
206                 if (log->last()==OWLOG_ERROR) return -3;
207                 err=0;
208                 for (int i = 0; i < pagesize + 2; i++) {
209                         if (cl[i + 1] != clb[i + 1]) {
210                                 usleep(50000);
211                                 err=1;
212                                 break;
213                         }
214                 }
215                 if (err==0) break;
216         }
217         if (err==1) {
218                 usleep(50000);
219                 return -2;
220         }
221
222
223         return 0;
224 }
225
226
227 int owInterface::flashHEXFile(std::string filename,snum_t dev,int resetid,int progress) {
228         log->set(OWLOG_INFO,"Open Hex-File: %s",filename.c_str());
229         hexFile *hf=new hexFile(filename);
230         if (hf->lastError==1) {log->set(OWLOG_ERROR,"CRC Error in HEX-File %s",filename.c_str());return -1;}
231         if (hf->lastError==2) {log->set(OWLOG_ERROR,"Error interpreting  HEX-File %s",filename.c_str());return -2;}
232         if (hf->lastError==3) {log->set(OWLOG_ERROR,"File could not be opened: %s",filename.c_str());return -3;}
233         unsigned int blcount=hf->getBlockCount(64);
234         if (blcount>118) {
235                 log->set(OWLOG_ERROR,"Code to big, max 7552 Byte allowed (118 Pages). Code has %i pages!",blcount);
236                 return -5;
237         }
238         log->set(OWLOG_INFO,"Try to start Bootloader on device %llX",dev.num);
239         int r=maxrepeat+1;
240         int found;
241         do {
242                 log->clear();
243                 std::vector<uint8_t> data;
244                 MatchRom(dev);
245                 data.push_back(0x88);
246                 Communicate(&data, 1, 0);
247                 MatchRom(dev);
248                 Communicate(&data, 1, 0);
249                 MatchRom(dev);
250                 Communicate(&data, 1, 0);
251                 sleep(3);
252                 log->set(OWLOG_INFO,"Search for Bootloader...");
253                 log->setLogLevel(OWLOG_WARNING);
254                 Find();
255                 log->setLogLevel(OWLOG_INFO);
256                 found=0;
257                 for (owDevice* dev :devices) {
258                         if (dev->getNum().num==0xfa55aa55aa55aaa3) {
259                                 found=1;
260                                 break;
261                         }       
262                 }
263                 if (found==0) log->set(OWLOG_WARNING,"Bootloader not found");
264                 r--;
265         }       while ((found==0)&&(r>0));
266         if (r==0) {
267                 log->set(OWLOG_ERROR,"Can not start Bootloader on this device %llX",dev.num);
268                 return -4;
269         }
270         log->set(OWLOG_INFO,"Start Programm %i Pages",blcount);
271         int rp=0;
272         int er=0;
273         unsigned int i =0;
274         for ( i= 0; i < blcount; i++) {
275                 std::vector<uint8_t> blk = hf->getBlock(i*64, 64);
276                 int errc = maxrepeat*5;
277                 while (errc != 0) {
278                         log->clear();
279                         if (programmPage(i, blk, 64) >= 0) {
280                                 if (progress) {printf("#");fflush(stdout);} 
281                                 break;
282                         }
283                         
284                         errc -= 1;
285                         rp++;
286                         if (progress) {printf("\033[1;31m#\033[0m");fflush(stdout);} //printf("\033[1;33m%s\033[0m\n",s);
287                                         
288                 }
289       if (errc == 0) { er++; break; }
290         }
291         if (progress) printf("\n");
292         if (er != 0) {
293                 log->set(OWLOG_ERROR,"ERROR Writing Program Memory!!!");
294                 if (i==0) {
295                         log->set(OWLOG_ERROR,"If Fuse SELFPRGEN enabled?");
296                 } else
297                         log->set(OWLOG_ERROR,"Maybe 1-Wire Connection is verry bad!");
298         } else {
299                 if (resetid) {
300                         log->set(OWLOG_INFO,"Set 1-Wire ID to ID in hexfile...",blcount); 
301                         resetID();
302                         sleep(3);
303                         resetID();      
304                         sleep(3);
305                 }
306         }       
307         
308         log->set(OWLOG_INFO,"Back from bootloader to normal device...",blcount); 
309         
310         
311         resetFlasher();
312         sleep(1);       
313         resetFlasher();
314         sleep(3);       
315
316         Find();
317         
318         return 1;
319                 
320 }
321
322
323 int owInterface::owSearch() {
324         int id_bit_number;
325         int last_zero, rom_byte_number, search_result;
326         int id_bit, cmp_id_bit;
327         unsigned char rom_byte_mask, search_direction;
328
329         // initialize for search
330         id_bit_number = 1;
331         last_zero = 0;
332         rom_byte_number = 0;
333         rom_byte_mask = 1;
334         search_result = 0;
335         crc8 = 0;
336
337         // if the last call was not the last one
338         if (!LastDeviceFlag) {
339                 // 1-Wire reset
340                 Wait_Free();
341                 if (!Reset()) {
342         // reset the search
343                         LastDiscrepancy = 0;
344                         LastDeviceFlag = FALSE;
345                         LastFamilyDiscrepancy = 0;
346                         Free();
347                         return FALSE;
348                 }
349                 if (log->last()==OWLOG_ERROR) return -3;
350                 // issue the search command 
351                 sendrecivByte(0xF0);  
352                 if (log->last()==OWLOG_ERROR) return -3;
353
354                 // loop to do the search
355                 do {
356                         // read a bit and its complement
357                         id_bit = sendrecivBit(1);
358                         cmp_id_bit = sendrecivBit(1);
359                         // check for no devices on 1-wire
360                         if ((id_bit == 1) && (cmp_id_bit == 1))
361                                 break;
362                         else {
363                                 // all devices coupled have 0 or 1
364                                 if (id_bit != cmp_id_bit)
365                                         search_direction = id_bit;  // bit write value for search
366                                 else  {
367                                         // if this discrepancy if before the Last Discrepancy
368                                         // on a previous next then pick the same as last time
369                                         if (id_bit_number < LastDiscrepancy)
370                                                 search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0);
371                                         else
372                                                 // if equal to last pick 1, if not then pick 0
373                                                 search_direction = (id_bit_number == LastDiscrepancy);
374
375                                         // if 0 was picked then record its position in LastZero
376                                         if (search_direction == 0) {
377                                                 last_zero = id_bit_number;
378                                                 // check for Last discrepancy in family
379                                                 if (last_zero < 9)
380                                                         LastFamilyDiscrepancy = last_zero;
381                                         }
382                                 }
383                                 // set or clear the bit in the ROM byte rom_byte_number
384                                 // with mask rom_byte_mask
385                                 if (search_direction == 1)
386                                         ROM_NO[rom_byte_number] |= rom_byte_mask;
387                                 else
388                                         ROM_NO[rom_byte_number] &= ~rom_byte_mask;
389                                 // serial number search direction write bit
390                                 sendrecivBit(search_direction);
391                                 //usleep(50);
392
393                                 // increment the byte counter id_bit_number
394                                 // and shift the mask rom_byte_mask
395                                 id_bit_number++;
396                                 rom_byte_mask <<= 1;
397
398                                 // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
399                                 if (rom_byte_mask == 0) {
400                                         docrc8(ROM_NO[rom_byte_number]);  // accumulate the CRC
401                                         rom_byte_number++;
402                                         rom_byte_mask = 1;
403                                 }
404                         }
405                 }
406                 while(rom_byte_number < 8);  // loop until through all ROM bytes 0-7
407                 // if the search was successful then
408                 if (!((id_bit_number < 65) || (crc8 != 0))) {
409                         // search successful so set LastDiscrepancy,LastDeviceFlag,search_result
410                         LastDiscrepancy = last_zero;
411                         // check for last device
412                         if (LastDiscrepancy == 0)
413                         LastDeviceFlag = TRUE;
414                         search_result = TRUE;
415                 } else {
416                         log->set(OWLOG_WARNING,"CRC Error on Search Rom");
417                 }
418         }
419
420                 // if no device found then reset counters so next 'search' will be like a first
421         if (!search_result || !ROM_NO[0]) {
422                 LastDiscrepancy = 0;
423                 LastDeviceFlag = FALSE;
424                 LastFamilyDiscrepancy = 0;
425                 search_result = FALSE;
426         }
427         Free();
428         return search_result;
429         
430
431 }
432 void owInterface::Clean() {
433         for (owDevice* dev :devices) {
434                 delete dev;
435         }
436         devices.clear();
437         device_nums.clear();
438         devices_changed=1;
439 }
440
441 int owInterface::Find() {
442         int rslt,i,cnt=0;
443         std::vector<snum_t> found;
444         for (int k=0;k<maxrepeat;k++) {
445                 cnt=0;
446                 log->clear();
447                 found.clear();
448                 rslt = owFirst();
449                 if (log->last()>=OWLOG_WARNING) continue;
450                 while (rslt){
451                         snum_t snum;
452                         // print device found
453                         for (i = 7; i >= 0; i--)
454                                 snum.byte[i]=ROM_NO[i];
455                                 //printf("%02X", ROM_NO[i]);
456                                 //printf("  %d\n",++cnt);
457                         found.push_back(snum);
458                         cnt++;
459                         log->clear();
460                         rslt = owNext();
461                         if (log->last()>=OWLOG_WARNING) {rslt=-1;break;}
462                 }
463                 if (rslt==0) break;
464         
465         }
466         if (log->last()>=OWLOG_WARNING) { 
467                 log->set(OWLOG_ERROR,"To much Errors while search rom"); 
468                 //Alles so lassen wie es ist?           
469                 return 0;
470         }
471         for(snum_t snum:found) {
472                 int snum_found=0;
473                 //Device schon forhanden?
474                 for(snum_t d : device_nums) {
475                         if (snum.num==d.num) {snum_found=1;break;}
476                 }
477                 //nein, dann anlegen.
478                 if (!snum_found) {
479                         log->set(OWLOG_INFO,"new dev %llx\n",snum.num);
480                         devices_changed=1;
481                         device_nums.push_back(snum);
482                         owDevice *d=NULL;
483                         
484                         switch (snum.byte[0]) {
485                                 case 0x28:d=new owDeviceDS18B20(this,snum);break;
486                                 case 0x26:d=new owDeviceDS2438(this,snum);break;
487                                 case 0x20:d=new owDeviceDS2450(this,snum);break;
488                                 case 0x1D:d=new owDeviceDS2423(this,snum);break;
489                                 default:d=new owDevice(this,snum);
490                         }
491                         devices.push_back(d);
492                         if (d!=NULL)    {d->readConfig();}
493                 }
494         }
495         //Pruefe nach nicht mehr vorhandenen devices
496         int dpos=0;
497         for(snum_t d:device_nums) {
498                 int snum_found=0;
499                 for(snum_t fd:found) {
500                         if (fd.num==d.num) {snum_found=1;break;}
501                 }
502                 //Device nicht gefunden, vieleicht nur Fehler?
503                 if (!snum_found) {
504                         devices[dpos]->lastfound++;
505                         log->set(OWLOG_INFO,"%llx not found %i times \n",device_nums[dpos].num,devices[dpos]->lastfound); 
506                         
507                         if (devices[dpos]->lastfound>2) {
508
509                                 log->set(OWLOG_INFO,"del device %llx (pos %i)\n",device_nums[dpos].num,dpos);
510                         
511                                 devices_changed=1;
512                                 delete devices[dpos];
513                                 device_nums.erase(device_nums.begin()+dpos);
514                                 devices.erase(devices.begin()+dpos);    
515                         //printf("new length %i\n",devices.size());
516                                 dpos--;
517                         } 
518
519                 } else {
520                         devices[dpos]->lastfound=0;
521                 }
522                 dpos++;
523                 
524         }       
525         return cnt;     
526 }
527
528 int owInterface::MatchRom(snum_t snum) {
529         Reset();
530         sendrecivByte(0x55);
531         usleep(20);
532         for(int i=0;i<8;i++) {
533                 sendrecivByte(snum.byte[i]); 
534                 usleep(20);
535         }
536         if (log->last()>OWLOG_WARNING) return 0;
537         return 1;
538 }
539 int owInterface::Communicate(std::vector<uint8_t> *data, int scount, int rcount) {
540         int i=0;
541         data->resize(scount);
542         for(uint8_t v:*data) {
543                 (*data)[i]=sendrecivByte(v);i++;
544                 usleep(20);
545         }
546         for(i=0;i<rcount;i++) {
547                 data->push_back(sendrecivByte(0xFF));
548                 usleep(20);
549                 
550         }
551         return 0;
552 }
553