63242ea2bff1d5b832e7a045cbd9220406ee22c3
[fw/sdcc] / device / examples / ds390 / ow390 / owllu.c
1 #define DEBUG_OW_LLU 0
2 #if DEBUG_OW_LLU
3 #include <stdio.h>
4 #endif
5 //---------------------------------------------------------------------------
6 // Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved.
7 // 
8 // Permission is hereby granted, free of charge, to any person obtaining a 
9 // copy of this software and associated documentation files (the "Software"), 
10 // to deal in the Software without restriction, including without limitation 
11 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 
12 // and/or sell copies of the Software, and to permit persons to whom the 
13 // Software is furnished to do so, subject to the following conditions:
14 // 
15 // The above copyright notice and this permission notice shall be included 
16 // in all copies or substantial portions of the Software.
17 // 
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
19 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
20 // MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
21 // IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES 
22 // OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
23 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
24 // OTHER DEALINGS IN THE SOFTWARE.
25 // 
26 // Except as contained in this notice, the name of Dallas Semiconductor 
27 // shall not be used except as stated in the Dallas Semiconductor 
28 // Branding Policy. 
29 //---------------------------------------------------------------------------
30 //
31 //  owLLU.C - Link Layer 1-Wire Net functions using the DS2480/DS2480B (U)
32 //            serial interface chip.
33 //
34 //  Version: 2.00
35 //
36 //  History: 1.00 -> 1.01  DS2480 version number now ignored in 
37 //                         owTouchReset.
38 //           1.02 -> 1.03  Removed caps in #includes for Linux capatibility
39 //                         Removed #include <windows.h> 
40 //                         Add #include "ownet.h" to define TRUE,FALSE
41 //           1.03 -> 2.00  Changed 'MLan' to 'ow'. Added support for 
42 //                         multiple ports.  
43
44 #include "ownet.h"
45 #include "ds2480.h"
46
47 // local varable flag, true if program voltage available
48 static int ProgramAvailable[MAX_PORTNUM];
49
50 //--------------------------------------------------------------------------
51 // Reset all of the devices on the 1-Wire Net and return the result.
52 //
53 // 'portnum'    - number 0 to MAX_PORTNUM-1.  This number was provided to
54 //                OpenCOM to indicate the port number.
55 //
56 // Returns: TRUE(1):  presense pulse(s) detected, device(s) reset
57 //          FALSE(0): no presense pulses detected
58 //
59 // WARNING: This routine will not function correctly on some
60 //          Alarm reset types of the DS1994/DS1427/DS2404 with
61 //          Rev 1,2, and 3 of the DS2480/DS2480B.
62 //
63 int owTouchReset(int portnum)
64 {
65    uchar readbuffer[10],sendpacket[10];
66    int sendlen=0;
67
68 #if DEBUG_OW_LLU
69    printf ("owTouchReset\n");
70 #endif
71    // make sure normal level
72    owLevel(portnum,MODE_NORMAL);
73
74    // check if correct mode 
75    if (UMode[portnum] != MODSEL_COMMAND)
76    {
77       UMode[portnum] = MODSEL_COMMAND;
78       sendpacket[sendlen++] = MODE_COMMAND;
79    }
80
81    // construct the command
82    sendpacket[sendlen++] = (uchar)(CMD_COMM | FUNCTSEL_RESET | USpeed[portnum]);
83
84    // flush the buffers
85    FlushCOM(portnum);
86
87    // send the packet 
88    if (WriteCOM(portnum,sendlen,sendpacket)) 
89    {
90       // read back the 1 byte response 
91       if (ReadCOM(portnum,1,readbuffer) == 1)
92       {
93          // make sure this byte looks like a reset byte
94          if (((readbuffer[0] & RB_RESET_MASK) == RB_PRESENCE) ||
95              ((readbuffer[0] & RB_RESET_MASK) == RB_ALARMPRESENCE)) 
96          {
97             // check if programming voltage available
98             ProgramAvailable[portnum] = ((readbuffer[0] & 0x20) == 0x20); 
99             return TRUE;
100          }
101          else
102             return FALSE;
103       }
104    }
105
106    // an error occured so re-sync with DS2480
107    DS2480Detect(portnum);
108
109    return FALSE;
110 }
111
112 //--------------------------------------------------------------------------
113 // Send 1 bit of communication to the 1-Wire Net and return the
114 // result 1 bit read from the 1-Wire Net.  The parameter 'sendbit'
115 // least significant bit is used and the least significant bit
116 // of the result is the return bit.
117 //
118 // 'portnum' - number 0 to MAX_PORTNUM-1.  This number was provided to
119 //             OpenCOM to indicate the port number.
120 // 'sendbit' - the least significant bit is the bit to send
121 //
122 // Returns: 0:   0 bit read from sendbit
123 //          1:   1 bit read from sendbit
124 //
125 int owTouchBit(int portnum, int sendbit)
126 {
127    uchar readbuffer[10],sendpacket[10];
128    int sendlen=0;
129
130    // make sure normal level
131    owLevel(portnum,MODE_NORMAL);
132
133    // check if correct mode 
134    if (UMode[portnum] != MODSEL_COMMAND)
135    {
136       UMode[portnum] = MODSEL_COMMAND;
137       sendpacket[sendlen++] = MODE_COMMAND;
138    }
139
140    // construct the command
141    sendpacket[sendlen] = (sendbit != 0) ? BITPOL_ONE : BITPOL_ZERO;
142    sendpacket[sendlen++] |= CMD_COMM | FUNCTSEL_BIT | USpeed[portnum];
143
144    // flush the buffers
145    FlushCOM(portnum);
146
147    // send the packet 
148    if (WriteCOM(portnum,sendlen,sendpacket)) 
149    {
150       // read back the response 
151       if (ReadCOM(portnum,1,readbuffer) == 1)
152       {
153          // interpret the response 
154          if (((readbuffer[0] & 0xE0) == 0x80) &&
155              ((readbuffer[0] & RB_BIT_MASK) == RB_BIT_ONE))
156             return 1;
157          else
158             return 0;
159       }
160    }
161
162    // an error occured so re-sync with DS2480
163    DS2480Detect(portnum);
164
165    return 0;
166 }
167
168 //--------------------------------------------------------------------------
169 // Send 8 bits of communication to the 1-Wire Net and verify that the
170 // 8 bits read from the 1-Wire Net is the same (write operation).  
171 // The parameter 'sendbyte' least significant 8 bits are used.
172 //
173 // 'portnum'  - number 0 to MAX_PORTNUM-1.  This number was provided to
174 //              OpenCOM to indicate the port number.
175 // 'sendbyte' - 8 bits to send (least significant byte)
176 //
177 // Returns:  TRUE: bytes written and echo was the same
178 //           FALSE: echo was not the same 
179 //
180 int owWriteByte(int portnum, int sendbyte)
181 {
182    return (owTouchByte(portnum,sendbyte) == sendbyte) ? TRUE : FALSE;
183 }
184
185
186 //--------------------------------------------------------------------------
187 // Send 8 bits of read communication to the 1-Wire Net and and return the
188 // result 8 bits read from the 1-Wire Net.   
189 //
190 // 'portnum'  - number 0 to MAX_PORTNUM-1.  This number was provided to
191 //              OpenCOM to indicate the port number.
192 //
193 // Returns:  8 bytes read from 1-Wire Net
194 //
195 int owReadByte(int portnum)
196 {
197    return owTouchByte(portnum,0xFF);
198 }
199
200 //--------------------------------------------------------------------------
201 // Send 8 bits of communication to the 1-Wire Net and return the
202 // result 8 bits read from the 1-Wire Net.  The parameter 'sendbyte'
203 // least significant 8 bits are used and the least significant 8 bits
204 // of the result is the return byte.
205 //
206 // 'portnum'  - number 0 to MAX_PORTNUM-1.  This number was provided to
207 //              OpenCOM to indicate the port number.
208 // 'sendbyte' - 8 bits to send (least significant byte)
209 //
210 // Returns:  8 bytes read from sendbyte
211 //
212 int owTouchByte(int portnum, int sendbyte)
213 {
214    uchar readbuffer[10],sendpacket[10];
215    int sendlen=0;
216
217    // make sure normal level
218    owLevel(portnum,MODE_NORMAL);
219
220    // check if correct mode 
221    if (UMode[portnum] != MODSEL_DATA)
222    {
223       UMode[portnum] = MODSEL_DATA;
224       sendpacket[sendlen++] = MODE_DATA;
225    }
226
227    // add the byte to send
228    sendpacket[sendlen++] = (uchar)sendbyte;
229
230    // check for duplication of data that looks like COMMAND mode 
231    if (sendbyte == MODE_COMMAND) 
232       sendpacket[sendlen++] = (uchar)sendbyte;
233
234    // flush the buffers
235    FlushCOM(portnum);
236
237    // send the packet 
238    if (WriteCOM(portnum,sendlen,sendpacket)) 
239    {
240       // read back the 1 byte response 
241       if (ReadCOM(portnum,1,readbuffer) == 1)
242       {
243           // return the response 
244           return (int)readbuffer[0];
245       }
246    }
247
248    // an error occured so re-sync with DS2480
249    DS2480Detect(portnum);
250
251    return 0;
252 }
253
254 //--------------------------------------------------------------------------
255 // Set the 1-Wire Net communucation speed.  
256 //
257 // 'portnum'   - number 0 to MAX_PORTNUM-1.  This number was provided to
258 //               OpenCOM to indicate the port number.
259 // 'new_speed' - new speed defined as
260 //                MODE_NORMAL     0x00
261 //                MODE_OVERDRIVE  0x01
262 //
263 // Returns:  current 1-Wire Net speed 
264 //
265 int owSpeed(int portnum, int new_speed)
266 {
267    uchar sendpacket[5];
268    short sendlen=0;
269    int rt = FALSE;
270    
271 #if DEBUG_OW_LLU
272    printf ("starting owSpeed: %d\n", new_speed);
273 #endif
274    // check if change from current mode
275    if (((new_speed == MODE_OVERDRIVE) &&
276         (USpeed[portnum] != SPEEDSEL_OD)) ||
277        ((new_speed == MODE_NORMAL) &&
278         (USpeed[portnum] != SPEEDSEL_FLEX)))
279    {
280       if (new_speed == MODE_OVERDRIVE) 
281       {
282          // if overdrive then switch to 115200 baud
283          if (DS2480ChangeBaud(portnum,PARMSET_115200) == PARMSET_115200)
284          {
285             USpeed[portnum] = SPEEDSEL_OD;
286             rt = TRUE;
287          }
288       }
289       else if (new_speed == MODE_NORMAL) 
290       {
291          // else normal so set to 9600 baud
292          if (DS2480ChangeBaud(portnum,PARMSET_9600) == PARMSET_9600)
293          {
294             USpeed[portnum] = SPEEDSEL_FLEX;
295             rt = TRUE;
296          }
297       }
298
299       // if baud rate is set correctly then change DS2480 speed
300       if (rt)
301       {
302          // check if correct mode 
303          if (UMode[portnum] != MODSEL_COMMAND)
304          {
305             UMode[portnum] = MODSEL_COMMAND;
306             sendpacket[sendlen++] = MODE_COMMAND;
307          }
308
309          // proceed to set the DS2480 communication speed
310          sendpacket[sendlen++] = CMD_COMM | FUNCTSEL_SEARCHOFF | USpeed[portnum];
311
312          // send the packet 
313          if (!WriteCOM(portnum,sendlen,sendpacket)) 
314          {
315             rt = FALSE;
316             // lost communication with DS2480 then reset 
317             DS2480Detect(portnum);
318          }
319       }
320    }
321 #if DEBUG_OW_LLU
322    printf ("owSpeed: %d\n", rt);
323 #endif
324    // return the current speed
325    return (USpeed[portnum] == SPEEDSEL_OD) ? MODE_OVERDRIVE : MODE_NORMAL;
326 }
327
328 //--------------------------------------------------------------------------
329 // Set the 1-Wire Net line level.  The values for new_level are
330 // as follows:
331 //
332 // 'portnum'   - number 0 to MAX_PORTNUM-1.  This number was provided to
333 //               OpenCOM to indicate the port number.
334 // 'new_level' - new level defined as
335 //                MODE_NORMAL     0x00
336 //                MODE_STRONG5    0x02
337 //                MODE_PROGRAM    0x04
338 //                MODE_BREAK      0x08 (not supported)
339 //
340 // Returns:  current 1-Wire Net level  
341 //
342 int owLevel(int portnum, int new_level)
343 {
344    uchar sendpacket[10],readbuffer[10];
345    short sendlen=0;
346    short rt=FALSE;
347
348 #if DEBUG_OW_LLU
349    printf ("owLevel: %d\n", new_level);
350 #endif
351    // check if need to change level
352    if (new_level != ULevel[portnum])
353    {
354       // check if just putting back to normal
355       if (new_level == MODE_NORMAL)
356       {
357          // check if correct mode 
358          if (UMode[portnum] != MODSEL_COMMAND)
359          {
360             UMode[portnum] = MODSEL_COMMAND;
361             sendpacket[sendlen++] = MODE_COMMAND;
362          }
363
364          // stop pulse command
365          sendpacket[sendlen++] = MODE_STOP_PULSE;
366    
367          // flush the buffers
368          FlushCOM(portnum);
369
370          // send the packet 
371          if (WriteCOM(portnum,sendlen,sendpacket)) 
372          {
373             // read back the 1 byte response 
374             if (ReadCOM(portnum,1,readbuffer) == 1)
375             {
376                // check response byte
377                if ((readbuffer[0] & 0xE0) == 0xE0)
378                {
379                   rt = TRUE;
380                   ULevel[portnum] = MODE_NORMAL;
381                }
382             }
383          }
384       }
385       // set new level
386       else
387       {
388          // check if correct mode 
389          if (UMode[portnum] != MODSEL_COMMAND)
390          {
391             UMode[portnum] = MODSEL_COMMAND;
392             sendpacket[sendlen++] = MODE_COMMAND;
393          }
394
395          // strong 5 volts
396          if (new_level == MODE_STRONG5)
397          {
398             // set the SPUD time value 
399             sendpacket[sendlen++] = CMD_CONFIG | PARMSEL_5VPULSE | PARMSET_infinite;
400             // add the command to begin the pulse
401             sendpacket[sendlen++] = CMD_COMM | FUNCTSEL_CHMOD | SPEEDSEL_PULSE | BITPOL_5V;
402          }
403          // 12 volts
404          else if (new_level == MODE_PROGRAM)
405          {
406             // check if programming voltage available
407             if (!ProgramAvailable[portnum])
408                return MODE_NORMAL;
409
410             // set the PPD time value 
411             sendpacket[sendlen++] = CMD_CONFIG | PARMSEL_12VPULSE | PARMSET_infinite;
412             // add the command to begin the pulse
413             sendpacket[sendlen++] = CMD_COMM | FUNCTSEL_CHMOD | SPEEDSEL_PULSE | BITPOL_12V;
414          }
415
416          // flush the buffers
417          FlushCOM(portnum);
418
419          // send the packet 
420          if (WriteCOM(portnum,sendlen,sendpacket)) 
421          {
422             // read back the 1 byte response from setting time limit
423             if (ReadCOM(portnum,1,readbuffer) == 1)
424             {
425                // check response byte
426                if ((readbuffer[0] & 0x81) == 0)
427                {
428                   ULevel[portnum] = new_level;
429                   rt = TRUE;
430                }
431             }
432          }
433       }
434
435       // if lost communication with DS2480 then reset 
436       if (rt != TRUE)
437          DS2480Detect(portnum);
438    }
439
440    // return the current level
441    return ULevel[portnum];      
442 }
443
444 //--------------------------------------------------------------------------
445 // This procedure creates a fixed 480 microseconds 12 volt pulse 
446 // on the 1-Wire Net for programming EPROM iButtons.
447 //
448 // 'portnum'  - number 0 to MAX_PORTNUM-1.  This number was provided to
449 //              OpenCOM to indicate the port number.
450 //
451 // Returns:  TRUE  successful
452 //           FALSE program voltage not available  
453 //
454 int owProgramPulse(int portnum)
455 {
456    uchar sendpacket[10],readbuffer[10];
457    short sendlen=0;
458
459    // check if programming voltage available
460    if (!ProgramAvailable[portnum])
461       return FALSE;
462
463    // make sure normal level
464    owLevel(portnum,MODE_NORMAL);
465
466    // check if correct mode 
467    if (UMode[portnum] != MODSEL_COMMAND)
468    {
469       UMode[portnum] = MODSEL_COMMAND;
470       sendpacket[sendlen++] = MODE_COMMAND;
471    }
472
473    // set the SPUD time value 
474    sendpacket[sendlen++] = CMD_CONFIG | PARMSEL_12VPULSE | PARMSET_512us;
475
476    // pulse command
477    sendpacket[sendlen++] = CMD_COMM | FUNCTSEL_CHMOD | BITPOL_12V | SPEEDSEL_PULSE;
478    
479    // flush the buffers
480    FlushCOM(portnum);
481
482    // send the packet 
483    if (WriteCOM(portnum,sendlen,sendpacket)) 
484    {
485       // read back the 2 byte response 
486       if (ReadCOM(portnum,2,readbuffer) == 2)
487       {
488          // check response byte
489          if (((readbuffer[0] | CMD_CONFIG) == 
490                 (CMD_CONFIG | PARMSEL_12VPULSE | PARMSET_512us)) &&
491              ((readbuffer[1] & 0xFC) == 
492                 (0xFC & (CMD_COMM | FUNCTSEL_CHMOD | BITPOL_12V | SPEEDSEL_PULSE))))
493             return TRUE;
494       }
495    }
496
497    // an error occured so re-sync with DS2480
498    DS2480Detect(portnum);
499
500    return FALSE;
501 }