//--------------------------------------------------------------------------- // Copyright (C) 1999 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. //--------------------------------------------------------------------------- // // MWeather.C - Test application to read the MicroLAN Weather Station. // The weather station consists of the following devices // on the trunk of the MicroLAN: // DS1820 - temperature measurement // DS2423 - counter for reading wind speed (page 15) // DS2407 - switch to isolate 8 DS2401's for wind // direction on channel B. // This test uses MLanNetU.c and MLanTrnU.c // using the low level Win 32-bit functions in WIN32Lnk.c. // // Version: 1.03 // // History: 1.01 -> 1.02 Changed to generic OpenCOM/CloseCOM for easier // use with other platforms. // Corrected ReadCounter to read the right counter // page of DS2423. // Changed to accomodate more than 1 DS1820 // temperature reading. // 1.02 -> 1.03 Removed caps in #includes for Linux capatibility // Changed to use msGettick() instead of // GetTickCount() // Changed reading loop to be infinite in non-win32 // Changed to use Aquire/Release 1-Wire Net functions // #ifdef WIN32 #include #endif #include #include #include #include "mlan.h" // defines #define FALSE 0 #define TRUE 1 // family codes of devices #define TEMP_FAMILY 0x10 #define SWITCH_FAMILY 0x12 #define COUNT_FAMILY 0x1D #define DIR_FAMILY 0x01 // switch states #define SWITCH_AOFF_BON 0x3F #define SWITCH_AOFF_BOFF 0x7F // misc #define MAXTEMPS 10 // external MLan functions extern int MLanTouchByte(int); extern int MLanFirst(int,int); extern int MLanNext(int,int); extern void MLanSerialNum(uchar *, int); extern void MLanFamilySearchSetup(int); extern void MLanSkipFamily(void); extern int MLanAccess(void); extern int MLanOverdriveAccess(void); extern int MLanVerify(int); extern int MLanBlock(int, uchar *, int); extern int MLanReadPacketStd(int, int, uchar *); extern int MLanWritePacketStd(int, uchar *, int, int, int); extern int MLanSpeed(int); extern int MLanLevel(int); extern int MLanReadFile(uchar *, uchar *); extern int MLanFormatWriteFile(uchar *, int, uchar *); extern int MLanProgramPulse(void); extern void msDelay(int); extern long msGettick(void); extern unsigned short crc16(int); extern uchar dowcrc(uchar); extern int Aquire1WireNet(char *, char *); extern void Release1WireNet(char *); // local funcitons void PrintSerialNum(void); int FindWeatherStation(void); int ReadCounter(uchar *, int, unsigned long *); int ReadTemperature(uchar *, float *); int ReadWindDirection(uchar *, char *); int SetSwitchState(uchar *, int); // external global for CRC16 calculation extern unsigned short CRC16; extern uchar DOWCRC; // global serial numbers of Weather Station devices uchar TempSN[MAXTEMPS][8],CountSN[8],SwitchSN[8]; int NumTemps=0; //---------------------------------------------------------------------- // Main Test for Weather Station // void main(short argc, char **argv) { unsigned long start_count=0, end_count=0, start_time, end_time; float current_temp; char current_direction[250]; char return_msg[128]; double revolution_sec; int i; time_t tlong; struct tm *tstruct; //---------------------------------------- // Introduction header printf("\n/---------------------------------------------\n"); printf(" NWeather - V1.03\n" " The following is a test to excersize a\n" " MicroLAN Weather Station containing\n" " DS1820 - temperature measurement (at least 1)\n" " DS2423 - counter for reading wind speed (page 15)\n" " DS2407 - switch to isolate 8 DS2401's for wind\n" " direction on channel B.\n"); #ifdef WIN32 printf(" Press any key to stop this program.\n\n"); #else printf(" Press any CTRL-C to stop this program.\n\n"); #endif printf("Output [Time, Temp1(F),Temp2(F).., Direction Serial Number(s), " "Wind speed(MPH)]\n\n"); // check for required port name if (argc != 2) { printf("1-Wire Net name required on command line!\n" " (example: \"COM1\" (Win32 DS2480),\"/dev/cua0\" " "(Linux DS2480),\"1\" (Win32 TMEX)\n"); exit(1); } // attempt to aquire the 1-Wire Net if (!Aquire1WireNet(argv[1], return_msg)) { printf("%s",return_msg); exit(1); } // success printf("%s",return_msg); // Find the devices required for the Weather Station if (FindWeatherStation()) { // loop to read the state of the weather station // (stops on keypress in WIN32, infinite in others) do { // print the current time time(&tlong); tstruct = localtime(&tlong); printf("%02d:%02d:%02d,",tstruct->tm_hour,tstruct->tm_min,tstruct->tm_sec); // read the current counter // use this reference to calculate wind speed later if (!ReadCounter(CountSN,15,&start_count)) { printf("\nError reading counter, verify device present:%d\n", MLanVerify(FALSE)); continue; } // get a time stamp (mS) start_time = msGettick(); // read the temperature and print in F for (i = 0; i < NumTemps; i++) { if (ReadTemperature(TempSN[i],¤t_temp)) printf("%5.1f,",current_temp * 9 / 5 + 32); else { printf("\nError reading temperature, verify device present:%d\n", MLanVerify(FALSE)); continue; } } // read the wind direction if (ReadWindDirection(SwitchSN,current_direction)) printf("%s, ",current_direction); else { printf("\nError reading wind direction, verify device present:%d\n", MLanVerify(FALSE)); continue; } // read the counter again if (!ReadCounter(CountSN,15,&end_count)) { printf("Error reading counter, verify device present:%d\n", MLanVerify(FALSE)); continue; } // get a time stamp (mS) end_time = msGettick(); // calculate the wind speed based on the revolutions per second revolution_sec = (((end_count - start_count) * 1000.0) / (end_time - start_time)) / 2.0; printf("%5.1f\n",revolution_sec * 2.453); } #ifdef WIN32 while (!kbhit()); #else while (1==1); #endif } else printf("\n\n\nERROR, all required devices for a Weather Station not found!\n"); // release the 1-Wire Net Release1WireNet(return_msg); printf("%s",return_msg); exit(0); } //---------------------------------------------------------------------- // Search for the three types of devices required for a // Weather Station: // - DS1820 // - DS2423 // - DS2407 // // Returns: TRUE(1) success, all required device types found // FALSE(0) all required devices not found // int FindWeatherStation(void) { // find the DS1820 temperature printf("Searching for DS1820..."); // set the search to first find that family code MLanFamilySearchSetup(TEMP_FAMILY); // loop to find all of the temperature device up to MAXTEMPS NumTemps = 0; do { // perform the search if (!MLanNext(TRUE,FALSE)) break; // verify the family code MLanSerialNum(TempSN[NumTemps],TRUE); // check if correct family if (TempSN[NumTemps][0] != TEMP_FAMILY) break; else { // success! correct device type found if (NumTemps > 0) printf(" "); else printf("FOUND: "); PrintSerialNum(); NumTemps++; } } while (NumTemps < (MAXTEMPS - 1)); // check if not at least 1 temperature device if (NumTemps == 0) return FALSE; // find the DS2407 switch printf("Searching for DS2407..."); // set the search to first find that family code MLanFamilySearchSetup(SWITCH_FAMILY); // perform the search if (!MLanNext(TRUE,FALSE)) return FALSE; // verify the family code MLanSerialNum(SwitchSN,TRUE); if (SwitchSN[0] != SWITCH_FAMILY) return FALSE; // success! correct device type found printf("FOUND: "); PrintSerialNum(); // find the DS2423 switch printf("Searching for DS2423..."); // set the search to first find that family code MLanFamilySearchSetup(COUNT_FAMILY); // perform the search if (!MLanNext(TRUE,FALSE)) return FALSE; // verify the family code MLanSerialNum(CountSN,TRUE); if (CountSN[0] != COUNT_FAMILY) return FALSE; // success! correct device type found printf("FOUND: "); PrintSerialNum(); printf("\n"); return TRUE; } //---------------------------------------------------------------------- // Read the counter on a specified page of a DS2423. // // 'SerialNum' - Serial Number of DS2423 that contains the counter // to be read // 'CounterPage' - page number that the counter is associated with // 'Count' - pointer to variable where that count will be returned // // Returns: TRUE(1) counter has been read and verified // FALSE(0) could not read the counter, perhaps device is not // in contact // int ReadCounter(uchar SerialNum[8], int CounterPage, unsigned long *Count) { int rt=FALSE; uchar send_block[30]; int send_cnt=0, address, i; CRC16 = 0; // set the device serial number to the counter device MLanSerialNum(SerialNum,FALSE); // access the device if (MLanAccess()) { // create a block to send that reads the counter // read memory and counter command send_block[send_cnt++] = 0xA5; crc16(0xA5); // address of last data byte before counter address = (CounterPage << 5) + 31; // (1.02) send_block[send_cnt++] = (uchar)(address & 0xFF); crc16(address & 0xFF); send_block[send_cnt++] = (uchar)(address >> 8); crc16(address >> 8); // now add the read bytes for data byte,counter,zero bits, crc16 for (i = 0; i < 11; i++) send_block[send_cnt++] = 0xFF; // now send the block if (MLanBlock(FALSE,send_block,send_cnt)) { // perform the CRC16 on the last 11 bytes of packet for (i = send_cnt - 11; i < send_cnt; i++) crc16(send_block[i]); // verify CRC16 is correct if (CRC16 == 0xB001) { // success rt = TRUE; // extract the counter value *Count = 0; for (i = send_cnt - 7; i >= send_cnt - 10; i--) { *Count <<= 8; *Count |= send_block[i]; } } } } // return the result flag rt return rt; } //---------------------------------------------------------------------- // Read the temperature of a DS1820 // // 'SerialNum' - Serial Number of DS1820 to read temperature from // 'Temp ' - pointer to variable where that temperature will be // returned // // Returns: TRUE(1) temperature has been read and verified // FALSE(0) could not read the temperature, perhaps device is not // in contact // int ReadTemperature(uchar SerialNum[8], float *Temp) { int rt=FALSE; uchar send_block[30]; int send_cnt=0, tsht, i; float tmp,cr,cpc; DOWCRC = 0; // set the device serial number to the counter device MLanSerialNum(SerialNum,FALSE); // access the device if (MLanAccess()) { // send the convert temperature command MLanTouchByte(0x44); // set the MicroLAN to strong pull-up if (MLanLevel(MODE_STRONG5) != MODE_STRONG5) return FALSE; // sleep for 1 second msDelay(1000); // turn off the MicroLAN strong pull-up if (MLanLevel(MODE_NORMAL) != MODE_NORMAL) return FALSE; // access the device if (MLanAccess()) { // create a block to send that reads the temperature // read scratchpad command send_block[send_cnt++] = 0xBE; // now add the read bytes for data bytes and crc8 for (i = 0; i < 9; i++) send_block[send_cnt++] = 0xFF; // now send the block if (MLanBlock(FALSE,send_block,send_cnt)) { // perform the CRC8 on the last 8 bytes of packet for (i = send_cnt - 9; i < send_cnt; i++) dowcrc(send_block[i]); // verify CRC8 is correct if (DOWCRC == 0x00) { // calculate the high-res temperature tsht = send_block[1]; if (send_block[2] & 0x01) tsht |= -256; tmp = (float)(tsht/2); cr = send_block[7]; cpc = send_block[8]; if (cpc == 0) return FALSE; else tmp = tmp - (float)0.25 + (cpc - cr)/cpc; *Temp = tmp; // success rt = TRUE; } } } } // return the result flag rt return rt; } //---------------------------------------------------------------------- // Read the wind direction by closing the channel B of the specified // DS2407 and looking for any DS2401 devices on that branch. The // present DS2401(s) will indicate the wind direction. // // 'SerialNum' - Serial Number of DS2407 to that controls direction // 'Direction' - pointer to string where that wind direction will // be returned. This demo will just return the serial // numbers of the DS2401's found. With a reference this // could be changed to return the actual direction. // // Returns: TRUE(1) Direction has been read // FALSE(0) could not read the direction, perhaps device is not // in contact // int ReadWindDirection(uchar SerialNum[8], char *Direction) { int string_cnt,i; uchar DirSN[8]; // clear the return string string_cnt = sprintf(Direction,""); // connect channel B of DS2407 if (!SetSwitchState(SerialNum,SWITCH_AOFF_BON)) return FALSE; // delay to allow presence pulse to proceed msDelay(10); // record all of DS2401's found // set the search to first find direction family codes DS2401 MLanFamilySearchSetup(DIR_FAMILY); for (;;) { // perform the search if (!MLanNext(TRUE,FALSE)) break; // verify the family code MLanSerialNum(DirSN,TRUE); // if custom DS2401 then skip if (((DirSN[0] & 0x7F) == DIR_FAMILY) && ((DirSN[0] & 0x80) == 0x80)) continue; // check for correct DS2401 family code if (DirSN[0] == DIR_FAMILY) { // record the ID of the DS2401 found string_cnt += sprintf(&Direction[string_cnt]," "); for (i = 7; i >= 0; i--) string_cnt += sprintf(&Direction[string_cnt],"%02X",DirSN[i]); } else break; } // open channel B of DS2407 // give this up to 15 attempts so that the DS2401 present pulses // do not interrupt other sensor readings for (i = 0; i < 15; i++) { if (SetSwitchState(SerialNum,SWITCH_AOFF_BOFF)) return TRUE; else msDelay(10); } // failed to open the B channel of the DS2407 return FALSE; } //---------------------------------------------------------------------- // Set the channel state of the specified DS2407 // // 'SerialNum' - Serial Number of DS2407 to set the switch state // 'State' - State value to be written to location 7 of the // status memory. // // Returns: TRUE(1) State of DS2407 set and verified // FALSE(0) could not set the DS2407, perhaps device is not // in contact // int SetSwitchState(uchar SerialNum[8], int State) { int rt=FALSE; uchar send_block[30]; int send_cnt=0; CRC16 = 0; // set the device serial number to the counter device MLanSerialNum(SerialNum,FALSE); // access the device if (MLanAccess()) { // create a block to send that reads the counter // write status command send_block[send_cnt++] = 0x55; crc16(0x55); // address of switch state send_block[send_cnt++] = 0x07; crc16(0x07); send_block[send_cnt++] = 0x00; crc16(0x00); // write state send_block[send_cnt++] = (uchar)State; crc16(State); // read CRC16 send_block[send_cnt++] = 0xFF; send_block[send_cnt++] = 0xFF; // now send the block if (MLanBlock(FALSE,send_block,send_cnt)) { // perform the CRC16 on the last 2 bytes of packet crc16(send_block[send_cnt-2]); crc16(send_block[send_cnt-1]); // verify CRC16 is correct if (CRC16 == 0xB001) // success rt = TRUE; } } // return the result flag rt return rt; } //---------------------------------------------------------------------- // Read and print the Serial Number. // void PrintSerialNum(void) { uchar TempSerialNumber[8]; int i; MLanSerialNum(TempSerialNumber,TRUE); for (i = 7; i >= 0; i--) printf("%02X",TempSerialNumber[i]); printf("\n"); }