diff options
Diffstat (limited to 'python/native/bridge.c')
| -rw-r--r-- | python/native/bridge.c | 720 |
1 files changed, 720 insertions, 0 deletions
diff --git a/python/native/bridge.c b/python/native/bridge.c new file mode 100644 index 0000000..8b2b8da --- /dev/null +++ b/python/native/bridge.c | |||
| @@ -0,0 +1,720 @@ | |||
| 1 | /* | ||
| 2 | Copyright (c) 2012 Ben Croston / 2012-2013 Eric PTAK | ||
| 3 | |||
| 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
| 5 | this software and associated documentation files (the "Software"), to deal in | ||
| 6 | the Software without restriction, including without limitation the rights to | ||
| 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | ||
| 8 | of the Software, and to permit persons to whom the Software is furnished to do | ||
| 9 | so, subject to the following conditions: | ||
| 10 | |||
| 11 | The above copyright notice and this permission notice shall be included in all | ||
| 12 | copies or substantial portions of the Software. | ||
| 13 | |||
| 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 20 | SOFTWARE. | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include "Python.h" | ||
| 24 | #include "gpio.h" | ||
| 25 | #include "cpuinfo.h" | ||
| 26 | |||
| 27 | static PyObject *_SetupException; | ||
| 28 | static PyObject *_InvalidDirectionException; | ||
| 29 | static PyObject *_InvalidChannelException; | ||
| 30 | static PyObject *_InvalidPullException; | ||
| 31 | |||
| 32 | static PyObject *_gpioCount; | ||
| 33 | |||
| 34 | |||
| 35 | static PyObject *_low; | ||
| 36 | static PyObject *_high; | ||
| 37 | |||
| 38 | static PyObject *_in; | ||
| 39 | static PyObject *_out; | ||
| 40 | static PyObject *_alt0; | ||
| 41 | static PyObject *_alt1; | ||
| 42 | static PyObject *_alt2; | ||
| 43 | static PyObject *_alt3; | ||
| 44 | static PyObject *_alt4; | ||
| 45 | static PyObject *_alt5; | ||
| 46 | static PyObject *_pwm; | ||
| 47 | |||
| 48 | static PyObject *_pud_off; | ||
| 49 | static PyObject *_pud_up; | ||
| 50 | static PyObject *_pud_down; | ||
| 51 | |||
| 52 | static PyObject *_board_revision; | ||
| 53 | |||
| 54 | static char* FUNCTIONS[] = {"IN", "OUT", "ALT5", "ALT4", "ALT0", "ALT1", "ALT2", "ALT3", "PWM"}; | ||
| 55 | static char* PWM_MODES[] = {"none", "ratio", "angle"}; | ||
| 56 | |||
| 57 | static int module_state = -1; | ||
| 58 | |||
| 59 | // setup function run on import of the RPi.GPIO module | ||
| 60 | static int module_setup(void) | ||
| 61 | { | ||
| 62 | if (module_state == SETUP_OK) { | ||
| 63 | return SETUP_OK; | ||
| 64 | } | ||
| 65 | |||
| 66 | module_state = setup(); | ||
| 67 | if (module_state == SETUP_DEVMEM_FAIL) | ||
| 68 | { | ||
| 69 | PyErr_SetString(_SetupException, "No access to /dev/mem. Try running as root!"); | ||
| 70 | } else if (module_state == SETUP_MALLOC_FAIL) { | ||
| 71 | PyErr_NoMemory(); | ||
| 72 | } else if (module_state == SETUP_MMAP_FAIL) { | ||
| 73 | PyErr_SetString(_SetupException, "Mmap failed on module import"); | ||
| 74 | } | ||
| 75 | |||
| 76 | return module_state; | ||
| 77 | } | ||
| 78 | |||
| 79 | // python function getFunction(channel) | ||
| 80 | static PyObject *py_get_function(PyObject *self, PyObject *args) | ||
| 81 | { | ||
| 82 | if (module_setup() != SETUP_OK) { | ||
| 83 | return NULL; | ||
| 84 | } | ||
| 85 | |||
| 86 | int channel, f; | ||
| 87 | |||
| 88 | if (!PyArg_ParseTuple(args, "i", &channel)) | ||
| 89 | return NULL; | ||
| 90 | |||
| 91 | if (channel < 0 || channel >= GPIO_COUNT) | ||
| 92 | { | ||
| 93 | PyErr_SetString(_InvalidChannelException, "The GPIO channel is invalid"); | ||
| 94 | return NULL; | ||
| 95 | } | ||
| 96 | |||
| 97 | f = get_function(channel); | ||
| 98 | return Py_BuildValue("i", f); | ||
| 99 | } | ||
| 100 | |||
| 101 | // python function getFunctionString(channel) | ||
| 102 | static PyObject *py_get_function_string(PyObject *self, PyObject *args) | ||
| 103 | { | ||
| 104 | if (module_setup() != SETUP_OK) { | ||
| 105 | return NULL; | ||
| 106 | } | ||
| 107 | |||
| 108 | int channel, f; | ||
| 109 | char *str; | ||
| 110 | |||
| 111 | if (!PyArg_ParseTuple(args, "i", &channel)) | ||
| 112 | return NULL; | ||
| 113 | |||
| 114 | if (channel < 0 || channel >= GPIO_COUNT) | ||
| 115 | { | ||
| 116 | PyErr_SetString(_InvalidChannelException, "The GPIO channel is invalid"); | ||
| 117 | return NULL; | ||
| 118 | } | ||
| 119 | |||
| 120 | f = get_function(channel); | ||
| 121 | str = FUNCTIONS[f]; | ||
| 122 | return Py_BuildValue("s", str); | ||
| 123 | } | ||
| 124 | |||
| 125 | // python function setFunction(channel, direction, pull_up_down=PUD_OFF) | ||
| 126 | static PyObject *py_set_function(PyObject *self, PyObject *args, PyObject *kwargs) | ||
| 127 | { | ||
| 128 | if (module_setup() != SETUP_OK) { | ||
| 129 | return NULL; | ||
| 130 | } | ||
| 131 | |||
| 132 | int channel, function; | ||
| 133 | int pud = PUD_OFF; | ||
| 134 | static char *kwlist[] = {"channel", "function", "pull_up_down", NULL}; | ||
| 135 | |||
| 136 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|i", kwlist, &channel, &function, &pud)) | ||
| 137 | return NULL; | ||
| 138 | |||
| 139 | if (function != IN && function != OUT && function != PWM) | ||
| 140 | { | ||
| 141 | PyErr_SetString(_InvalidDirectionException, "Invalid function"); | ||
| 142 | return NULL; | ||
| 143 | } | ||
| 144 | |||
| 145 | if (function == OUT || function == PWM) | ||
| 146 | pud = PUD_OFF; | ||
| 147 | |||
| 148 | if (pud != PUD_OFF && pud != PUD_DOWN && pud != PUD_UP) | ||
| 149 | { | ||
| 150 | PyErr_SetString(_InvalidPullException, "Invalid value for pull_up_down - should be either PUD_OFF, PUD_UP or PUD_DOWN"); | ||
| 151 | return NULL; | ||
| 152 | } | ||
| 153 | |||
| 154 | if (channel < 0 || channel >= GPIO_COUNT) | ||
| 155 | { | ||
| 156 | PyErr_SetString(_InvalidChannelException, "The GPIO channel is invalid"); | ||
| 157 | return NULL; | ||
| 158 | } | ||
| 159 | |||
| 160 | set_function(channel, function, pud); | ||
| 161 | |||
| 162 | Py_INCREF(Py_None); | ||
| 163 | return Py_None; | ||
| 164 | } | ||
| 165 | |||
| 166 | // python function value = input(channel) | ||
| 167 | static PyObject *py_input(PyObject *self, PyObject *args) | ||
| 168 | { | ||
| 169 | if (module_setup() != SETUP_OK) { | ||
| 170 | return NULL; | ||
| 171 | } | ||
| 172 | |||
| 173 | int channel; | ||
| 174 | |||
| 175 | if (!PyArg_ParseTuple(args, "i", &channel)) | ||
| 176 | return NULL; | ||
| 177 | |||
| 178 | if (channel < 0 || channel >= GPIO_COUNT) | ||
| 179 | { | ||
| 180 | PyErr_SetString(_InvalidChannelException, "The GPIO channel is invalid"); | ||
| 181 | return NULL; | ||
| 182 | } | ||
| 183 | |||
| 184 | if (input(channel)) | ||
| 185 | Py_RETURN_TRUE; | ||
| 186 | else | ||
| 187 | Py_RETURN_FALSE; | ||
| 188 | } | ||
| 189 | |||
| 190 | // python function output(channel, value) | ||
| 191 | static PyObject *py_output(PyObject *self, PyObject *args, PyObject *kwargs) | ||
| 192 | { | ||
| 193 | if (module_setup() != SETUP_OK) { | ||
| 194 | return NULL; | ||
| 195 | } | ||
| 196 | |||
| 197 | int channel, value; | ||
| 198 | static char *kwlist[] = {"channel", "value", NULL}; | ||
| 199 | |||
| 200 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii", kwlist, &channel, &value)) | ||
| 201 | return NULL; | ||
| 202 | |||
| 203 | if (channel < 0 || channel >= GPIO_COUNT) | ||
| 204 | { | ||
| 205 | PyErr_SetString(_InvalidChannelException, "The GPIO channel is invalid"); | ||
| 206 | return NULL; | ||
| 207 | } | ||
| 208 | |||
| 209 | if (get_function(channel) != OUT) | ||
| 210 | { | ||
| 211 | PyErr_SetString(_InvalidDirectionException, "The GPIO channel is not an OUTPUT"); | ||
| 212 | return NULL; | ||
| 213 | } | ||
| 214 | |||
| 215 | output(channel, value); | ||
| 216 | |||
| 217 | Py_INCREF(Py_None); | ||
| 218 | return Py_None; | ||
| 219 | } | ||
| 220 | |||
| 221 | // python function outputSequence(channel, period, sequence) | ||
| 222 | static PyObject *py_output_sequence(PyObject *self, PyObject *args, PyObject *kwargs) | ||
| 223 | { | ||
| 224 | if (module_setup() != SETUP_OK) { | ||
| 225 | return NULL; | ||
| 226 | } | ||
| 227 | |||
| 228 | int channel, period; | ||
| 229 | char* sequence; | ||
| 230 | static char *kwlist[] = {"channel", "period", "sequence", NULL}; | ||
| 231 | |||
| 232 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iis", kwlist, &channel, &period, &sequence)) | ||
| 233 | return NULL; | ||
| 234 | |||
| 235 | if (channel < 0 || channel >= GPIO_COUNT) | ||
| 236 | { | ||
| 237 | PyErr_SetString(_InvalidChannelException, "The GPIO channel is invalid"); | ||
| 238 | return NULL; | ||
| 239 | } | ||
| 240 | |||
| 241 | if (get_function(channel) != OUT) | ||
| 242 | { | ||
| 243 | PyErr_SetString(_InvalidDirectionException, "The GPIO channel is not an OUTPUT"); | ||
| 244 | return NULL; | ||
| 245 | } | ||
| 246 | |||
| 247 | outputSequence(channel, period, sequence); | ||
| 248 | |||
| 249 | Py_INCREF(Py_None); | ||
| 250 | return Py_None; | ||
| 251 | } | ||
| 252 | |||
| 253 | |||
| 254 | static PyObject *py_pulseMilli(PyObject *self, PyObject *args, PyObject *kwargs) | ||
| 255 | { | ||
| 256 | if (module_setup() != SETUP_OK) { | ||
| 257 | return NULL; | ||
| 258 | } | ||
| 259 | |||
| 260 | int channel, function, up, down; | ||
| 261 | static char *kwlist[] = {"channel", "up", "down", NULL}; | ||
| 262 | |||
| 263 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iii", kwlist, &channel, &up, &down)) | ||
| 264 | return NULL; | ||
| 265 | |||
| 266 | if (channel < 0 || channel >= GPIO_COUNT) | ||
| 267 | { | ||
| 268 | PyErr_SetString(_InvalidChannelException, "The GPIO channel is invalid"); | ||
| 269 | return NULL; | ||
| 270 | } | ||
| 271 | |||
| 272 | function = get_function(channel); | ||
| 273 | if ((function != OUT) && (function != PWM)) | ||
| 274 | { | ||
| 275 | PyErr_SetString(_InvalidDirectionException, "The GPIO channel is not an OUTPUT or PWM"); | ||
| 276 | return NULL; | ||
| 277 | } | ||
| 278 | |||
| 279 | pulseMilli(channel, up, down); | ||
| 280 | |||
| 281 | Py_INCREF(Py_None); | ||
| 282 | return Py_None; | ||
| 283 | } | ||
| 284 | |||
| 285 | |||
| 286 | static PyObject *py_pulseMilliRatio(PyObject *self, PyObject *args, PyObject *kwargs) | ||
| 287 | { | ||
| 288 | if (module_setup() != SETUP_OK) { | ||
| 289 | return NULL; | ||
| 290 | } | ||
| 291 | |||
| 292 | int channel, function, width; | ||
| 293 | float ratio; | ||
| 294 | static char *kwlist[] = {"channel", "width", "ratio", NULL}; | ||
| 295 | |||
| 296 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iif", kwlist, &channel, &width, &ratio)) | ||
| 297 | return NULL; | ||
| 298 | |||
| 299 | if (channel < 0 || channel >= GPIO_COUNT) | ||
| 300 | { | ||
| 301 | PyErr_SetString(_InvalidChannelException, "The GPIO channel is invalid"); | ||
| 302 | return NULL; | ||
| 303 | } | ||
| 304 | |||
| 305 | function = get_function(channel); | ||
| 306 | if ((function != OUT) && (function != PWM)) | ||
| 307 | { | ||
| 308 | PyErr_SetString(_InvalidDirectionException, "The GPIO channel is not an OUTPUT or PWM"); | ||
| 309 | return NULL; | ||
| 310 | } | ||
| 311 | |||
| 312 | pulseMilliRatio(channel, width, ratio); | ||
| 313 | |||
| 314 | Py_INCREF(Py_None); | ||
| 315 | return Py_None; | ||
| 316 | } | ||
| 317 | |||
| 318 | |||
| 319 | static PyObject *py_pulseMicro(PyObject *self, PyObject *args, PyObject *kwargs) | ||
| 320 | { | ||
| 321 | if (module_setup() != SETUP_OK) { | ||
| 322 | return NULL; | ||
| 323 | } | ||
| 324 | |||
| 325 | int channel, function, up, down; | ||
| 326 | static char *kwlist[] = {"channel", "up", "down", NULL}; | ||
| 327 | |||
| 328 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iii", kwlist, &channel, &up, &down)) | ||
| 329 | return NULL; | ||
| 330 | |||
| 331 | if (channel < 0 || channel >= GPIO_COUNT) | ||
| 332 | { | ||
| 333 | PyErr_SetString(_InvalidChannelException, "The GPIO channel is invalid"); | ||
| 334 | return NULL; | ||
| 335 | } | ||
| 336 | |||
| 337 | function = get_function(channel); | ||
| 338 | if ((function != OUT) && (function != PWM)) | ||
| 339 | { | ||
| 340 | PyErr_SetString(_InvalidDirectionException, "The GPIO channel is not an OUTPUT or PWM"); | ||
| 341 | return NULL; | ||
| 342 | } | ||
| 343 | |||
| 344 | pulseMicro(channel, up, down); | ||
| 345 | |||
| 346 | Py_INCREF(Py_None); | ||
| 347 | return Py_None; | ||
| 348 | } | ||
| 349 | |||
| 350 | static PyObject *py_pulseMicroRatio(PyObject *self, PyObject *args, PyObject *kwargs) | ||
| 351 | { | ||
| 352 | if (module_setup() != SETUP_OK) { | ||
| 353 | return NULL; | ||
| 354 | } | ||
| 355 | |||
| 356 | int channel, function, width; | ||
| 357 | float ratio; | ||
| 358 | static char *kwlist[] = {"channel", "width", "ratio", NULL}; | ||
| 359 | |||
| 360 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iif", kwlist, &channel, &width, &ratio)) | ||
| 361 | return NULL; | ||
| 362 | |||
| 363 | if (channel < 0 || channel >= GPIO_COUNT) | ||
| 364 | { | ||
| 365 | PyErr_SetString(_InvalidChannelException, "The GPIO channel is invalid"); | ||
| 366 | return NULL; | ||
| 367 | } | ||
| 368 | |||
| 369 | function = get_function(channel); | ||
| 370 | if ((function != OUT) && (function != PWM)) | ||
| 371 | { | ||
| 372 | PyErr_SetString(_InvalidDirectionException, "The GPIO channel is not an OUTPUT or PWM"); | ||
| 373 | return NULL; | ||
| 374 | } | ||
| 375 | |||
| 376 | pulseMicroRatio(channel, width, ratio); | ||
| 377 | |||
| 378 | Py_INCREF(Py_None); | ||
| 379 | return Py_None; | ||
| 380 | } | ||
| 381 | |||
| 382 | static PyObject *py_pulseAngle(PyObject *self, PyObject *args, PyObject *kwargs) | ||
| 383 | { | ||
| 384 | if (module_setup() != SETUP_OK) { | ||
| 385 | return NULL; | ||
| 386 | } | ||
| 387 | |||
| 388 | int channel, function; | ||
| 389 | float angle; | ||
| 390 | static char *kwlist[] = {"channel", "angle", NULL}; | ||
| 391 | |||
| 392 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "if", kwlist, &channel, &angle)) | ||
| 393 | return NULL; | ||
| 394 | |||
| 395 | if (channel < 0 || channel >= GPIO_COUNT) | ||
| 396 | { | ||
| 397 | PyErr_SetString(_InvalidChannelException, "The GPIO channel is invalid"); | ||
| 398 | return NULL; | ||
| 399 | } | ||
| 400 | |||
| 401 | function = get_function(channel); | ||
| 402 | if ((function != OUT) && (function != PWM)) | ||
| 403 | { | ||
| 404 | PyErr_SetString(_InvalidDirectionException, "The GPIO channel is not an OUTPUT or PWM"); | ||
| 405 | return NULL; | ||
| 406 | } | ||
| 407 | |||
| 408 | pulseAngle(channel, angle); | ||
| 409 | |||
| 410 | Py_INCREF(Py_None); | ||
| 411 | return Py_None; | ||
| 412 | } | ||
| 413 | |||
| 414 | static PyObject *py_pulseRatio(PyObject *self, PyObject *args, PyObject *kwargs) | ||
| 415 | { | ||
| 416 | if (module_setup() != SETUP_OK) { | ||
| 417 | return NULL; | ||
| 418 | } | ||
| 419 | |||
| 420 | int channel, function; | ||
| 421 | float ratio; | ||
| 422 | static char *kwlist[] = {"channel", "ratio", NULL}; | ||
| 423 | |||
| 424 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "if", kwlist, &channel, &ratio)) | ||
| 425 | return NULL; | ||
| 426 | |||
| 427 | if (channel < 0 || channel >= GPIO_COUNT) | ||
| 428 | { | ||
| 429 | PyErr_SetString(_InvalidChannelException, "The GPIO channel is invalid"); | ||
| 430 | return NULL; | ||
| 431 | } | ||
| 432 | |||
| 433 | function = get_function(channel); | ||
| 434 | if ((function != OUT) && (function != PWM)) | ||
| 435 | { | ||
| 436 | PyErr_SetString(_InvalidDirectionException, "The GPIO channel is not an OUTPUT or PWM"); | ||
| 437 | return NULL; | ||
| 438 | } | ||
| 439 | |||
| 440 | pulseRatio(channel, ratio); | ||
| 441 | |||
| 442 | Py_INCREF(Py_None); | ||
| 443 | return Py_None; | ||
| 444 | } | ||
| 445 | |||
| 446 | static PyObject *py_pulse(PyObject *self, PyObject *args) | ||
| 447 | { | ||
| 448 | if (module_setup() != SETUP_OK) { | ||
| 449 | return NULL; | ||
| 450 | } | ||
| 451 | |||
| 452 | int channel; | ||
| 453 | |||
| 454 | if (!PyArg_ParseTuple(args, "i", &channel)) | ||
| 455 | return NULL; | ||
| 456 | |||
| 457 | if (channel < 0 || channel >= GPIO_COUNT) | ||
| 458 | { | ||
| 459 | PyErr_SetString(_InvalidChannelException, "The GPIO channel is invalid"); | ||
| 460 | return NULL; | ||
| 461 | } | ||
| 462 | |||
| 463 | pulseRatio(channel, 0.5); | ||
| 464 | return Py_None; | ||
| 465 | } | ||
| 466 | |||
| 467 | static PyObject *py_getPulse(PyObject *self, PyObject *args) | ||
| 468 | { | ||
| 469 | if (module_setup() != SETUP_OK) { | ||
| 470 | return NULL; | ||
| 471 | } | ||
| 472 | |||
| 473 | int channel; | ||
| 474 | char str[256]; | ||
| 475 | struct pulse *p; | ||
| 476 | |||
| 477 | if (!PyArg_ParseTuple(args, "i", &channel)) | ||
| 478 | return NULL; | ||
| 479 | |||
| 480 | if (channel < 0 || channel >= GPIO_COUNT) | ||
| 481 | { | ||
| 482 | PyErr_SetString(_InvalidChannelException, "The GPIO channel is invalid"); | ||
| 483 | return NULL; | ||
| 484 | } | ||
| 485 | |||
| 486 | p = getPulse(channel); | ||
| 487 | |||
| 488 | sprintf(str, "%s:%.2f", PWM_MODES[p->type], p->value); | ||
| 489 | #if PY_MAJOR_VERSION > 2 | ||
| 490 | return PyUnicode_FromString(str); | ||
| 491 | #else | ||
| 492 | return PyString_FromString(str); | ||
| 493 | #endif | ||
| 494 | } | ||
| 495 | |||
| 496 | static PyObject *py_enablePWM(PyObject *self, PyObject *args) | ||
| 497 | { | ||
| 498 | if (module_setup() != SETUP_OK) { | ||
| 499 | return NULL; | ||
| 500 | } | ||
| 501 | |||
| 502 | int channel; | ||
| 503 | |||
| 504 | if (!PyArg_ParseTuple(args, "i", &channel)) | ||
| 505 | return NULL; | ||
| 506 | |||
| 507 | if (channel < 0 || channel >= GPIO_COUNT) | ||
| 508 | { | ||
| 509 | PyErr_SetString(_InvalidChannelException, "The GPIO channel is invalid"); | ||
| 510 | return NULL; | ||
| 511 | } | ||
| 512 | |||
| 513 | enablePWM(channel); | ||
| 514 | return Py_None; | ||
| 515 | } | ||
| 516 | |||
| 517 | static PyObject *py_disablePWM(PyObject *self, PyObject *args) | ||
| 518 | { | ||
| 519 | if (module_setup() != SETUP_OK) { | ||
| 520 | return NULL; | ||
| 521 | } | ||
| 522 | |||
| 523 | int channel; | ||
| 524 | |||
| 525 | if (!PyArg_ParseTuple(args, "i", &channel)) | ||
| 526 | return NULL; | ||
| 527 | |||
| 528 | if (channel < 0 || channel >= GPIO_COUNT) | ||
| 529 | { | ||
| 530 | PyErr_SetString(_InvalidChannelException, "The GPIO channel is invalid"); | ||
| 531 | return NULL; | ||
| 532 | } | ||
| 533 | |||
| 534 | disablePWM(channel); | ||
| 535 | return Py_None; | ||
| 536 | } | ||
| 537 | |||
| 538 | |||
| 539 | |||
| 540 | static PyObject *py_isPWMEnabled(PyObject *self, PyObject *args) | ||
| 541 | { | ||
| 542 | if (module_setup() != SETUP_OK) { | ||
| 543 | return NULL; | ||
| 544 | } | ||
| 545 | |||
| 546 | int channel; | ||
| 547 | |||
| 548 | if (!PyArg_ParseTuple(args, "i", &channel)) | ||
| 549 | return NULL; | ||
| 550 | |||
| 551 | if (channel < 0 || channel >= GPIO_COUNT) | ||
| 552 | { | ||
| 553 | PyErr_SetString(_InvalidChannelException, "The GPIO channel is invalid"); | ||
| 554 | return NULL; | ||
| 555 | } | ||
| 556 | |||
| 557 | if (isPWMEnabled(channel)) | ||
| 558 | Py_RETURN_TRUE; | ||
| 559 | else | ||
| 560 | Py_RETURN_FALSE; | ||
| 561 | } | ||
| 562 | |||
| 563 | PyMethodDef python_methods[] = { | ||
| 564 | {"getFunction", py_get_function, METH_VARARGS, "Return the current GPIO setup (IN, OUT, ALT0)"}, | ||
| 565 | {"getSetup", py_get_function, METH_VARARGS, "Return the current GPIO setup (IN, OUT, ALT0)"}, | ||
| 566 | |||
| 567 | {"getFunctionString", py_get_function_string, METH_VARARGS, "Return the current GPIO setup (IN, OUT, ALT0) as string"}, | ||
| 568 | {"getSetupString", py_get_function_string, METH_VARARGS, "Return the current GPIO setup (IN, OUT, ALT0) as string"}, | ||
| 569 | |||
| 570 | {"setFunction", (PyCFunction)py_set_function, METH_VARARGS | METH_KEYWORDS, "Setup the GPIO channel, direction and (optional) pull/up down control\nchannel - BCM GPIO number\ndirection - IN or OUT\n[pull_up_down] - PUD_OFF (default), PUD_UP or PUD_DOWN"}, | ||
| 571 | {"setup", (PyCFunction)py_set_function, METH_VARARGS | METH_KEYWORDS, "Setup the GPIO channel, direction and (optional) pull/up down control\nchannel - BCM GPIO number\ndirection - IN or OUT\n[pull_up_down] - PUD_OFF (default), PUD_UP or PUD_DOWN"}, | ||
| 572 | |||
| 573 | {"input", py_input, METH_VARARGS, "Input from a GPIO channel - Deprecated, use digitalRead instead"}, | ||
| 574 | {"digitalRead", py_input, METH_VARARGS, "Read a GPIO channel"}, | ||
| 575 | |||
| 576 | {"output", (PyCFunction)py_output, METH_VARARGS | METH_KEYWORDS, "Output to a GPIO channel - Deprecated, use digitalWrite instead"}, | ||
| 577 | {"digitalWrite", (PyCFunction)py_output, METH_VARARGS | METH_KEYWORDS, "Write to a GPIO channel"}, | ||
| 578 | |||
| 579 | {"outputSequence", (PyCFunction)py_output_sequence, METH_VARARGS | METH_KEYWORDS, "Output a sequence to a GPIO channel"}, | ||
| 580 | |||
| 581 | {"getPulse", py_getPulse, METH_VARARGS, "Read current PWM output"}, | ||
| 582 | {"pwmRead", py_getPulse, METH_VARARGS, "Read current PWM output"}, | ||
| 583 | |||
| 584 | {"pulseMilli", (PyCFunction)py_pulseMilli, METH_VARARGS | METH_KEYWORDS, "Output a PWM to a GPIO channel using milliseconds for both HIGH and LOW state widths"}, | ||
| 585 | {"pulseMilliRatio", (PyCFunction)py_pulseMilliRatio, METH_VARARGS | METH_KEYWORDS, "Output a PWM to a GPIO channel using millisecond for the total width and a ratio (duty cycle) for the HIGH state width"}, | ||
| 586 | {"pulseMicro", (PyCFunction)py_pulseMicro, METH_VARARGS | METH_KEYWORDS, "Output a PWM pulse to a GPIO channel using microseconds for both HIGH and LOW state widths"}, | ||
| 587 | {"pulseMicroRatio", (PyCFunction)py_pulseMicroRatio, METH_VARARGS | METH_KEYWORDS, "Output a PWM to a GPIO channel using microseconds for the total width and a ratio (duty cycle) for the HIGH state width"}, | ||
| 588 | |||
| 589 | {"pulseAngle", (PyCFunction)py_pulseAngle, METH_VARARGS | METH_KEYWORDS, "Output a PWM to a GPIO channel using an angle - Deprecated, use pwmWriteAngle instead"}, | ||
| 590 | {"pwmWriteAngle", (PyCFunction)py_pulseAngle, METH_VARARGS | METH_KEYWORDS, "Output a PWM to a GPIO channel using an angle"}, | ||
| 591 | |||
| 592 | {"pulseRatio", (PyCFunction)py_pulseRatio, METH_VARARGS | METH_KEYWORDS, "Output a PWM to a GPIO channel using a ratio (duty cycle) with the default 50Hz signal - Deprecated, use pwmWrite instead"}, | ||
| 593 | {"pwmWrite", (PyCFunction)py_pulseRatio, METH_VARARGS | METH_KEYWORDS, "Output a PWM to a GPIO channel using a ratio (duty cycle) with the default 50Hz signal"}, | ||
| 594 | |||
| 595 | {"pulse", py_pulse, METH_VARARGS, "Output a PWM to a GPIO channel using a 50% ratio (duty cycle) with the default 50Hz signal"}, | ||
| 596 | |||
| 597 | {"enablePWM", py_enablePWM, METH_VARARGS, "Enable software PWM loop for a GPIO channel"}, | ||
| 598 | {"disablePWM", py_disablePWM, METH_VARARGS, "Disable software PWM loop of a GPIO channel"}, | ||
| 599 | {"isPWMEnabled", py_isPWMEnabled, METH_VARARGS, "Returns software PWM state"}, | ||
| 600 | |||
| 601 | {NULL, NULL, 0, NULL} | ||
| 602 | }; | ||
| 603 | |||
| 604 | #if PY_MAJOR_VERSION > 2 | ||
| 605 | static struct PyModuleDef python_module = { | ||
| 606 | PyModuleDef_HEAD_INIT, | ||
| 607 | "_webiopi.GPIO", /* name of module */ | ||
| 608 | NULL, /* module documentation, may be NULL */ | ||
| 609 | -1, /* size of per-interpreter state of the module, | ||
| 610 | or -1 if the module keeps state in global variables. */ | ||
| 611 | python_methods | ||
| 612 | }; | ||
| 613 | #endif | ||
| 614 | |||
| 615 | #if PY_MAJOR_VERSION > 2 | ||
| 616 | PyMODINIT_FUNC PyInit_GPIO(void) | ||
| 617 | #else | ||
| 618 | PyMODINIT_FUNC initGPIO(void) | ||
| 619 | #endif | ||
| 620 | { | ||
| 621 | PyObject *module = NULL; | ||
| 622 | int revision = -1; | ||
| 623 | |||
| 624 | #if PY_MAJOR_VERSION > 2 | ||
| 625 | if ((module = PyModule_Create(&python_module)) == NULL) | ||
| 626 | goto exit; | ||
| 627 | #else | ||
| 628 | if ((module = Py_InitModule("_webiopi.GPIO", python_methods)) == NULL) | ||
| 629 | goto exit; | ||
| 630 | #endif | ||
| 631 | |||
| 632 | _SetupException = PyErr_NewException("_webiopi.GPIO.SetupException", NULL, NULL); | ||
| 633 | PyModule_AddObject(module, "SetupException", _SetupException); | ||
| 634 | |||
| 635 | _InvalidDirectionException = PyErr_NewException("_webiopi.GPIO.InvalidDirectionException", NULL, NULL); | ||
| 636 | PyModule_AddObject(module, "InvalidDirectionException", _InvalidDirectionException); | ||
| 637 | |||
| 638 | _InvalidChannelException = PyErr_NewException("_webiopi.GPIO.InvalidChannelException", NULL, NULL); | ||
| 639 | PyModule_AddObject(module, "InvalidChannelException", _InvalidChannelException); | ||
| 640 | |||
| 641 | _InvalidPullException = PyErr_NewException("_webiopi.GPIO.InvalidPullException", NULL, NULL); | ||
| 642 | PyModule_AddObject(module, "InvalidPullException", _InvalidPullException); | ||
| 643 | |||
| 644 | _gpioCount = Py_BuildValue("i", GPIO_COUNT); | ||
| 645 | PyModule_AddObject(module, "GPIO_COUNT", _gpioCount); | ||
| 646 | |||
| 647 | _low = Py_BuildValue("i", LOW); | ||
| 648 | PyModule_AddObject(module, "LOW", _low); | ||
| 649 | |||
| 650 | _high = Py_BuildValue("i", HIGH); | ||
| 651 | PyModule_AddObject(module, "HIGH", _high); | ||
| 652 | |||
| 653 | _in = Py_BuildValue("i", IN); | ||
| 654 | PyModule_AddObject(module, "IN", _in); | ||
| 655 | |||
| 656 | _out = Py_BuildValue("i", OUT); | ||
| 657 | PyModule_AddObject(module, "OUT", _out); | ||
| 658 | |||
| 659 | _alt0 = Py_BuildValue("i", ALT0); | ||
| 660 | PyModule_AddObject(module, "ALT0", _alt0); | ||
| 661 | |||
| 662 | _alt1 = Py_BuildValue("i", ALT1); | ||
| 663 | PyModule_AddObject(module, "ALT1", _alt1); | ||
| 664 | |||
| 665 | _alt2 = Py_BuildValue("i", ALT2); | ||
| 666 | PyModule_AddObject(module, "ALT2", _alt2); | ||
| 667 | |||
| 668 | _alt3 = Py_BuildValue("i", ALT3); | ||
| 669 | PyModule_AddObject(module, "ALT3", _alt3); | ||
| 670 | |||
| 671 | _alt4 = Py_BuildValue("i", ALT4); | ||
| 672 | PyModule_AddObject(module, "ALT4", _alt4); | ||
| 673 | |||
| 674 | _alt5 = Py_BuildValue("i", ALT5); | ||
| 675 | PyModule_AddObject(module, "ALT5", _alt5); | ||
| 676 | |||
| 677 | _pwm = Py_BuildValue("i", PWM); | ||
| 678 | PyModule_AddObject(module, "PWM", _pwm); | ||
| 679 | |||
| 680 | _pud_off = Py_BuildValue("i", PUD_OFF); | ||
| 681 | PyModule_AddObject(module, "PUD_OFF", _pud_off); | ||
| 682 | |||
| 683 | _pud_up = Py_BuildValue("i", PUD_UP); | ||
| 684 | PyModule_AddObject(module, "PUD_UP", _pud_up); | ||
| 685 | |||
| 686 | _pud_down = Py_BuildValue("i", PUD_DOWN); | ||
| 687 | PyModule_AddObject(module, "PUD_DOWN", _pud_down); | ||
| 688 | |||
| 689 | // detect board revision and set up accordingly | ||
| 690 | revision = get_rpi_revision(); | ||
| 691 | if (revision == -1) | ||
| 692 | { | ||
| 693 | PyErr_SetString(_SetupException, "This module can only be run on a Raspberry Pi!"); | ||
| 694 | #if PY_MAJOR_VERSION > 2 | ||
| 695 | return NULL; | ||
| 696 | #else | ||
| 697 | return; | ||
| 698 | #endif | ||
| 699 | } | ||
| 700 | |||
| 701 | _board_revision = Py_BuildValue("i", revision); | ||
| 702 | PyModule_AddObject(module, "BOARD_REVISION", _board_revision); | ||
| 703 | |||
| 704 | if (Py_AtExit(cleanup) != 0) | ||
| 705 | { | ||
| 706 | cleanup(); | ||
| 707 | #if PY_MAJOR_VERSION > 2 | ||
| 708 | return NULL; | ||
| 709 | #else | ||
| 710 | return; | ||
| 711 | #endif | ||
| 712 | } | ||
| 713 | |||
| 714 | exit: | ||
| 715 | #if PY_MAJOR_VERSION > 2 | ||
| 716 | return module; | ||
| 717 | #else | ||
| 718 | return; | ||
| 719 | #endif | ||
| 720 | } | ||
