Attempting to publish a tree
Dependencies: BLE_API mbed-dev-bin nRF51822
Fork of microbit-dal by
MicroBitPin.cpp
00001 /* 00002 The MIT License (MIT) 00003 00004 Copyright (c) 2016 British Broadcasting Corporation. 00005 This software is provided by Lancaster University by arrangement with the BBC. 00006 00007 Permission is hereby granted, free of charge, to any person obtaining a 00008 copy of this software and associated documentation files (the "Software"), 00009 to deal in the Software without restriction, including without limitation 00010 the rights to use, copy, modify, merge, publish, distribute, sublicense, 00011 and/or sell copies of the Software, and to permit persons to whom the 00012 Software is furnished to do so, subject to the following conditions: 00013 00014 The above copyright notice and this permission notice shall be included in 00015 all copies or substantial portions of the Software. 00016 00017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00018 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00019 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 00020 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00021 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 00022 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 00023 DEALINGS IN THE SOFTWARE. 00024 */ 00025 00026 /** 00027 * Class definition for MicroBitPin. 00028 * 00029 * Commonly represents an I/O pin on the edge connector. 00030 */ 00031 #include "MicroBitConfig.h" 00032 #include "MicroBitPin.h" 00033 #include "MicroBitButton.h" 00034 #include "DynamicPwm.h" 00035 #include "ErrorNo.h" 00036 00037 /** 00038 * Constructor. 00039 * Create a MicroBitPin instance, generally used to represent a pin on the edge connector. 00040 * 00041 * @param id the unique EventModel id of this component. 00042 * 00043 * @param name the mbed PinName for this MicroBitPin instance. 00044 * 00045 * @param capability the capabilities this MicroBitPin instance should have. 00046 * (PIN_CAPABILITY_DIGITAL, PIN_CAPABILITY_ANALOG, PIN_CAPABILITY_TOUCH, PIN_CAPABILITY_AD, PIN_CAPABILITY_ALL) 00047 * 00048 * @code 00049 * MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_ALL); 00050 * @endcode 00051 */ 00052 MicroBitPin::MicroBitPin(int id, PinName name, PinCapability capability) 00053 { 00054 //set mandatory attributes 00055 this->id = id; 00056 this->name = name; 00057 this->capability = capability; 00058 00059 // Power up in a disconnected, low power state. 00060 // If we're unused, this is how it will stay... 00061 this->status = 0x00; 00062 this->pin = NULL; 00063 00064 } 00065 00066 /** 00067 * Disconnect any attached mBed IO from this pin. 00068 * 00069 * Used only when pin changes mode (i.e. Input/Output/Analog/Digital) 00070 */ 00071 void MicroBitPin::disconnect() 00072 { 00073 // This is a bit ugly, but rarely used code. 00074 // It would be much better to use some polymorphism here, but the mBed I/O classes aren't arranged in an inheritance hierarchy... yet. :-) 00075 if (status & IO_STATUS_DIGITAL_IN) 00076 delete ((DigitalIn *)pin); 00077 00078 if (status & IO_STATUS_DIGITAL_OUT) 00079 delete ((DigitalOut *)pin); 00080 00081 if (status & IO_STATUS_ANALOG_IN){ 00082 NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Disabled; // forcibly disable the ADC - BUG in mbed.... 00083 delete ((AnalogIn *)pin); 00084 } 00085 00086 if (status & IO_STATUS_ANALOG_OUT) 00087 { 00088 if(((DynamicPwm *)pin)->getPinName() == name) 00089 ((DynamicPwm *)pin)->release(); 00090 } 00091 00092 if (status & IO_STATUS_TOUCH_IN) 00093 delete ((MicroBitButton *)pin); 00094 00095 this->pin = NULL; 00096 this->status = status & IO_STATUS_EVENTBUS_ENABLED; //retain event bus status 00097 } 00098 00099 /** 00100 * Configures this IO pin as a digital output (if necessary) and sets the pin to 'value'. 00101 * 00102 * @param value 0 (LO) or 1 (HI) 00103 * 00104 * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range, or MICROBIT_NOT_SUPPORTED 00105 * if the given pin does not have digital capability. 00106 * 00107 * @code 00108 * MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH); 00109 * P0.setDigitalValue(1); // P0 is now HI 00110 * @endcode 00111 */ 00112 int MicroBitPin::setDigitalValue(int value) 00113 { 00114 // Check if this pin has a digital mode... 00115 if(!(PIN_CAPABILITY_DIGITAL & capability)) 00116 return MICROBIT_NOT_SUPPORTED; 00117 00118 // Ensure we have a valid value. 00119 if (value < 0 || value > 1) 00120 return MICROBIT_INVALID_PARAMETER; 00121 00122 // Move into a Digital input state if necessary. 00123 if (!(status & IO_STATUS_DIGITAL_OUT)){ 00124 disconnect(); 00125 pin = new DigitalOut(name); 00126 status |= IO_STATUS_DIGITAL_OUT; 00127 } 00128 00129 // Write the value. 00130 ((DigitalOut *)pin)->write(value); 00131 00132 return MICROBIT_OK; 00133 } 00134 00135 /** 00136 * Configures this IO pin as a digital input (if necessary) and tests its current value. 00137 * 00138 * @return 1 if this input is high, 0 if input is LO, or MICROBIT_NOT_SUPPORTED 00139 * if the given pin does not have analog capability. 00140 * 00141 * @code 00142 * MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH); 00143 * P0.getDigitalValue(); // P0 is either 0 or 1; 00144 * @endcode 00145 */ 00146 int MicroBitPin::getDigitalValue() 00147 { 00148 //check if this pin has a digital mode... 00149 if(!(PIN_CAPABILITY_DIGITAL & capability)) 00150 return MICROBIT_NOT_SUPPORTED; 00151 00152 // Move into a Digital input state if necessary. 00153 if (!(status & IO_STATUS_DIGITAL_IN)){ 00154 disconnect(); 00155 pin = new DigitalIn(name,PullDown); 00156 status |= IO_STATUS_DIGITAL_IN; 00157 } 00158 00159 return ((DigitalIn *)pin)->read(); 00160 } 00161 00162 int MicroBitPin::obtainAnalogChannel() 00163 { 00164 // Move into an analogue input state if necessary, if we are no longer the focus of a DynamicPWM instance, allocate ourselves again! 00165 if (!(status & IO_STATUS_ANALOG_OUT) || !(((DynamicPwm *)pin)->getPinName() == name)){ 00166 disconnect(); 00167 pin = (void *)DynamicPwm::allocate(name); 00168 status |= IO_STATUS_ANALOG_OUT; 00169 } 00170 00171 return MICROBIT_OK; 00172 } 00173 00174 /** 00175 * Configures this IO pin as an analog/pwm output, and change the output value to the given level. 00176 * 00177 * @param value the level to set on the output pin, in the range 0 - 1024 00178 * 00179 * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range, or MICROBIT_NOT_SUPPORTED 00180 * if the given pin does not have analog capability. 00181 */ 00182 int MicroBitPin::setAnalogValue(int value) 00183 { 00184 //check if this pin has an analogue mode... 00185 if(!(PIN_CAPABILITY_ANALOG & capability)) 00186 return MICROBIT_NOT_SUPPORTED; 00187 00188 //sanitise the level value 00189 if(value < 0 || value > MICROBIT_PIN_MAX_OUTPUT) 00190 return MICROBIT_INVALID_PARAMETER; 00191 00192 float level = (float)value / float(MICROBIT_PIN_MAX_OUTPUT); 00193 00194 //obtain use of the DynamicPwm instance, if it has changed / configure if we do not have one 00195 if(obtainAnalogChannel() == MICROBIT_OK) 00196 return ((DynamicPwm *)pin)->write(level); 00197 00198 return MICROBIT_OK; 00199 } 00200 00201 /** 00202 * Configures this IO pin as an analog/pwm output (if necessary) and configures the period to be 20ms, 00203 * with a duty cycle between 500 us and 2500 us. 00204 * 00205 * A value of 180 sets the duty cycle to be 2500us, and a value of 0 sets the duty cycle to be 500us by default. 00206 * 00207 * This range can be modified to fine tune, and also tolerate different servos. 00208 * 00209 * @param value the level to set on the output pin, in the range 0 - 180. 00210 * 00211 * @param range which gives the span of possible values the i.e. the lower and upper bounds (center +/- range/2). Defaults to MICROBIT_PIN_DEFAULT_SERVO_RANGE. 00212 * 00213 * @param center the center point from which to calculate the lower and upper bounds. Defaults to MICROBIT_PIN_DEFAULT_SERVO_CENTER 00214 * 00215 * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range, or MICROBIT_NOT_SUPPORTED 00216 * if the given pin does not have analog capability. 00217 */ 00218 int MicroBitPin::setServoValue(int value, int range, int center) 00219 { 00220 //check if this pin has an analogue mode... 00221 if(!(PIN_CAPABILITY_ANALOG & capability)) 00222 return MICROBIT_NOT_SUPPORTED; 00223 00224 //sanitise the servo level 00225 if(value < 0 || range < 1 || center < 1) 00226 return MICROBIT_INVALID_PARAMETER; 00227 00228 //clip - just in case 00229 if(value > MICROBIT_PIN_MAX_SERVO_RANGE) 00230 value = MICROBIT_PIN_MAX_SERVO_RANGE; 00231 00232 //calculate the lower bound based on the midpoint 00233 int lower = (center - (range / 2)) * 1000; 00234 00235 value = value * 1000; 00236 00237 //add the percentage of the range based on the value between 0 and 180 00238 int scaled = lower + (range * (value / MICROBIT_PIN_MAX_SERVO_RANGE)); 00239 00240 return setServoPulseUs(scaled / 1000); 00241 } 00242 00243 /** 00244 * Configures this IO pin as an analogue input (if necessary), and samples the Pin for its analog value. 00245 * 00246 * @return the current analogue level on the pin, in the range 0 - 1024, or 00247 * MICROBIT_NOT_SUPPORTED if the given pin does not have analog capability. 00248 * 00249 * @code 00250 * MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH); 00251 * P0.getAnalogValue(); // P0 is a value in the range of 0 - 1024 00252 * @endcode 00253 */ 00254 int MicroBitPin::getAnalogValue() 00255 { 00256 //check if this pin has an analogue mode... 00257 if(!(PIN_CAPABILITY_ANALOG & capability)) 00258 return MICROBIT_NOT_SUPPORTED; 00259 00260 // Move into an analogue input state if necessary. 00261 if (!(status & IO_STATUS_ANALOG_IN)){ 00262 disconnect(); 00263 pin = new AnalogIn(name); 00264 status |= IO_STATUS_ANALOG_IN; 00265 } 00266 00267 //perform a read! 00268 return ((AnalogIn *)pin)->read_u16(); 00269 } 00270 00271 /** 00272 * Determines if this IO pin is currently configured as an input. 00273 * 00274 * @return 1 if pin is an analog or digital input, 0 otherwise. 00275 */ 00276 int MicroBitPin::isInput() 00277 { 00278 return (status & (IO_STATUS_DIGITAL_IN | IO_STATUS_ANALOG_IN)) == 0 ? 0 : 1; 00279 } 00280 00281 /** 00282 * Determines if this IO pin is currently configured as an output. 00283 * 00284 * @return 1 if pin is an analog or digital output, 0 otherwise. 00285 */ 00286 int MicroBitPin::isOutput() 00287 { 00288 return (status & (IO_STATUS_DIGITAL_OUT | IO_STATUS_ANALOG_OUT)) == 0 ? 0 : 1; 00289 } 00290 00291 /** 00292 * Determines if this IO pin is currently configured for digital use. 00293 * 00294 * @return 1 if pin is digital, 0 otherwise. 00295 */ 00296 int MicroBitPin::isDigital() 00297 { 00298 return (status & (IO_STATUS_DIGITAL_IN | IO_STATUS_DIGITAL_OUT)) == 0 ? 0 : 1; 00299 } 00300 00301 /** 00302 * Determines if this IO pin is currently configured for analog use. 00303 * 00304 * @return 1 if pin is analog, 0 otherwise. 00305 */ 00306 int MicroBitPin::isAnalog() 00307 { 00308 return (status & (IO_STATUS_ANALOG_IN | IO_STATUS_ANALOG_OUT)) == 0 ? 0 : 1; 00309 } 00310 00311 /** 00312 * Configures this IO pin as a "makey makey" style touch sensor (if necessary) 00313 * and tests its current debounced state. 00314 * 00315 * Users can also subscribe to MicroBitButton events generated from this pin. 00316 * 00317 * @return 1 if pin is touched, 0 if not, or MICROBIT_NOT_SUPPORTED if this pin does not support touch capability. 00318 * 00319 * @code 00320 * MicroBitMessageBus bus; 00321 * 00322 * MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_ALL); 00323 * if(P0.isTouched()) 00324 * { 00325 * //do something! 00326 * } 00327 * 00328 * // subscribe to events generated by this pin! 00329 * bus.listen(MICROBIT_ID_IO_P0, MICROBIT_BUTTON_EVT_CLICK, someFunction); 00330 * @endcode 00331 */ 00332 int MicroBitPin::isTouched() 00333 { 00334 //check if this pin has a touch mode... 00335 if(!(PIN_CAPABILITY_TOUCH & capability)) 00336 return MICROBIT_NOT_SUPPORTED; 00337 00338 // Move into a touch input state if necessary. 00339 if (!(status & IO_STATUS_TOUCH_IN)){ 00340 disconnect(); 00341 pin = new MicroBitButton(name, id); 00342 status |= IO_STATUS_TOUCH_IN; 00343 } 00344 00345 return ((MicroBitButton *)pin)->isPressed(); 00346 } 00347 00348 /** 00349 * Configures this IO pin as an analog/pwm output if it isn't already, configures the period to be 20ms, 00350 * and sets the pulse width, based on the value it is given. 00351 * 00352 * @param pulseWidth the desired pulse width in microseconds. 00353 * 00354 * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range, or MICROBIT_NOT_SUPPORTED 00355 * if the given pin does not have analog capability. 00356 */ 00357 int MicroBitPin::setServoPulseUs(int pulseWidth) 00358 { 00359 //check if this pin has an analogue mode... 00360 if(!(PIN_CAPABILITY_ANALOG & capability)) 00361 return MICROBIT_NOT_SUPPORTED; 00362 00363 //sanitise the pulse width 00364 if(pulseWidth < 0) 00365 return MICROBIT_INVALID_PARAMETER; 00366 00367 //Check we still have the control over the DynamicPwm instance 00368 if(obtainAnalogChannel() == MICROBIT_OK) 00369 { 00370 //check if the period is set to 20ms 00371 if(((DynamicPwm *)pin)->getPeriodUs() != MICROBIT_DEFAULT_PWM_PERIOD) 00372 ((DynamicPwm *)pin)->setPeriodUs(MICROBIT_DEFAULT_PWM_PERIOD); 00373 00374 ((DynamicPwm *)pin)->pulsewidth_us(pulseWidth); 00375 } 00376 00377 return MICROBIT_OK; 00378 } 00379 00380 /** 00381 * Configures the PWM period of the analog output to the given value. 00382 * 00383 * @param period The new period for the analog output in microseconds. 00384 * 00385 * @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the 00386 * given pin is not configured as an analog output. 00387 */ 00388 int MicroBitPin::setAnalogPeriodUs(int period) 00389 { 00390 if (!(status & IO_STATUS_ANALOG_OUT)) 00391 return MICROBIT_NOT_SUPPORTED; 00392 00393 return ((DynamicPwm *)pin)->setPeriodUs(period); 00394 } 00395 00396 /** 00397 * Configures the PWM period of the analog output to the given value. 00398 * 00399 * @param period The new period for the analog output in milliseconds. 00400 * 00401 * @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the 00402 * given pin is not configured as an analog output. 00403 */ 00404 int MicroBitPin::setAnalogPeriod(int period) 00405 { 00406 return setAnalogPeriodUs(period*1000); 00407 } 00408 00409 /** 00410 * Obtains the PWM period of the analog output in microseconds. 00411 * 00412 * @return the period on success, or MICROBIT_NOT_SUPPORTED if the 00413 * given pin is not configured as an analog output. 00414 */ 00415 int MicroBitPin::getAnalogPeriodUs() 00416 { 00417 if (!(status & IO_STATUS_ANALOG_OUT)) 00418 return MICROBIT_NOT_SUPPORTED; 00419 00420 return ((DynamicPwm *)pin)->getPeriodUs(); 00421 } 00422 00423 /** 00424 * Obtains the PWM period of the analog output in milliseconds. 00425 * 00426 * @return the period on success, or MICROBIT_NOT_SUPPORTED if the 00427 * given pin is not configured as an analog output. 00428 */ 00429 int MicroBitPin::getAnalogPeriod() 00430 { 00431 return getAnalogPeriodUs()/1000; 00432 }
Generated on Tue Jul 12 2022 19:58:09 by 1.7.2