![](/media/cache/profiles/a7bf3f5462cc82062e41b3a2262e1a21.50x50_q85.jpg)
1-Wire implementation, using DS2480B controller interfaced with serial port, working example to read DS18B20, based on work already in progress / Dallas - Public domain code
Diff: owtrnu.cpp
- Revision:
- 0:1193dbfe28e2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/owtrnu.cpp Thu Mar 24 17:21:29 2011 +0000 @@ -0,0 +1,598 @@ +//--------------------------------------------------------------------------- +// Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES +// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// Except as contained in this notice, the name of Dallas Semiconductor +// shall not be used except as stated in the Dallas Semiconductor +// Branding Policy. +//--------------------------------------------------------------------------- +// +// owTranU.C - Transport functions for 1-Wire Net +// using the DS2480B (U) serial interface chip. +// +// Version: 2.01 +// +// History: 1.02 -> 1.03 Removed caps in #includes for Linux capatibility +// 1.03 -> 2.00 Changed 'MLan' to 'ow'. Added support for +// multiple ports. +// 2.00 -> 2.01 Added support for owError library +// 2.01 -> 2.10 Added SMALLINT for small processors and error +// handling plus the raw memory utilities. +// 2.10 -> 3.00 Added memory bank functionality +// Added file I/O operations +// + +#include "ownet.h" +#include "./Headers/ds2480.h" +// external defined in ds2480ut.c +extern SMALLINT UBaud[MAX_PORTNUM]; +extern SMALLINT UMode[MAX_PORTNUM]; +extern SMALLINT USpeed[MAX_PORTNUM]; +extern uchar SerialNum[MAX_PORTNUM][8]; + +// local static functions +static SMALLINT Write_Scratchpad(int,uchar *,int,SMALLINT); +static SMALLINT Copy_Scratchpad(int,int,SMALLINT); + +//-------------------------------------------------------------------------- +// The 'owBlock' transfers a block of data to and from the +// 1-Wire Net with an optional reset at the begining of communication. +// The result is returned in the same buffer. +// +// 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to +// indicate the symbolic port number. +// 'do_reset' - cause a owTouchReset to occure at the begining of +// communication TRUE(1) or not FALSE(0) +// 'tran_buf' - pointer to a block of unsigned +// chars of length 'tran_len' that will be sent +// to the 1-Wire Net +// 'tran_len' - length in bytes to transfer + +// Supported devices: all +// +// Returns: TRUE (1) : The optional reset returned a valid +// presence (do_reset == TRUE) or there +// was no reset required. +// FALSE (0): The reset did not return a valid prsence +// (do_reset == TRUE). +// +// The maximum tran_length is (160) +// +SMALLINT owBlock(int portnum, SMALLINT do_reset, uchar *tran_buf, SMALLINT tran_len) +{ + uchar sendpacket[320]; + uchar sendlen=0,i; + + // check for a block too big + if (tran_len > 160) + { + OWERROR(OWERROR_BLOCK_TOO_BIG); + return FALSE; + } + + // check if need to do a owTouchReset first + if (do_reset) + { + if (!owTouchReset(portnum)) + { + OWERROR(OWERROR_NO_DEVICES_ON_NET); + return FALSE; + } + } + + // construct the packet to send to the DS2480 + // check if correct mode + if (UMode[portnum] != MODSEL_DATA) + { + UMode[portnum] = MODSEL_DATA; + sendpacket[sendlen++] = MODE_DATA; + } + + // add the bytes to send +// pos = sendlen; + for (i = 0; i < tran_len; i++) + { + sendpacket[sendlen++] = tran_buf[i]; + + // check for duplication of data that looks like COMMAND mode + if (tran_buf[i] == MODE_COMMAND) + sendpacket[sendlen++] = tran_buf[i]; + } + + // flush the buffers + FlushCOM(portnum); + + // send the packet + if (WriteCOM(portnum,sendlen,sendpacket)) + { + // read back the response + if (ReadCOM(portnum,tran_len,tran_buf) == tran_len) + return TRUE; + else + OWERROR(OWERROR_READCOM_FAILED); + } + else + OWERROR(OWERROR_WRITECOM_FAILED); + + // an error occured so re-sync with DS2480 + DS2480Detect(portnum); + + return FALSE; +} + +//-------------------------------------------------------------------------- +// Read a Universal Data Packet from a standard NVRAM iButton +// and return it in the provided buffer. The page that the +// packet resides on is 'start_page'. Note that this function is limited +// to single page packets. The buffer 'read_buf' must be at least +// 29 bytes long. +// +// The Universal Data Packet always start on page boundaries but +// can end anywhere. The length is the number of data bytes not +// including the length byte and the CRC16 bytes. There is one +// length byte. The CRC16 is first initialized to the starting +// page number. This provides a check to verify the page that +// was intended is being read. The CRC16 is then calculated over +// the length and data bytes. The CRC16 is then inverted and stored +// low byte first followed by the high byte. +// +// Supported devices: DS1992, DS1993, DS1994, DS1995, DS1996, DS1982, +// DS1985, DS1986, DS2407, and DS1971. +// +// 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to +// indicate the symbolic port number. +// 'do_access' - flag to indicate if an 'owAccess' should be +// peformed at the begining of the read. This may +// be FALSE (0) if the previous call was to read the +// previous page (start_page-1). +// 'start_page' - page number to start the read from +// 'read_buf' - pointer to a location to store the data read +// +// Returns: >=0 success, number of data bytes in the buffer +// -1 failed to read a valid UDP +// +// +SMALLINT owReadPacketStd(int portnum, SMALLINT do_access, int start_page, uchar *read_buf) +{ + uchar i,length,sendlen=0,head_len=0; + uchar sendpacket[50]; + unsigned short lastcrc16; + + // check if access header is done + // (only use if in sequention read with one access at begining) + if (do_access) + { + // match command + sendpacket[sendlen++] = 0x55; + for (i = 0; i < 8; i++) + sendpacket[sendlen++] = SerialNum[portnum][i]; + // read memory command + sendpacket[sendlen++] = 0xF0; + // write the target address + sendpacket[sendlen++] = ((start_page << 5) & 0xFF); + sendpacket[sendlen++] = (start_page >> 3); + // check for DS1982 exception (redirection byte) + if (SerialNum[portnum][0] == 0x09) + sendpacket[sendlen++] = 0xFF; + // record the header length + head_len = sendlen; + } + // read the entire page length byte + for (i = 0; i < 32; i++) + sendpacket[sendlen++] = 0xFF; + + // send/recieve the transfer buffer + if (owBlock(portnum,do_access,sendpacket,sendlen)) + { + // seed crc with page number + setcrc16(portnum,(unsigned short)start_page); + + // attempt to read UDP from sendpacket + length = sendpacket[head_len]; + docrc16(portnum,(unsigned short)length); + + // verify length is not too large + if (length <= 29) + { + // loop to read packet including CRC + for (i = 0; i < length; i++) + { + read_buf[i] = sendpacket[i+1+head_len]; + docrc16(portnum,read_buf[i]); + } + + // read and compute the CRC16 + docrc16(portnum,sendpacket[i+1+head_len]); + lastcrc16 = docrc16(portnum,sendpacket[i+2+head_len]); + + // verify the CRC16 is correct + if (lastcrc16 == 0xB001) + return length; // return number of byte in record + else + OWERROR(OWERROR_CRC_FAILED); + } + else + OWERROR(OWERROR_INCORRECT_CRC_LENGTH); + } + else + OWERROR(OWERROR_BLOCK_FAILED); + + // failed block or incorrect CRC + return -1; +} + +//-------------------------------------------------------------------------- +// Write a Universal Data Packet onto a standard NVRAM 1-Wire device +// on page 'start_page'. This function is limited to UDPs that +// fit on one page. The data to write is provided as a buffer +// 'write_buf' with a length 'write_len'. +// +// The Universal Data Packet always start on page boundaries but +// can end anywhere. The length is the number of data bytes not +// including the length byte and the CRC16 bytes. There is one +// length byte. The CRC16 is first initialized to the starting +// page number. This provides a check to verify the page that +// was intended is being read. The CRC16 is then calculated over +// the length and data bytes. The CRC16 is then inverted and stored +// low byte first followed by the high byte. +// +// Supported devices: is_eprom=0 +// DS1992, DS1993, DS1994, DS1995, DS1996 +// is_eprom=1, crc_type=0(CRC8) +// DS1982 +// is_eprom=1, crc_type=1(CRC16) +// DS1985, DS1986, DS2407 +// +// 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to +// indicate the symbolic port number. +// 'start_page' - page number to write packet to +// 'write_buf' - pointer to buffer containing data to write +// 'write_len' - number of data byte in write_buf +// 'is_eprom' - flag set if device is an EPROM (1 EPROM, 0 NVRAM) +// 'crc_type' - if is_eprom=1 then indicates CRC type +// (0 CRC8, 1 CRC16) +// +// Returns: TRUE(1) success, packet written +// FALSE(0) failure to write, contact lost or device locked +// +SMALLINT owWritePacketStd(int portnum, int start_page, uchar *write_buf, + SMALLINT write_len, SMALLINT is_eprom, SMALLINT crc_type) +{ + uchar construct_buffer[32]; + uchar i,buffer_cnt=0,start_address,do_access; + unsigned short lastcrc16=0; + + // check to see if data too long to fit on device + if (write_len > 29) + return FALSE; + + // seed crc with page number + setcrc16(portnum,(unsigned short)start_page); + + // set length byte + construct_buffer[buffer_cnt++] = (uchar)(write_len); + docrc16(portnum,(unsigned short)write_len); + + // fill in the data to write + for (i = 0; i < write_len; i++) + { + lastcrc16 = docrc16(portnum,write_buf[i]); + construct_buffer[buffer_cnt++] = write_buf[i]; + } + + // add the crc + construct_buffer[buffer_cnt++] = (uchar)(~(lastcrc16 & 0xFF)); + construct_buffer[buffer_cnt++] = (uchar)(~((lastcrc16 & 0xFF00) >> 8)); + + // check if not EPROM + if (!is_eprom) + { + // write the page + if (!Write_Scratchpad(portnum,construct_buffer,start_page,buffer_cnt)) + { + OWERROR(OWERROR_WRITE_SCRATCHPAD_FAILED); + return FALSE; + } + + // copy the scratchpad + if (!Copy_Scratchpad(portnum,start_page,buffer_cnt)) + { + OWERROR(OWERROR_COPY_SCRATCHPAD_FAILED); + return FALSE; + } + + // copy scratch pad was good then success + return TRUE; + } + // is EPROM + else + { + // calculate the start address + start_address = ((start_page >> 3) << 8) | ((start_page << 5) & 0xFF); + do_access = TRUE; + // loop to program each byte + for (i = 0; i < buffer_cnt; i++) + { + if (owProgramByte(portnum,construct_buffer[i], start_address + i, + 0x0F, crc_type, do_access) != construct_buffer[i]) + { + OWERROR(OWERROR_PROGRAM_BYTE_FAILED); + return FALSE; + } + do_access = FALSE; + } + return TRUE; + } +} + +//-------------------------------------------------------------------------- +// Write a byte to an EPROM 1-Wire device. +// +// Supported devices: crc_type=0(CRC8) +// DS1982 +// crc_type=1(CRC16) +// DS1985, DS1986, DS2407 +// +// 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to +// indicate the symbolic port number. +// 'write_byte' - byte to program +// 'addr' - address of byte to program +// 'write_cmd' - command used to write (0x0F reg mem, 0x55 status) +// 'crc_type' - CRC used (0 CRC8, 1 CRC16) +// 'do_access' - Flag to access device for each byte +// (0 skip access, 1 do the access) +// WARNING, only use do_access=0 if programing the NEXT +// byte immediatly after the previous byte. +// +// Returns: >=0 success, this is the resulting byte from the program +// effort +// -1 error, device not connected or program pulse voltage +// not available +// +SMALLINT owProgramByte(int portnum, SMALLINT write_byte, int addr, SMALLINT write_cmd, + SMALLINT crc_type, SMALLINT do_access) +{ + unsigned short lastcrc16; + uchar lastcrc8; + + // optionally access the device + if (do_access) + { + if (!owAccess(portnum)) + { + OWERROR(OWERROR_ACCESS_FAILED); + return -1; + } + + // send the write command + if (!owWriteByte(portnum,write_cmd)) + { + OWERROR(OWERROR_WRITE_BYTE_FAILED); + return -1; + } + + // send the address + if (!owWriteByte(portnum,addr & 0xFF) || !owWriteByte(portnum,addr >> 8)) + { + OWERROR(OWERROR_WRITE_BYTE_FAILED); + return -1; + } + } + + // send the data to write + if (!owWriteByte(portnum,write_byte)) + { + OWERROR(OWERROR_WRITE_BYTE_FAILED); + return -1; + } + + // read the CRC + if (crc_type == 0) + { + // calculate CRC8 + if (do_access) + { + setcrc8(portnum,0); + docrc8(portnum,(uchar)write_cmd); + docrc8(portnum,(uchar)(addr & 0xFF)); + docrc8(portnum,(uchar)(addr >> 8)); + } + else + setcrc8(portnum,(uchar)(addr & 0xFF)); + + docrc8(portnum,(uchar)write_byte); + // read and calculate the read crc + lastcrc8 = docrc8(portnum,(uchar)owReadByte(portnum)); + // crc should now be 0x00 + if (lastcrc8 != 0) + { + OWERROR(OWERROR_CRC_FAILED); + return -1; + } + } + else + { + // CRC16 + if (do_access) + { + setcrc16(portnum,0); + docrc16(portnum,(unsigned short)write_cmd); + docrc16(portnum,(unsigned short)(addr & 0xFF)); + docrc16(portnum,(unsigned short)(addr >> 8)); + } + else + setcrc16(portnum,(unsigned short)addr); + docrc16(portnum,(unsigned short)write_byte); + // read and calculate the read crc + docrc16(portnum,( unsigned short)owReadByte(portnum)); + lastcrc16 = docrc16(portnum,( unsigned short)owReadByte(portnum)); + // crc should now be 0xB001 + if (lastcrc16 != 0xB001) + { + OWERROR(OWERROR_CRC_FAILED); + return -1; + } + } + + // send the program pulse + if (!owProgramPulse(portnum)) + { + OWERROR(OWERROR_PROGRAM_PULSE_FAILED); + return -1; + } + + // read back and return the resulting byte + return owReadByte(portnum); +} + +//-------------------------------------------------------------------------- +// Write the scratchpad of a standard NVRam device such as the DS1992,3,4 +// and verify its contents. +// +// 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to +// indicate the symbolic port number. +// 'write_buf' - pointer to buffer containing data to write +// 'start_page' - page number to write packet to +// 'write_len' - number of data byte in write_buf +// +// Returns: TRUE(1) success, the data was written and verified +// FALSE(0) failure, the data could not be written +// +// +SMALLINT Write_Scratchpad(int portnum, uchar *write_buf, int start_page, SMALLINT write_len) +{ + uchar i,sendlen=0; + uchar sendpacket[50]; + + // match command + sendpacket[sendlen++] = 0x55; + for (i = 0; i < 8; i++) + sendpacket[sendlen++] = SerialNum[portnum][i]; + // write scratchpad command + sendpacket[sendlen++] = 0x0F; + // write the target address + sendpacket[sendlen++] = ((start_page << 5) & 0xFF); + sendpacket[sendlen++] = (start_page >> 3); + + // write packet bytes + for (i = 0; i < write_len; i++) + sendpacket[sendlen++] = write_buf[i]; + + // send/recieve the transfer buffer + if (owBlock(portnum,TRUE,sendpacket,sendlen)) + { + // now attempt to read back to check + sendlen = 0; + // match command + sendpacket[sendlen++] = 0x55; + for (i = 0; i < 8; i++) + sendpacket[sendlen++] = SerialNum[portnum][i]; + // read scratchpad command + sendpacket[sendlen++] = 0xAA; + // read the target address, offset and data + for (i = 0; i < (write_len + 3); i++) + sendpacket[sendlen++] = 0xFF; + + // send/recieve the transfer buffer + if (owBlock(portnum,TRUE,sendpacket,sendlen)) + { + // check address and offset of scratchpad read + if ((sendpacket[10] != ((start_page << 5) & 0xFF)) || + (sendpacket[11] != (start_page >> 3)) || + (sendpacket[12] != (write_len - 1))) + { + OWERROR(OWERROR_READ_VERIFY_FAILED); + return FALSE; + } + + // verify each data byte + for (i = 0; i < write_len; i++) + if (sendpacket[i+13] != write_buf[i]) + { + OWERROR(OWERROR_WRITE_VERIFY_FAILED); + return FALSE; + } + + // must have verified + return TRUE; + } + else + OWERROR(OWERROR_BLOCK_FAILED); + } + else + OWERROR(OWERROR_BLOCK_FAILED); + + // failed a block tranfer + return FALSE; +} + +//-------------------------------------------------------------------------- +// Copy the contents of the scratchpad to its intended nv ram page. The +// page and length of the data is needed to build the authorization bytes +// to copy. +// +// 'portnum' - number 0 to MAX_PORTNUM-1. This number is provided to +// indicate the symbolic port number. +// 'start_page' - page number to write packet to +// 'write_len' - number of data bytes that are being copied +// +// Returns: TRUE(1) success +// FALSE(0) failure +// +SMALLINT Copy_Scratchpad(int portnum, int start_page, SMALLINT write_len) +{ + uchar i,sendlen=0; + uchar sendpacket[50]; + + // match command + sendpacket[sendlen++] = 0x55; + for (i = 0; i < 8; i++) + sendpacket[sendlen++] = SerialNum[portnum][i]; + // copy scratchpad command + sendpacket[sendlen++] = 0x55; + // write the target address + sendpacket[sendlen++] = ((start_page << 5) & 0xFF); + sendpacket[sendlen++] = (start_page >> 3); + sendpacket[sendlen++] = write_len - 1; + // read copy result + sendpacket[sendlen++] = 0xFF; + + // send/recieve the transfer buffer + if (owBlock(portnum,TRUE,sendpacket,sendlen)) + { + // check address and offset of scratchpad read + if ((sendpacket[10] != ((start_page << 5) & 0xFF)) || + (sendpacket[11] != (start_page >> 3)) || + (sendpacket[12] != (write_len - 1)) || + (sendpacket[13] & 0xF0)) + { + OWERROR(OWERROR_READ_VERIFY_FAILED); + return FALSE; + } + else + return TRUE; + } + else + OWERROR(OWERROR_BLOCK_FAILED); + + // failed a block tranfer + return FALSE; +} +