Imported Upstream version 2.9.0
[debian/cc1111] / device / examples / ds390 / ow390 / owlli.c
1 //---------------------------------------------------------------------------
2 // Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved.
3 // 
4 // Permission is hereby granted, free of charge, to any person obtaining a 
5 // copy of this software and associated documentation files (the "Software"), 
6 // to deal in the Software without restriction, including without limitation 
7 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 
8 // and/or sell copies of the Software, and to permit persons to whom the 
9 // Software is furnished to do so, subject to the following conditions:
10 // 
11 // The above copyright notice and this permission notice shall be included 
12 // in all copies or substantial portions of the Software.
13 // 
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
16 // MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
17 // IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES 
18 // OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
19 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
20 // OTHER DEALINGS IN THE SOFTWARE.
21 // 
22 // Except as contained in this notice, the name of Dallas Semiconductor 
23 // shall not be used except as stated in the Dallas Semiconductor 
24 // Branding Policy. 
25 //---------------------------------------------------------------------------
26 //
27 // iow.c
28 //
29 // Minimal access routines for TINI internal one-wire bus patched together
30 // from Dallas example code (hence the copyright notice above).
31 //
32 // Kevin Vigor, 11/20/2000
33  
34 #include <stdio.h>
35 #include "ownet.h"
36
37 /* The internal 1-wire bus is hooked to P3.5, a.k.a T1 */
38 /* The "activity" LED is also hooked to this line.     */
39 #define INT_OW_PORT T1
40
41 // local variables for this module to hold search state information
42 static int LastDiscrepancy;
43 static int LastFamilyDiscrepancy;
44 static int LastDevice;
45 static unsigned char iSerialNum[8];
46
47 static uchar iowTouchBit(uchar);
48 static uchar iowTouchByte(uchar);
49
50 //--------------------------------------------------------------------------
51 // Reset all of the devices on the 1-Wire Net and return the result.
52 //
53 // Returns: TRUE(1):  presense pulse(s) detected, device(s) reset
54 //          FALSE(0): no presense pulses detected
55 //
56 unsigned char iowTouchReset(void)
57 {
58    unsigned char result;
59    
60    //printf ("iowTouchReset(): ");
61
62    /* Code stolen straight from appnote 126. */
63    INT_OW_PORT = 0;     /* drive bus low. */
64    ClockMicroSecondsDelay(480);
65    INT_OW_PORT = 1;     /* bus high. */
66    ClockMicroSecondsDelay(120);
67    result = INT_OW_PORT; /* get presence detect pulse. */
68    ClockMicroSecondsDelay(360);
69
70    //printf ("%d\n", result);
71    return result;
72 }
73
74 //--------------------------------------------------------------------------
75 // Send 1 bit of communication to the 1-Wire Net and return the
76 // result 1 bit read from the 1-Wire Net.  The parameter 'sendbit'
77 // least significant bit is used and the least significant bit
78 // of the result is the return bit.
79 //
80 // Returns: 0:   0 bit read from sendbit
81 //          1:   1 bit read from sendbit
82 //
83 static unsigned char iowTouchBit(unsigned char sendbit)
84 {
85    unsigned char result;
86    
87    INT_OW_PORT = 0;             /* start timeslot. */
88    ClockMicroSecondsDelay(1);
89
90    INT_OW_PORT = sendbit;       /* send bit out. */ 
91    ClockMicroSecondsDelay(9);
92    result = INT_OW_PORT;                /* sample result @ 10 us. */
93    ClockMicroSecondsDelay(50);
94    INT_OW_PORT = 1;             /* timeslot done. */
95    ClockMicroSecondsDelay(5);
96
97    return result;
98 }
99
100 //--------------------------------------------------------------------------
101 // Send 8 bits of communication to the 1-Wire Net and return the
102 // result 8 bits read from the 1-Wire Net.  The parameter 'sendbyte'
103 // least significant 8 bits are used and the least significant 8 bits
104 // of the result is the return byte.
105 //
106 // 'sendbyte'   - 8 bits to send (least significant byte)
107 //
108 // Returns:  8 bytes read from sendbyte
109 //
110 static unsigned char iowTouchByte(unsigned char sendbyte)
111 {
112    unsigned char i;
113    unsigned char result = 0;
114    
115    //printf ("iowTouchByte(%02x): ", sendbyte);
116
117    for (i = 0; i < 8; i++)
118    {
119        result |= (iowTouchBit(sendbyte & 1) << i);
120        sendbyte >>= 1;
121    }
122     
123    //printf ("%02x\n", result);
124    return result;
125 }
126
127 //--------------------------------------------------------------------------
128 // Send 8 bits of communication to the 1-Wire Net and verify that the
129 // 8 bits read from the 1-Wire Net is the same (write operation).  
130 // The parameter 'sendbyte' least significant 8 bits are used.
131 //
132 // 'sendbyte'   - 8 bits to send (least significant byte)
133 //
134 // Returns:  TRUE: bytes written and echo was the same
135 //           FALSE: echo was not the same 
136 //
137 unsigned char iowWriteByte(unsigned char sendbyte)
138 {
139    return (iowTouchByte(sendbyte) == sendbyte) ? TRUE : FALSE;
140 }
141
142 //--------------------------------------------------------------------------
143 // The 'owBlock' transfers a block of data to and from the 
144 // 1-Wire Net with an optional reset at the begining of communication.
145 // The result is returned in the same buffer.
146 //
147 // 'do_reset' - cause a owTouchReset to occure at the begining of 
148 //              communication TRUE(1) or not FALSE(0)
149 // 'tran_buf' - pointer to a block of unsigned
150 //              chars of length 'TranferLength' that will be sent 
151 //              to the 1-Wire Net
152 // 'tran_len' - length in bytes to transfer
153
154 // Supported devices: all 
155 //
156 // Returns:   TRUE (1) : The optional reset returned a valid 
157 //                       presence (do_reset == TRUE) or there
158 //                       was no reset required.
159 //            FALSE (0): The reset did not return a valid prsence
160 //                       (do_reset == TRUE).
161 //
162 //  The maximum tran_len is 64
163 //
164 unsigned char iowBlock(unsigned char do_reset, 
165                       unsigned char *tran_buf,
166                       unsigned char tran_len)
167 {
168    int i;
169
170    // check for a block too big
171    if (tran_len > 64)
172       return FALSE;
173
174    // check if need to do a owTouchReset first
175    if (do_reset)
176    {
177       if (!iowTouchReset())
178          return FALSE;
179    }  
180
181    // send and receive the buffer
182    for (i = 0; i < tran_len; i++)
183       tran_buf[i] = iowTouchByte(tran_buf[i]);
184       
185    return TRUE;
186 }
187
188 //--------------------------------------------------------------------------
189 // Send 8 bits of read communication to the 1-Wire Net and and return the
190 // result 8 bits read from the 1-Wire Net.   
191 //
192 // Returns:  8 bytes read from 1-Wire Net
193 //
194 unsigned char iowReadByte(void)
195 {
196    return iowTouchByte(0xFF);
197 }
198
199 //--------------------------------------------------------------------------
200 // The 'owFirst' finds the first device on the 1-Wire Net  This function 
201 // contains one parameter 'alarm_only'.  When 
202 // 'alarm_only' is TRUE (1) the find alarm command 0xEC is 
203 // sent instead of the normal search command 0xF0.
204 // Using the find alarm command 0xEC will limit the search to only
205 // 1-Wire devices that are in an 'alarm' state. 
206 //
207 // 'do_reset' - TRUE (1) 
208 //                perform reset before search. 
209 // 'alarm_only' - TRUE (1) the find alarm command 0xEC is 
210 //                sent instead of the normal search command 0xF0
211 //
212 // Returns:   TRUE (1) : when a 1-Wire device was found and it's 
213 //                        Serial Number placed in the global iSerialNum[portnum]
214 //            FALSE (0): There are no devices on the 1-Wire Net.
215 // 
216 unsigned char iowFirst(unsigned char do_reset, unsigned char alarm_only)
217 {
218    // reset the search state
219    LastDiscrepancy = 0;
220    LastDevice = FALSE;
221    LastFamilyDiscrepancy = 0; 
222
223    return iowNext(do_reset,alarm_only);
224 }
225
226 //--------------------------------------------------------------------------
227 // The 'owNext' function does a general search.  This function
228 // continues from the previos search state. The search state
229 // can be reset by using the 'owFirst' function.
230 // This function contains one parameter 'alarm_only'.  
231 // When 'alarm_only' is TRUE (1) the find alarm command 
232 // 0xEC is sent instead of the normal search command 0xF0.
233 // Using the find alarm command 0xEC will limit the search to only
234 // 1-Wire devices that are in an 'alarm' state. 
235 //
236 // 'do_reset'   - TRUE (1) perform reset before search, FALSE (0) do not
237 //                perform reset before search. 
238 // 'alarm_only' - TRUE (1) the find alarm command 0xEC is 
239 //                sent instead of the normal search command 0xF0
240 //
241 // Returns:   TRUE (1) : when a 1-Wire device was found and it's 
242 //                       Serial Number placed in the global iSerialNum[portnum]
243 //            FALSE (0): when no new device was found.  Either the
244 //                       last search was the last device or there
245 //                       are no devices on the 1-Wire Net.
246 // 
247 unsigned char iowNext(unsigned char do_reset, unsigned char alarm_only)
248 {
249    int bit_test, search_direction, bit_number;
250    int last_zero, serial_byte_number, next_result;
251    unsigned char serial_byte_mask;
252    unsigned char lastcrc8;
253
254    //printf ("iowNext(%d,%d)\n", do_reset, alarm_only);
255
256    // initialize for search 
257    bit_number = 1;
258    last_zero = 0;
259    serial_byte_number = 0;
260    serial_byte_mask = 1;
261    next_result = 0;     
262    lastcrc8 = 0;
263    
264    // if the last call was not the last one 
265    if (!LastDevice)
266    {
267       // check if reset first is requested
268       if (do_reset)
269       {
270          // reset the 1-wire 
271          // if there are no parts on 1-wire, return FALSE
272          if (!iowTouchReset())
273          {
274             // reset the search
275             LastDiscrepancy = 0;        
276             LastFamilyDiscrepancy = 0; 
277             return FALSE;
278          }
279       }
280
281       // If finding alarming devices issue a different command
282       if (alarm_only)
283          iowWriteByte(0xEC);  // issue the alarming search command 
284       else
285          iowWriteByte(0xF0);  // issue the search command 
286
287       // loop to do the search  
288       do
289       {
290          // read a bit and its compliment 
291          bit_test = iowTouchBit(1) << 1;
292          bit_test |= iowTouchBit(1);
293
294          // check for no devices on 1-wire
295          if (bit_test == 3)
296          {
297             break;
298          }
299          else
300          {
301             // all devices coupled have 0 or 1
302             if (bit_test > 0)
303             {
304               search_direction = !(bit_test & 0x01);  // bit write value for search 
305             }
306             else
307             {
308                // if this discrepancy if before the Last Discrepancy
309                // on a previous next then pick the same as last time 
310                if (bit_number < LastDiscrepancy) 
311                   search_direction = ((iSerialNum[serial_byte_number] & serial_byte_mask) > 0);
312                else
313                   // if equal to last pick 1, if not then pick 0              
314                   search_direction = (bit_number == LastDiscrepancy);       
315
316                // if 0 was picked then record its position in LastZero 
317                if (search_direction == 0) 
318                   last_zero = bit_number;  
319
320                // check for Last discrepancy in family 
321                if (last_zero < 9) 
322                   LastFamilyDiscrepancy = last_zero;
323             }
324
325             // set or clear the bit in the iSerialNum byte serial_byte_number 
326             // with mask serial_byte_mask 
327             if (search_direction == 1)
328               iSerialNum[serial_byte_number] |= serial_byte_mask;
329             else
330               iSerialNum[serial_byte_number] &= ~serial_byte_mask;
331
332             // serial number search direction write bit 
333             iowTouchBit(search_direction);
334
335             // increment the byte counter bit_number 
336             // and shift the mask serial_byte_mask 
337             bit_number++;
338             serial_byte_mask <<= 1;
339
340             // if the mask is 0 then go to new iSerialNum byte serial_byte_number
341             // and reset mask 
342             if (serial_byte_mask == 0)
343             {
344                 lastcrc8 = docrc8(lastcrc8,iSerialNum[serial_byte_number]);  // accumulate the CRC 
345                 serial_byte_number++; 
346                 serial_byte_mask = 1;
347             }
348          }
349       } 
350       while(serial_byte_number < 8);  // loop until through all iSerialNum bytes 0-7 
351
352       // if the search was successful then 
353       if (!((bit_number < 65) || lastcrc8))  
354       {
355          // search successful so set LastDiscrepancy,LastDevice,next_result 
356          LastDiscrepancy = last_zero;
357          LastDevice = (LastDiscrepancy == 0);
358          next_result = TRUE;
359       }
360    }
361    
362    // if no device found then reset counters so next 'next' will be
363    // like a first 
364    if (!next_result || !iSerialNum[0])
365    {
366       LastDiscrepancy = 0;
367       LastDevice = FALSE;
368       LastFamilyDiscrepancy = 0; 
369       next_result = FALSE;
370    }
371
372    return next_result;
373 }
374
375 //--------------------------------------------------------------------------
376 // The 'owSerialNum' function either reads or sets the SerialNum buffer 
377 // that is used in the search functions 'owFirst' and 'owNext'.  
378 // This function contains two parameters, 'serialnum_buf' is a pointer
379 // to a buffer provided by the caller.  'serialnum_buf' should point to 
380 // an array of 8 unsigned chars.  The second parameter is a flag called
381 // 'do_read' that is TRUE (1) if the operation is to read and FALSE
382 // (0) if the operation is to set the internal SerialNum buffer from 
383 // the data in the provided buffer.
384 //
385 // 'serialnum_buf' - buffer to that contains the serial number to set
386 //                   when do_read = FALSE (0) and buffer to get the serial
387 //                   number when do_read = TRUE (1).
388 // 'do_read'       - flag to indicate reading (1) or setting (0) the current
389 //                   serial number.
390 //
391 void iowSerialNum(unsigned char *serialnum_buf, unsigned char do_read)
392 {
393    int i;
394
395    // read the internal buffer and place in 'serialnum_buf'
396    if (do_read)
397    {
398       for (i = 0; i < 8; i++)
399       {
400          serialnum_buf[i] = iSerialNum[i];
401       }
402    }
403    // set the internal buffer from the data in 'serialnum_buf'
404    else
405    {
406       for (i = 0; i < 8; i++)
407       {
408          iSerialNum[i] = serialnum_buf[i];
409       }
410    }
411 }
412
413 // unsupported routines
414
415 uchar iowSpeed(int speed) {
416   speed; // hush the compiler
417   printf ("No owSpeed for internal ow yet\n");
418   return FALSE;
419 }
420
421 uchar iowLevel(int level) {
422   level; // hush the compiler
423   printf ("No owLevel for internal ow yet\n");
424   return FALSE;
425 }
426
427 uchar iowProgramPulse() {
428   printf ("No owProgramPulse for internal ow yet\n");
429   return FALSE;
430 }