Aleksandrs Gumenuks / MaximInterface_Extended

Dependents:   mbed_DS28EC20_GPIO

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers DS28EC20.cpp Source File

DS28EC20.cpp

00001 /*******************************************************************************
00002 * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
00003 *
00004 * Permission is hereby granted, free of charge, to any person obtaining a
00005 * copy of this software and associated documentation files (the "Software"),
00006 * to deal in the Software without restriction, including without limitation
00007 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00008 * and/or sell copies of the Software, and to permit persons to whom the
00009 * Software is furnished to do so, subject to the following conditions:
00010 *
00011 * The above copyright notice and this permission notice shall be included
00012 * in all copies or substantial portions of the Software.
00013 *
00014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00015 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00017 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
00018 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00019 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00020 * OTHER DEALINGS IN THE SOFTWARE.
00021 *
00022 * Except as contained in this notice, the name of Maxim Integrated
00023 * Products, Inc. shall not be used except as stated in the Maxim Integrated
00024 * Products, Inc. Branding Policy.
00025 *
00026 * The mere transfer of this software does not imply any licenses
00027 * of trade secrets, proprietary technology, copyrights, patents,
00028 * trademarks, maskwork rights, or any other form of intellectual
00029 * property whatsoever. Maxim Integrated Products, Inc. retains all
00030 * ownership rights.
00031 *******************************************************************************/
00032 
00033 #include "DS28EC20.hpp"
00034 #include <MaximInterface/Links/OneWireMaster.hpp>
00035 #include <MaximInterface/Utilities/Error.hpp>
00036 #include <MaximInterface/Utilities/crc.hpp>
00037 
00038 #include <algorithm>
00039 #include <string.h>
00040 
00041 namespace MaximInterface {
00042 
00043 typedef enum _Command_t
00044 {
00045     WriteScratchpad = 0x0F,
00046     ReadScratchpad = 0xAA,
00047     CopyScratchpad = 0x55,
00048     ReadMemory = 0xF0,
00049     ReadMemoryExt = 0xA5
00050 } Command;
00051 
00052 
00053 
00054 error_code writeMemory(DS28EC20 & device, DS28EC20::Address targetAddress,
00055                        const DS28EC20::Scratchpad & data) {
00056   error_code result = device.writeScratchpad(targetAddress, data);
00057   if (result) {
00058     return result;
00059   }
00060   DS28EC20::Scratchpad readData;
00061   uint_least8_t esByte;
00062   result = device.readScratchpad(readData, esByte);
00063   if (result) {
00064     return result;
00065   }
00066   result = device.copyScratchpad(targetAddress, esByte);
00067   return result;
00068 }
00069 
00070 
00071 error_code writeMemory(DS28EC20 & device, DS28EC20::Address inAddress,
00072                        const uint_least8_t * dataIn, size_t dataLen)
00073 {
00074     DS28EC20::Scratchpad scratchpad;
00075 
00076     DS28EC20::Address offset = inAddress - (inAddress & ~(DS28EC20::pageSizeBytes - 1));
00077     DS28EC20::Address targetAddress = inAddress - offset;
00078 
00079     uint_least8_t *p_Data = scratchpad.data();
00080     p_Data += offset;
00081 
00082     MaximInterface::error_code error;
00083     size_t readLen = (dataLen + offset);
00084 
00085     /* ... Align length to page boundary */
00086     readLen += readLen + (DS28EC20::pageSizeBytes - 1u);
00087     readLen &= ~(DS28EC20::pageSizeBytes - 1u);
00088 
00089     for (size_t writeLen = 0u; writeLen < readLen; writeLen += DS28EC20::pageSizeBytes) {
00090         if (offset && dataLen){
00091             error = device.readMemoryExt(targetAddress, scratchpad.data(), DS28EC20::pageSizeBytes);
00092         }
00093 
00094         if (error) {
00095             return error;
00096         }
00097 
00098         if (dataLen) {
00099             if (dataLen >= DS28EC20::pageSizeBytes) {
00100                 (void)memcpy(p_Data, dataIn, DS28EC20::pageSizeBytes);
00101                 dataIn += DS28EC20::pageSizeBytes;
00102                 dataLen -= DS28EC20::pageSizeBytes;
00103             }
00104             else {
00105                 (void)memcpy(p_Data, dataIn, dataLen);
00106                 dataLen = 0;
00107             }
00108             p_Data = scratchpad.data();
00109         }
00110 
00111         error = writeMemory(device, targetAddress, scratchpad);
00112         targetAddress += DS28EC20::pageSizeBytes;
00113 
00114         if (error) {
00115             return error;
00116         }
00117 
00118         offset = 0;
00119     }
00120 
00121     return error;
00122 }
00123 
00124 
00125 /* TODO: Test readMemory */
00126 error_code DS28EC20::readMemory(Address beginAddress, uint_least8_t * data,
00127                               size_t dataLen) const {
00128   error_code owmResult = selectRom(*master);
00129   if (owmResult) {
00130     return owmResult;
00131   }
00132   const uint_least8_t sendBlock[] = {ReadMemory, static_cast<uint_least8_t>(beginAddress), static_cast<uint_least8_t>(beginAddress >> 8)};
00133   owmResult =
00134       master->writeBlock(make_span(sendBlock, sizeof(sendBlock) / sizeof(sendBlock[0])));
00135   if (owmResult) {
00136     return owmResult;
00137   }
00138   owmResult = master->readBlock(make_span(data, dataLen));
00139   return owmResult;
00140 }
00141 
00142 #if 0
00143 static unsigned short crc16(const unsigned char* pin, int sz, unsigned short crc_in)
00144 {
00145     unsigned short crc = crc_in;
00146     unsigned short tmp, in;
00147     int i, index, bit;
00148     for (index = 0, bit = 0, i = 0; i < 8 * sz; i++) {
00149         in = pin[index];
00150         in >>= (bit);
00151         tmp = (crc & 0x8000);
00152         tmp >>= 15;
00153         in ^= tmp;
00154         in &= 1;
00155         bit++;
00156         if (bit >= 8) {
00157             bit = 0;
00158             index++;
00159         }
00160 
00161         crc <<= 1;
00162         tmp = crc;
00163         tmp &= 0x8004;
00164         if (in) {
00165             tmp ^= 0x8004;
00166             tmp &= 0x8004;
00167         }
00168         crc &= (~0x8004);
00169         crc |= tmp;
00170         if (in)
00171             crc |= 1;
00172         else
00173             crc &= (~1);
00174     }
00175 
00176     tmp = (crc & 1);
00177     for (i = 0; i < 15; i++) {
00178         tmp <<= 1;
00179         crc >>= 1;
00180         tmp |= (crc & 1);
00181     }
00182     return ~tmp;
00183 }
00184 
00185 #   define CRC16(...)\
00186     crc16(__VA_ARGS__)
00187 #else
00188 #   define CRC16(data, len, ...)\
00189     calculateCrc16(make_span(data, len), __VA_ARGS__)
00190 #endif
00191 
00192 #define PAGE_SIZE_BYTES 32
00193 #define CRC_LEN_BYTES   2
00194 
00195 
00196 static error_code processCrc16(OneWireMaster *master, uint_least16_t & crcLocal)
00197 {
00198     /* ... Read CRC */
00199     uint_least8_t crcRemote[CRC_LEN_BYTES];
00200     error_code owmResult = master->readBlock(make_span(&crcRemote[0], sizeof(crcRemote) / sizeof(crcRemote[0])));
00201 
00202     if (owmResult) {
00203         return owmResult;
00204     }
00205 
00206     crcLocal = ~crcLocal;
00207     crcLocal ^= crcRemote[0] | (static_cast<uint_least16_t>(crcRemote[1]) << 8);
00208 
00209     if (crcLocal) {
00210         owmResult = make_error_code(DS28EC20::CrcError);
00211         return owmResult;
00212     }
00213 
00214     crcLocal = 0;
00215 
00216     return owmResult;
00217 }
00218 
00219 
00220 error_code DS28EC20::readMemoryExt(Address beginAddress, uint_least8_t * data,
00221                                    size_t dataLen) const
00222 {
00223     error_code owmResult = selectRom(*master);
00224     if (owmResult) {
00225         return owmResult;
00226     }
00227 
00228     uint_least8_t addressMsb = static_cast<uint_least8_t>(beginAddress >> 8);
00229     uint_least8_t addressLsb = static_cast<uint_least8_t>(beginAddress >> 0);
00230 
00231     uint_least8_t offset = addressLsb & ~(PAGE_SIZE_BYTES - 1);
00232     offset = addressLsb - offset;
00233 
00234     const uint_least8_t sendBlock[] = { ReadMemoryExt, static_cast<uint_least8_t>(addressLsb - offset), addressMsb };
00235     owmResult = master->writeBlock(make_span(sendBlock, sizeof(sendBlock) / sizeof(sendBlock[0])));
00236 
00237     if (owmResult) {
00238         return owmResult;
00239     }
00240 
00241     uint_least16_t crcLocal = 0;
00242 
00243     /* ... Calculate CRC of control fields */
00244     crcLocal = CRC16(&sendBlock[0],  sizeof(sendBlock) / sizeof(sendBlock[0]), crcLocal);
00245 
00246     uint_least8_t byte = 0;
00247     /* ... Calculate CRC of head bytes */
00248     {
00249         uint32_t n = offset;
00250         while (n--) {
00251             owmResult = master->readByte(byte);
00252             crcLocal = CRC16(&byte, sizeof(byte), crcLocal);
00253         }
00254     }
00255 
00256     /* ... Read data blocks */
00257     const size_t blockCnt = dataLen / PAGE_SIZE_BYTES;
00258     size_t blockLen = PAGE_SIZE_BYTES - offset;
00259     for (size_t block = 0; block < blockCnt; ++block)
00260     {
00261         /* ... Read data */
00262         owmResult = master->readBlock(make_span(data, blockLen));
00263 
00264         if (owmResult) {
00265             return owmResult;
00266         }
00267 
00268         /* ... Calculate CRC of data */
00269         crcLocal = CRC16(data, blockLen, crcLocal);
00270         data += blockLen;
00271 
00272         /* ... Read CRC */
00273         owmResult = processCrc16(master, crcLocal);
00274 
00275         if (owmResult) {
00276             return owmResult;
00277         }
00278 
00279         blockLen = PAGE_SIZE_BYTES;
00280     }
00281 
00282 
00283     /* ... Read data reminder */
00284     size_t dataBlockLen = 0;
00285     size_t remLen       = 0;
00286     if (PAGE_SIZE_BYTES > blockLen)
00287     {
00288 
00289         /* ... Total amount of user data is less than one block */
00290         if (PAGE_SIZE_BYTES > (offset + dataLen)) {
00291             /* ... Total length does not cross block boundary.
00292              *     Read till the end of block. */
00293             dataBlockLen = dataLen;
00294             remLen = blockLen - dataBlockLen;
00295 
00296         }
00297         else {
00298             /* ... Total length is longer than one block.
00299              *     Read till the end of block and then the rest. */
00300             dataBlockLen = blockLen;
00301 
00302             /* ... Read data */
00303             owmResult = master->readBlock(make_span(data, dataBlockLen));
00304 
00305             if (owmResult) {
00306                 return owmResult;
00307             }
00308 
00309             /* ... Calculate CRC of data */
00310             crcLocal = CRC16(data, dataBlockLen, crcLocal);
00311             data += dataBlockLen;
00312 
00313             /* ... Read CRC */
00314             owmResult = processCrc16(master, crcLocal);
00315 
00316             if (owmResult) {
00317                 return owmResult;
00318             }
00319 
00320             dataBlockLen = dataLen - dataBlockLen;
00321             remLen = PAGE_SIZE_BYTES - dataBlockLen;
00322         }
00323 
00324     }
00325     else
00326     {
00327         /* ... Total amount of data is more than one block */
00328         dataBlockLen = dataLen % PAGE_SIZE_BYTES;
00329         remLen = PAGE_SIZE_BYTES - dataBlockLen;
00330     }
00331 
00332     /* ... Read data */
00333     owmResult = master->readBlock(make_span(data, dataBlockLen));
00334 
00335     if (owmResult) {
00336         return owmResult;
00337     }
00338 
00339     /* ... Calculate CRC of data */
00340     crcLocal = CRC16(data, dataBlockLen, crcLocal);
00341     data += dataBlockLen;
00342 
00343     /* ... Read tail */
00344     while (remLen--) {
00345         owmResult = master->readByte(byte);
00346         crcLocal = CRC16(&byte, sizeof(byte), crcLocal);
00347 
00348         if (owmResult) {
00349             return owmResult;
00350         }
00351     }
00352 
00353     /* ... Read CRC */
00354     owmResult = processCrc16(master, crcLocal);
00355 
00356     if (owmResult) {
00357         return owmResult;
00358     }
00359 
00360     return owmResult;
00361 }
00362 
00363 
00364 error_code DS28EC20::writeScratchpad(Address targetAddress,
00365                                    const Scratchpad & data) {
00366   error_code owmResult = selectRom(*master);
00367   if (owmResult) {
00368     return owmResult;
00369   }
00370 
00371   uint_least8_t addressMsb = static_cast<uint_least8_t>(targetAddress >> 8);
00372   uint_least8_t addressLsb = static_cast<uint_least8_t>(targetAddress >> 0);
00373   addressLsb &= ~(pageSizeBytes - 1);
00374 
00375   array<uint_least8_t, 3 + Scratchpad::csize> block;
00376   block[0] = WriteScratchpad;
00377   block[1] = addressLsb;
00378   block[2] = addressMsb;
00379 
00380   std::copy(data.begin(), data.end(), block.begin() + 3);
00381   owmResult = master->writeBlock(make_span(block.data(), block.size()));
00382   if (owmResult) {
00383     return owmResult;
00384   }
00385   const uint_fast16_t calculatedCrc = calculateCrc16(make_span(block.data(), block.size())) ^ 0xFFFFU;
00386   owmResult = master->readBlock(make_span(block.data(), 2));
00387   if (owmResult) {
00388     return owmResult;
00389   }
00390   if (calculatedCrc !=
00391       ((static_cast<uint_fast16_t>(block[1]) << 8) | block[0])) {
00392     owmResult = make_error_code(CrcError);
00393   }
00394   return owmResult;
00395 }
00396 
00397 error_code DS28EC20::readScratchpad(Scratchpad & data, uint_least8_t & esByte) {
00398   typedef array<uint_least8_t, 6 + Scratchpad::csize> Block;
00399 
00400   error_code owmResult = selectRom(*master);
00401   if (owmResult) {
00402     return owmResult;
00403   }
00404   Block block; block[0] = ReadScratchpad;
00405   owmResult = master->writeByte(block.front());
00406   if (owmResult) {
00407     return owmResult;
00408   }
00409   owmResult = master->readBlock(make_span(block.data() + 1, block.size() - 1));
00410   if (owmResult) {
00411     return owmResult;
00412   }
00413   Block::const_iterator blockIt = block.end();
00414   uint_fast16_t receivedCrc = static_cast<uint_fast16_t>(*(--blockIt)) << 8;
00415   receivedCrc |= *(--blockIt);
00416   const uint_fast16_t expectedCrc = calculateCrc16(make_span(block.data(), block.size() - 2)) ^ 0xFFFFU;
00417   if (expectedCrc == receivedCrc) {
00418     Block::const_iterator blockItEnd = blockIt;
00419     blockIt -= data.size();
00420     std::copy(blockIt, blockItEnd, data.begin());
00421     esByte = *(--blockIt);
00422   } else {
00423     owmResult = make_error_code(CrcError);
00424   }
00425   return owmResult;
00426 }
00427 
00428 /* TODO: Test copyScratchpad */
00429 error_code DS28EC20::copyScratchpad(Address targetAddress, uint_least8_t esByte) {
00430   error_code owmResult = selectRom(*master);
00431   if (owmResult) {
00432     return owmResult;
00433   }
00434 
00435   uint_least8_t addressMsb = static_cast<uint_least8_t>(targetAddress >> 8);
00436   uint_least8_t addressLsb = static_cast<uint_least8_t>(targetAddress >> 0);
00437   addressLsb &= ~(pageSizeBytes - 1);
00438 
00439   uint_least8_t block[] = {CopyScratchpad, addressLsb, addressMsb};
00440 
00441   owmResult = master->writeBlock(make_span(block, sizeof(block) / sizeof(block[0])));
00442   if (owmResult) {
00443     return owmResult;
00444   }
00445   owmResult = master->writeByteSetLevel(esByte, OneWireMaster::StrongLevel);
00446   if (owmResult) {
00447     return owmResult;
00448   }
00449   (*sleep)(10);
00450   owmResult = master->setLevel(OneWireMaster::NormalLevel);
00451   if (owmResult) {
00452     return owmResult;
00453   }
00454   owmResult = master->readByte(block[0]);
00455   if (owmResult) {
00456     return owmResult;
00457   }
00458   if (block[0] != 0xAA) {
00459     owmResult = make_error_code(OperationFailure);
00460   }
00461   return owmResult;
00462 }
00463 
00464 const error_category & DS28EC20::errorCategory() {
00465   static class : public error_category {
00466   public:
00467     virtual const char * name() const { return "DS28EC20"; }
00468 
00469     virtual std::string message(int condition) const {
00470       switch (condition) {
00471       case CrcError:
00472         return "CRC Error";
00473 
00474       case OperationFailure:
00475         return "Operation Failure";
00476 
00477       default:
00478         return defaultErrorMessage(condition);
00479       }
00480     }
00481   } instance;
00482   return instance;
00483 }
00484 
00485 } // namespace MaximInterface