Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
FlowIq2100.cpp
00001 /* FlowIQ Water Meter HW driver for Water Meter Demo 00002 * 00003 * Copyright (C) u-blox Melbourn Ltd 00004 * u-blox Melbourn Ltd, Melbourn, UK 00005 * 00006 * All rights reserved. 00007 * 00008 * This source file is the sole property of u-blox Melbourn Ltd. 00009 * Reproduction or utilization of this source in whole or part is 00010 * forbidden without the written consent of u-blox Melbourn Ltd. 00011 */ 00012 00013 /** 00014 * @file flowiq_2100.cpp 00015 * This file implements the water meter API to a Kamstrup 00016 * FlowIQ 2100 water meter for the MWC demo 2015. 00017 * 00018 * The meter follows a single subset of the fixed length 00019 * message format defined by the Sensus UI-1203R20 interace. 00020 * The pwrClk line is first toggled from low to high 00021 * a number of times to power up the meter. 00022 * The meter indicates that it is powered up by pulling 00023 * the data line low. What follows is a fixed length 00024 * message, data bits being toggled out of the meter by 00025 * sending the pwrClk line from low to high. Each byte 00026 * is preceded by a low start bit (the first of which 00027 * is the one triggered by the pwrClk operation), seven 00028 * data bits, an even parity bit and a high stop bit. 00029 * There are 25 bytes of message as follows: 00030 * 00031 * 0x56, 'V' Start message 00032 * 0x3B, ';' Start field 00033 * 0x52, 'R' Register field type 00034 * 0x42, 'B' Start numeric data 00035 * 0x30, '0' Volume: 020550019 00036 * 0x32, '2' 00037 * 0x30, '0' 00038 * 0x35, '5' 00039 * 0x35, '5' 00040 * 0x30, '0' 00041 * 0x30, '0' 00042 * 0x31, '1' 00043 * 0x39, '9' 00044 * 0x3B, ';' Start field 00045 * 0x49, 'I' Serial field type 00046 * 0x42, 'B' Start numeric data 00047 * 0x36, '6' Serial: 63268874 00048 * 0x33, '3' 00049 * 0x32, '2' 00050 * 0x36, '6' 00051 * 0x38, '8' 00052 * 0x38, '8' 00053 * 0x37, '7' 00054 * 0x34, '4' 00055 * 0x0D, 'CR' End Message 00056 * 00057 */ 00058 00059 #include <stdint.h> 00060 #include <stdio.h> 00061 #include <mbed.h> 00062 #ifdef TARGET_UBLOX_C027 00063 #include "C027_api.h" 00064 #else 00065 #error "This example is targeted for the C027N platform" 00066 #endif 00067 #include <math.h> // for pow() 00068 #include <WaterMeterApi.hpp> 00069 00070 // ---------------------------------------------------------------- 00071 // GENERAL COMPILE-TIME CONSTANTS 00072 // ---------------------------------------------------------------- 00073 00074 /// The parity the meter uses (if false then it's ODD). 00075 #define PARITY_IS_EVEN true 00076 00077 /// The default clock rate for the meter in Hz 00078 #define METER_DEFAULT_CLOCK_RATE_HZ 1000 00079 00080 /// The length of half a clock period in microseconds used when 00081 // powering up the meter. 00082 #define HALF_CLOCK_PERIOD_PWR_ON_US 1000 00083 00084 /// The maximum number of clocks that are sent to power up the 00085 // meter. 00086 #define MAX_PWR_ON_CLOCKS 10 00087 00088 /// The time for which pwr/clk must be kept low to effect 00089 // a reset of the interface. 00090 #define METER_RESET_PERIOD_US 200000 00091 00092 /// The length of the fixed-length message from the meter. 00093 #define METER_FIXED_MSG_LEN 25 00094 00095 /// The number of characters into the fixed length message that the 00096 // volume reading can be found. 00097 #define VOLUME_READING_OFFSET 4 00098 00099 /// The number of characters in the volume reading. 00100 #define VOLUME_READING_LEN 9 00101 00102 /// The number of characters into the fixed length message that the 00103 // serial number can be found. 00104 #define SERIAL_NUMBER_OFFSET 16 00105 00106 /// The number of characters in the serial number. 00107 #define SERIAL_NUMBER_LEN 8 00108 00109 // ---------------------------------------------------------------- 00110 // PRIVATE VARIABLES 00111 // ---------------------------------------------------------------- 00112 00113 // ---------------------------------------------------------------- 00114 // GENERIC PRIVATE FUNCTIONS 00115 // ---------------------------------------------------------------- 00116 00117 /// Toggle the pwrClk line to wake the meter up, which is 00118 // indicated by the data line going low, the start bit 00119 // (so this function swallows the first start bit). 00120 bool WaterMeterHandler::pwrOn (void) 00121 { 00122 bool success = false; 00123 uint32_t x; 00124 00125 if (ready) 00126 { 00127 // Start things up by pumping the power/clock line until 00128 // the data line goes low or we run out of tries. 00129 if (debug) 00130 { 00131 printf ("\nToggling clock at startup... "); 00132 } 00133 00134 for (x = 0; (*pData == 1) && (x < MAX_PWR_ON_CLOCKS); x++) 00135 { 00136 *pPwrClk = 0; 00137 wait_us (HALF_CLOCK_PERIOD_PWR_ON_US); 00138 *pPwrClk = 1; 00139 wait_us (HALF_CLOCK_PERIOD_PWR_ON_US); 00140 } 00141 00142 if (x < MAX_PWR_ON_CLOCKS) 00143 { 00144 success = true; 00145 if (debug) 00146 { 00147 printf (" success after %d toggle(s).\n", x); 00148 } 00149 } 00150 else 00151 { 00152 if (debug) 00153 { 00154 printf (" failed.\n"); 00155 } 00156 } 00157 } 00158 else 00159 { 00160 printf ("!!! pwrOn(): not initialised, call init() first.\n"); 00161 } 00162 00163 return success; 00164 } 00165 00166 /// Power down the meter interface by setting 00167 // the pwrClk line low. 00168 void WaterMeterHandler::pwrOff (void) 00169 { 00170 if (ready) 00171 { 00172 if (debug) 00173 { 00174 printf ("\nSetting pwrClk low for %d ms to power off meter interface.\n", METER_RESET_PERIOD_US / 1000); 00175 } 00176 00177 *pPwrClk = 0; 00178 } 00179 wait_us (METER_RESET_PERIOD_US); 00180 } 00181 00182 /// Read a start bit from the water meter (should be 0). 00183 bool WaterMeterHandler::readStartBit (void) 00184 { 00185 bool success = false; 00186 00187 if (ready) 00188 { 00189 // Toggle power/clock to get the start bit. 00190 *pPwrClk = 0; 00191 wait_us (halfClkPeriodUs); 00192 *pPwrClk = 1; 00193 wait_us (halfClkPeriodUs); 00194 if (!*pData) 00195 { 00196 success = true; 00197 } 00198 } 00199 else 00200 { 00201 printf ("!!! readStartBit(): not initialised, call init() first.\n"); 00202 } 00203 00204 return success; 00205 } 00206 00207 /// Read a stop bit from the water meter (should be 1). 00208 bool WaterMeterHandler::readStopBit (void) 00209 { 00210 bool success = false; 00211 00212 if (ready) 00213 { 00214 // Toggle power/clock to get the stop bit. 00215 *pPwrClk = 0; 00216 wait_us (halfClkPeriodUs); 00217 *pPwrClk = 1; 00218 wait_us (halfClkPeriodUs); 00219 if (*pData) 00220 { 00221 success = true; 00222 } 00223 } 00224 else 00225 { 00226 printf ("!!! readStopBit(): not initialised, call init() first.\n"); 00227 } 00228 00229 return success; 00230 } 00231 00232 /// Read a bit from the water meter by toggling 00233 // the pwrClk line low and then high. 00234 bool WaterMeterHandler::readDataBit (void) 00235 { 00236 bool bitValue = false; 00237 00238 if (ready) 00239 { 00240 // Toggle power/clock to get a data bit. 00241 *pPwrClk = 0; 00242 wait_us (halfClkPeriodUs); 00243 *pPwrClk = 1; 00244 wait_us (halfClkPeriodUs); 00245 if (*pData) 00246 { 00247 bitValue = true; 00248 } 00249 } 00250 else 00251 { 00252 printf ("!!! readDataBit: not initialised, call init() first.\n"); 00253 } 00254 00255 return bitValue; 00256 } 00257 00258 /// Check that parity is good. 00259 bool WaterMeterHandler::parityIsGood (uint8_t numOnes) 00260 { 00261 bool success = false; 00262 00263 #if PARITY_IS_EVEN 00264 if ((numOnes & 0x01) == 0) 00265 { 00266 success = true; 00267 } 00268 #else 00269 if ((numOnes & 0x01) == 1) 00270 { 00271 success = true; 00272 } 00273 #endif 00274 00275 return success; 00276 } 00277 00278 /// Read a character from the water meter and check parity. 00279 bool WaterMeterHandler::readChar (char *pChar) 00280 { 00281 bool success = false; 00282 bool bitValue; 00283 uint8_t numOnes = 0; 00284 char dataByte = 0; 00285 uint8_t x; 00286 00287 // Read the 7 data bits plus parity 00288 for (x = 0; x < 8; x++) 00289 { 00290 bitValue = readDataBit(); 00291 if (bitValue) 00292 { 00293 numOnes++; // Keep track of this for parity 00294 } 00295 dataByte |= ((bitValue && 0x01) << x); 00296 } 00297 00298 // Mask off the parity bit 00299 dataByte &= 0x7F; 00300 00301 if (debug) 00302 { 00303 printf ("data 0x%.2x ", dataByte); 00304 00305 if ((dataByte & 0x7F) >= 0x20) 00306 { 00307 printf ("(%c) ", dataByte); 00308 } 00309 else 00310 { 00311 printf (" "); 00312 } 00313 } 00314 00315 if (parityIsGood (numOnes)) 00316 { 00317 if (debug) 00318 { 00319 printf ("(parity GOOD) "); 00320 } 00321 00322 success = true; 00323 if (pChar != NULL) 00324 { 00325 *pChar = dataByte; 00326 } 00327 } 00328 else 00329 { 00330 if (debug) 00331 { 00332 printf ("(parity BAD) "); 00333 } 00334 } 00335 00336 return success; 00337 } 00338 00339 /// Read a fixed length message from the water meter. 00340 uint32_t WaterMeterHandler::readFixedLengthMsg (char *pChars, uint32_t numChars) 00341 { 00342 uint32_t x = 0; 00343 00344 // First, power the meter up until we get a start bit 00345 if (pwrOn()) 00346 { 00347 bool dataIsGood = true; 00348 // Now read the data 00349 for (x = 0; (x < numChars) && dataIsGood; x++) 00350 { 00351 if (debug) 00352 { 00353 printf ("Char: %.2d ", x + 1); 00354 } 00355 00356 // Read a data byte with parity 00357 dataIsGood = readChar (&(pChars[x])); 00358 if (dataIsGood) 00359 { 00360 // If parity was good, read a stop bit 00361 dataIsGood = readStopBit(); 00362 if (debug) 00363 { 00364 if (dataIsGood) 00365 { 00366 printf ("StopBit "); 00367 } 00368 else 00369 { 00370 printf (" "); 00371 } 00372 } 00373 00374 if (dataIsGood && (x < numChars - 1)) 00375 { 00376 // If the stop bit was good and we aren't at 00377 // the end, read the next start bit 00378 dataIsGood = readStartBit(); 00379 if (debug) 00380 { 00381 if (dataIsGood) 00382 { 00383 printf ("StartBit \n"); 00384 } 00385 else 00386 { 00387 printf (" \n"); 00388 } 00389 } 00390 } 00391 } 00392 } 00393 } 00394 00395 // Power the meter off afterwards 00396 pwrOff(); 00397 00398 return x; 00399 } 00400 00401 // Convert a series of ASCII numeric characters into a uint32_t value. 00402 bool WaterMeterHandler::decCharsToUint32 (char * pChars, uint32_t numChars, uint32_t * pValue) 00403 { 00404 bool success = true; 00405 double value = 0; 00406 00407 if ((numChars > 0) && (pChars != NULL)) 00408 { 00409 double multiplier; 00410 uint32_t x; 00411 00412 multiplier = pow ((double) 10, double (numChars - 1)); 00413 00414 for (x = 0; (x < numChars) && success; x++) 00415 { 00416 if ((pChars[x] >= 0x30) && (pChars[x] <= 0x39)) 00417 { 00418 value += (pChars[x] - 0x30) * multiplier; 00419 multiplier /= 10; 00420 if (multiplier == 0) 00421 { 00422 multiplier = 1; 00423 } 00424 } 00425 else 00426 { 00427 success = false; 00428 } 00429 } 00430 } 00431 else 00432 { 00433 success = false; 00434 } 00435 00436 if (success && (pValue != NULL)) 00437 { 00438 if (value > 0xFFFFFFFF) 00439 { 00440 success = false; 00441 if (debug) 00442 { 00443 printf ("Result is too big for an uint32_t (%f).\n", value); 00444 } 00445 } 00446 else 00447 { 00448 *pValue = (uint32_t) int (value); 00449 } 00450 } 00451 00452 return success; 00453 } 00454 00455 // ---------------------------------------------------------------- 00456 // PUBLIC FUNCTIONS 00457 // ---------------------------------------------------------------- 00458 00459 /// Constructor 00460 WaterMeterHandler::WaterMeterHandler(void) 00461 { 00462 ready = false; 00463 debug = false; 00464 pData = NULL; 00465 pPwrClk = NULL; 00466 halfClkPeriodUs = (1000000 / METER_DEFAULT_CLOCK_RATE_HZ) / 2; 00467 if (debug) 00468 { 00469 printf ("WaterMeterHandler DEBUG prints are on.\n"); 00470 } 00471 } 00472 00473 /// Destructor 00474 WaterMeterHandler::~WaterMeterHandler(void) 00475 { 00476 ready = false; 00477 pData = NULL; 00478 pPwrClk = NULL; 00479 } 00480 00481 /// Set debug output 00482 void WaterMeterHandler::setDebugOn (bool onNotOff) 00483 { 00484 debug = false; 00485 00486 if (onNotOff) 00487 { 00488 debug = true; 00489 } 00490 00491 if (debug) 00492 { 00493 printf ("\nWaterMeterHandler DEBUG prints are on.\n"); 00494 } 00495 else 00496 { 00497 printf ("\nWaterMeterHandler DEBUG prints are off.\n"); 00498 } 00499 } 00500 00501 /// Initialise the water meter and set alternative 00502 // values for the data/pwrClk pins and the clock 00503 // rate used when reading data. Then read a character 00504 // from the meter to ensure it's there. 00505 bool WaterMeterHandler::init (PinName dataPin, PinName pwrClkPin, uint32_t clkRateHz) 00506 { 00507 // Set context data 00508 pData = new DigitalIn (dataPin); 00509 pPwrClk = new DigitalOut (pwrClkPin); 00510 00511 if (clkRateHz > 1000000) 00512 { 00513 clkRateHz = 1000000; 00514 } 00515 halfClkPeriodUs = (1000000 / clkRateHz) / 2; 00516 00517 ready = true; 00518 // Power up the module and read a character. 00519 if (pwrOn()) 00520 { 00521 if (!readChar (NULL)) 00522 { 00523 ready = false; 00524 } 00525 } 00526 00527 // Power it off again. 00528 pwrOff(); 00529 00530 return ready; 00531 } 00532 00533 /// Take a water volume reading from the meter. 00534 bool WaterMeterHandler::readLitres (uint32_t *pValue) 00535 { 00536 bool success = false; 00537 char buffer[METER_FIXED_MSG_LEN]; 00538 uint32_t charsRead; 00539 00540 if (debug) 00541 { 00542 printf ("Reading volume from meter...\n"); 00543 } 00544 charsRead = readFixedLengthMsg (buffer, sizeof (buffer)); 00545 00546 if (debug) 00547 { 00548 printf ("\n%d byte(s) read of %d needed,\n", charsRead, VOLUME_READING_OFFSET + VOLUME_READING_LEN); 00549 } 00550 00551 if (charsRead >= VOLUME_READING_OFFSET + VOLUME_READING_LEN) 00552 { 00553 if (debug) 00554 { 00555 printf ("Converting %.*s to ", VOLUME_READING_LEN, &(buffer[VOLUME_READING_OFFSET])); 00556 } 00557 00558 success = decCharsToUint32 (&(buffer[VOLUME_READING_OFFSET]), VOLUME_READING_LEN, pValue); 00559 00560 if (debug) 00561 { 00562 if (success) 00563 { 00564 if (pValue != NULL) 00565 { 00566 printf ("%d.\n", *pValue); 00567 } 00568 else 00569 { 00570 printf ("[success].\n"); 00571 } 00572 } 00573 else 00574 { 00575 printf ("[conversion failed].\n"); 00576 } 00577 } 00578 } 00579 00580 return success; 00581 } 00582 00583 /// Read the serial number from the meter. 00584 bool WaterMeterHandler::readSerialNumber (uint32_t *pValue) 00585 { 00586 bool success = false; 00587 char buffer[METER_FIXED_MSG_LEN]; 00588 uint32_t charsRead; 00589 00590 if (debug) 00591 { 00592 printf ("Reading serial number from meter...\n"); 00593 } 00594 charsRead = readFixedLengthMsg (buffer, sizeof (buffer)); 00595 00596 if (debug) 00597 { 00598 printf ("\n%d byte(s) read of %d needed,\n", charsRead, SERIAL_NUMBER_OFFSET + SERIAL_NUMBER_LEN); 00599 } 00600 00601 if (charsRead >= SERIAL_NUMBER_OFFSET + SERIAL_NUMBER_LEN) 00602 { 00603 if (debug) 00604 { 00605 printf ("Converting %.*s to ", SERIAL_NUMBER_LEN, &(buffer[SERIAL_NUMBER_OFFSET])); 00606 } 00607 00608 success = decCharsToUint32 (&(buffer[SERIAL_NUMBER_OFFSET]), SERIAL_NUMBER_LEN, pValue); 00609 00610 if (debug) 00611 { 00612 if (success) 00613 { 00614 if (pValue != NULL) 00615 { 00616 printf ("%d.\n", *pValue); 00617 } 00618 else 00619 { 00620 printf ("[success].\n"); 00621 } 00622 } 00623 else 00624 { 00625 printf ("[conversion failed].\n"); 00626 } 00627 } 00628 } 00629 00630 return success; 00631 } 00632 00633 // End Of File
Generated on Wed Jul 13 2022 16:07:26 by
1.7.2