Module: LGPIO

Defined in:
lib/lgpio.rb,
lib/lgpio/version.rb,
lib/lgpio/infrared.rb,
lib/lgpio/one_wire.rb,
lib/lgpio/i2c_bitbang.rb,
lib/lgpio/spi_bitbang.rb,
lib/lgpio/hardware_pwm.rb,
lib/lgpio/positional_servo.rb,
ext/lgpio/lgpio.c

Defined Under Namespace

Classes: HardwarePWM, I2CBitBang, Infrared, OneWire, PositionalServo, SPIBitBang

Constant Summary collapse

LOW =
0
HIGH =
1
VERSION =
"0.1.11"
SET_ACTIVE_LOW =

Constants

INT2NUM(LG_SET_ACTIVE_LOW)
SET_OPEN_DRAIN =
INT2NUM(LG_SET_OPEN_DRAIN)
SET_OPEN_SOURCE =
INT2NUM(LG_SET_OPEN_SOURCE)
SET_PULL_UP =
INT2NUM(LG_SET_PULL_UP)
SET_PULL_DOWN =
INT2NUM(LG_SET_PULL_DOWN)
SET_PULL_NONE =
INT2NUM(LG_SET_PULL_NONE)
RISING_EDGE =
INT2NUM(LG_RISING_EDGE)
FALLING_EDGE =
INT2NUM(LG_FALLING_EDGE)
BOTH_EDGES =
INT2NUM(LG_BOTH_EDGES)
TX_PWM =

Soft PWM / Wave

INT2NUM(LG_TX_PWM)
TX_WAVE =
INT2NUM(LG_TX_WAVE)

Class Method Summary collapse

Class Method Details

.chip_close(handle) ⇒ Object



58
59
60
61
# File 'ext/lgpio/lgpio.c', line 58

static VALUE chip_close(VALUE self, VALUE handle) {
  int result = lgGpiochipClose(NUM2INT(handle));
  return INT2NUM(result);
}

.chip_open(gpio_dev) ⇒ Object

**************************************************************************



53
54
55
56
# File 'ext/lgpio/lgpio.c', line 53

static VALUE chip_open(VALUE self, VALUE gpio_dev) {
  int result = lgGpiochipOpen(NUM2INT(gpio_dev));
  return INT2NUM(result);
}

.gpio_claim_alert(handle, gpio, flags, eFlags) ⇒ Object



140
141
142
143
# File 'ext/lgpio/lgpio.c', line 140

static VALUE gpio_claim_alert(VALUE self, VALUE handle, VALUE gpio, VALUE flags, VALUE eFlags) {
  int result = lgGpioClaimAlert(NUM2INT(handle), NUM2INT(flags), NUM2INT(eFlags), NUM2INT(gpio), -1);
  return INT2NUM(result);
}

.gpio_claim_input(handle, gpio, flags) ⇒ Object



73
74
75
76
# File 'ext/lgpio/lgpio.c', line 73

static VALUE gpio_claim_input(VALUE self, VALUE handle, VALUE gpio, VALUE flags) {
  int result = lgGpioClaimInput(NUM2INT(handle), NUM2INT(flags), NUM2INT(gpio));
  return INT2NUM(result);
}

.gpio_claim_output(handle, gpio, flags, level) ⇒ Object



68
69
70
71
# File 'ext/lgpio/lgpio.c', line 68

static VALUE gpio_claim_output(VALUE self, VALUE handle, VALUE gpio, VALUE flags, VALUE level) {
  int result = lgGpioClaimOutput(NUM2INT(handle), NUM2INT(flags), NUM2INT(gpio), NUM2INT(level));
  return INT2NUM(result);
}

.gpio_free(handle, gpio) ⇒ Object



78
79
80
81
# File 'ext/lgpio/lgpio.c', line 78

static VALUE gpio_free(VALUE self, VALUE handle, VALUE gpio) {
  int result = lgGpioFree(NUM2INT(handle), NUM2INT(gpio));
  return INT2NUM(result);
}

.gpio_get_mode(handle, gpio) ⇒ Object



63
64
65
66
# File 'ext/lgpio/lgpio.c', line 63

static VALUE gpio_get_mode(VALUE self, VALUE handle, VALUE gpio) {
  int result = lgGpioGetMode(NUM2INT(handle), NUM2INT(gpio));
  return INT2NUM(result);
}

.gpio_get_reportObject



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'ext/lgpio/lgpio.c', line 161

static VALUE gpio_get_report(VALUE self){
  VALUE hash = rb_hash_new();
  bool popped = false;

  pthread_mutex_lock(&queueLock);
  // qWritePos is where the NEXT report will go. Always trail it by 1.
  if (qWritePos - qReadPos != 1){
    qReadPos += 1;
    rb_hash_aset(hash, ID2SYM(rb_intern("timestamp")), ULL2NUM(reportQueue[qReadPos].timestamp));
    rb_hash_aset(hash, ID2SYM(rb_intern("chip")),      UINT2NUM(reportQueue[qReadPos].chip));
    rb_hash_aset(hash, ID2SYM(rb_intern("gpio")),      UINT2NUM(reportQueue[qReadPos].gpio));
    rb_hash_aset(hash, ID2SYM(rb_intern("level")),     UINT2NUM(reportQueue[qReadPos].level));
    rb_hash_aset(hash, ID2SYM(rb_intern("flags")),     UINT2NUM(reportQueue[qReadPos].flags));
    popped = true;
  }
  pthread_mutex_unlock(&queueLock);

  return (popped) ? hash : Qnil;
}

.gpio_read(handle, gpio) ⇒ Object



83
84
85
86
# File 'ext/lgpio/lgpio.c', line 83

static VALUE gpio_read(VALUE self, VALUE handle, VALUE gpio) {
  int result = lgGpioRead(NUM2INT(handle), NUM2INT(gpio));
  return INT2NUM(result);
}

.gpio_read_pulses_us(rbHandle, rbGPIO, rbReset_us, rbResetLevel, rbLimit, rbTimeout_ms) ⇒ Object



502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
# File 'ext/lgpio/lgpio.c', line 502

static VALUE gpio_read_pulses_us(VALUE self, VALUE rbHandle, VALUE rbGPIO, VALUE rbReset_us, VALUE rbResetLevel, VALUE rbLimit, VALUE rbTimeout_ms) {
  // C values
  int handle          = NUM2INT(rbHandle);
  int gpio            = NUM2INT(rbGPIO);
  uint32_t reset_us   = NUM2UINT(rbReset_us);
  uint8_t  resetLevel = NUM2UINT(rbResetLevel);
  uint32_t limit      = NUM2UINT(rbLimit);
  uint64_t timeout_ns = NUM2UINT(rbTimeout_ms) * 1000000;

  // State setup
  uint64_t pulses_ns[limit];
  uint32_t pulseIndex = 0;
  int      gpioState;
  struct timespec start;
  struct timespec lastPulse;
  struct timespec now;

  // Perform reset
  if (reset_us > 0) {
    int result = lgGpioClaimOutput(handle, LG_SET_PULL_NONE, gpio, resetLevel);
    if (result < 0) return NUM2INT(result);
    microDelay(reset_us);
  }

  // Initialize timing
  clock_gettime(CLOCK_MONOTONIC, &start);
  lastPulse = start;
  now       = start;

  // Switch to input and read initial state
  lgGpioClaimInput(handle, LG_SET_PULL_NONE, gpio);
  gpioState = lgGpioRead(handle, gpio);

  // Read pulses in nanoseconds
  while ((nanoDiff(&now, &start) < timeout_ns) && (pulseIndex < limit)) {
    clock_gettime(CLOCK_MONOTONIC, &now);
    if (lgGpioRead(handle, gpio) != gpioState) {
      pulses_ns[pulseIndex] = nanoDiff(&now, &lastPulse);
      lastPulse = now;
      gpioState = gpioState ^ 0b1;
      pulseIndex++;
    }
  }

  // Return Ruby array of pulse as microseconds
  if (pulseIndex == 0) return Qnil;
  VALUE retArray = rb_ary_new2(pulseIndex);
  for(uint32_t i=0; i<pulseIndex; i++){
    uint32_t pulse_us = round(pulses_ns[i] / 1000.0);
    rb_ary_store(retArray, i, UINT2NUM(pulse_us));
  }
  return retArray;
}

.gpio_read_ultrasonic(rbHandle, rbTrigger, rbEcho, rbTriggerTime) ⇒ Object

**************************************************************************



459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
# File 'ext/lgpio/lgpio.c', line 459

static VALUE gpio_read_ultrasonic(VALUE self, VALUE rbHandle, VALUE rbTrigger, VALUE rbEcho, VALUE rbTriggerTime) {
  int handle            = NUM2UINT(rbHandle);
  int trigger           = NUM2UINT(rbTrigger);
  int echo              = NUM2UINT(rbEcho);
  uint32_t triggerTime  = NUM2UINT(rbTriggerTime);
  struct timespec start;
  struct timespec now;
  bool echoSeen = false;

  // Pull down avoids false readings if disconnected.
  lgGpioClaimInput(handle, LG_SET_PULL_DOWN, echo);

  // Initial pulse on the triger pin.
  lgGpioClaimOutput(handle, LG_SET_PULL_NONE, trigger, 0);
  microDelay(5);
  lgGpioWrite(handle, trigger, 1);
  microDelay(triggerTime);
  lgGpioWrite(handle, trigger, 0);

  clock_gettime(CLOCK_MONOTONIC, &start);
  now = start;

  // Wait for echo to go high, up to 25,000 us after trigger.
  while(nanoDiff(&now, &start) < 25000000){
    clock_gettime(CLOCK_MONOTONIC, &now);
    if (lgGpioRead(handle, echo) == 1) {
      echoSeen = true;
      start = now;
      break;
    }
  }
  if (!echoSeen) return Qnil;

  // Wait for echo to go low again, up to 25,000 us after echo start.
  while(nanoDiff(&now, &start) < 25000000){
    clock_gettime(CLOCK_MONOTONIC, &now);
    if (lgGpioRead(handle, echo) == 0) break;
  }

  // High pulse time in microseconds.
  return INT2NUM(round(nanoDiff(&now, &start) / 1000.0));
}

.gpio_set_debounce(handle, gpio, debounce) ⇒ Object

Alerts / Reports



135
136
137
138
# File 'ext/lgpio/lgpio.c', line 135

static VALUE gpio_set_debounce(VALUE self, VALUE handle, VALUE gpio, VALUE debounce) {
  int result =  lgGpioSetDebounce(NUM2INT(handle), NUM2INT(gpio), NUM2INT(debounce));
  return INT2NUM(result);
}

.gpio_start_reportingObject



156
157
158
159
# File 'ext/lgpio/lgpio.c', line 156

static VALUE gpio_start_reporting(VALUE self) {
  lgGpioSetSamplesFunc(queue_gpio_reports, NULL);
  return Qnil;
}

.gpio_write(handle, gpio, level) ⇒ Object



88
89
90
91
# File 'ext/lgpio/lgpio.c', line 88

static VALUE gpio_write(VALUE self, VALUE handle, VALUE gpio, VALUE level) {
  int result = lgGpioWrite(NUM2INT(handle), NUM2INT(gpio), NUM2INT(level));
  return INT2NUM(result);
}

.group_claim_input(handle, gpios, flags) ⇒ Object

Grouped



93
94
95
96
97
98
99
100
101
102
103
# File 'ext/lgpio/lgpio.c', line 93

static VALUE group_claim_input(VALUE self, VALUE handle, VALUE gpios, VALUE flags) {
  Check_Type(gpios, T_ARRAY);
  int count = rb_array_len(gpios);
  int lgGpios[count];
  int i;
  for(i=0; i<count; i++) {
    lgGpios[i] = NUM2INT(rb_ary_entry(gpios, i));
  }
  int result = lgGroupClaimInput(NUM2INT(handle), NUM2INT(flags), count, lgGpios);
  return INT2NUM(result);
}

.group_claim_output(handle, gpios, flags, levels) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'ext/lgpio/lgpio.c', line 105

static VALUE group_claim_output(VALUE self, VALUE handle, VALUE gpios, VALUE flags, VALUE levels) {
  Check_Type(gpios, T_ARRAY);
  int count = rb_array_len(gpios);
  int lgGpios[count];
  int lgLevels[count];
  int i;
  for(i=0; i<count; i++) {
    lgGpios[i]  = NUM2INT(rb_ary_entry(gpios, i));
    lgLevels[i] = NUM2INT(rb_ary_entry(levels, i));
  }
  int result = lgGroupClaimOutput(NUM2INT(handle), NUM2INT(flags), count, lgGpios, lgLevels);
  return INT2NUM(result);
}

.group_free(handle, gpio) ⇒ Object



119
120
121
122
# File 'ext/lgpio/lgpio.c', line 119

static VALUE group_free(VALUE self, VALUE handle, VALUE gpio) {
  int result = lgGroupFree(NUM2INT(handle), NUM2INT(gpio));
  return INT2NUM(result);
}

.group_read(handle, gpio) ⇒ Object



124
125
126
127
128
# File 'ext/lgpio/lgpio.c', line 124

static VALUE group_read(VALUE self, VALUE handle, VALUE gpio) {
  uint64_t result;
  lgGroupRead(NUM2INT(handle), NUM2INT(gpio), &result);
  return UINT2NUM(result);
}

.group_write(handle, gpio, bits, mask) ⇒ Object



130
131
132
133
# File 'ext/lgpio/lgpio.c', line 130

static VALUE group_write(VALUE self, VALUE handle, VALUE gpio, VALUE bits, VALUE mask) {
  int result = lgGroupWrite(NUM2INT(handle), NUM2INT(gpio), NUM2UINT(bits), NUM2UINT(mask));
  return INT2NUM(result);
}

.i2c_bb_read_byte(rbSCL_H, rbSCL_L, rbSDA_H, rbSDA_L, rbACK) ⇒ Object



646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
# File 'ext/lgpio/lgpio.c', line 646

static VALUE i2c_bb_read_byte(VALUE self, VALUE rbSCL_H, VALUE rbSCL_L, VALUE rbSDA_H, VALUE rbSDA_L, VALUE rbACK) {
  int scl_H   = NUM2INT(rbSCL_H);
  int scl_L   = NUM2INT(rbSCL_L);
  int sda_H   = NUM2INT(rbSDA_H);
  int sda_L   = NUM2INT(rbSDA_L);
  uint8_t ack = RTEST(rbACK);

  // Prevent caching by setting opposite to first state SDA will take.
  uint8_t sdaState = 0;
  uint8_t b;
  uint8_t bit;

  // Receive MSB first.
  for (int i=7; i>=0; i--) {
    i2c_bb_set_sda(sda_H, sda_L, &sdaState, 1);
    lgGpioWrite(scl_H, scl_L, 1);
    bit = lgGpioRead(sda_H, sda_L);
    lgGpioWrite(scl_H, scl_L, 0);

    bitWriteU8(&b, i, bit);
  }

  // Send ACK or NACK.
  i2c_bb_set_sda(sda_H, sda_L, &sdaState, ack ^ 0b1);
  lgGpioWrite(scl_H, scl_L, 1);
  lgGpioWrite(scl_H, scl_L, 0);

  return UINT2NUM(b);
}

.i2c_bb_write_byte(rbSCL_H, rbSCL_L, rbSDA_H, rbSDA_L, rbByte) ⇒ Object

Bit-bang I2C Helpers



676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
# File 'ext/lgpio/lgpio.c', line 676

static VALUE i2c_bb_write_byte(VALUE self, VALUE rbSCL_H, VALUE rbSCL_L, VALUE rbSDA_H, VALUE rbSDA_L, VALUE rbByte) {
  int scl_H   = NUM2INT(rbSCL_H);
  int scl_L   = NUM2INT(rbSCL_L);
  int sda_H   = NUM2INT(rbSDA_H);
  int sda_L   = NUM2INT(rbSDA_L);
  uint8_t b   = NUM2UINT(rbByte);

  // Prevent caching by setting opposite to first state SDA will take.
  uint8_t sdaState = bitReadU8(&b, 7) ^ 0b1;
  uint8_t ack;

  // Write MSBFIRST.
  for (int i=7; i>=0; i--) {
    i2c_bb_set_sda(sda_H, sda_L, &sdaState, bitReadU8(&b, i));
    lgGpioWrite(scl_H, scl_L, 1);
    lgGpioWrite(scl_H, scl_L, 0);
  }

  // Read and return ACK.
  i2c_bb_set_sda(sda_H, sda_L, &sdaState, 1);
  lgGpioWrite(scl_H, scl_L, 1);
  ack = lgGpioRead(sda_H, sda_L);
  lgGpioWrite(scl_H, scl_L, 0);
  return (ack == 0) ? Qtrue : Qfalse;
}

.i2c_close(handle) ⇒ Object



282
283
284
285
# File 'ext/lgpio/lgpio.c', line 282

static VALUE i2c_close(VALUE self, VALUE handle){
  int result = lgI2cClose(NUM2INT(handle));
  return INT2NUM(result);
}

.i2c_open(i2cDev, i2cAddr, i2cFlags) ⇒ Object

**************************************************************************



277
278
279
280
# File 'ext/lgpio/lgpio.c', line 277

static VALUE i2c_open(VALUE self, VALUE i2cDev, VALUE i2cAddr, VALUE i2cFlags){
  int handle = lgI2cOpen(NUM2INT(i2cDev), NUM2INT(i2cAddr), NUM2INT(i2cFlags));
  return INT2NUM(handle);
}

.i2c_read_device(handle, count) ⇒ Object



302
303
304
305
306
307
308
309
310
311
312
313
314
# File 'ext/lgpio/lgpio.c', line 302

static VALUE i2c_read_device(VALUE self, VALUE handle, VALUE count){
  int rxCount = NUM2INT(count);
  uint8_t rxBuf[rxCount];

  int result = lgI2cReadDevice(NUM2INT(handle), rxBuf, rxCount);
  if(result < 0) return INT2NUM(result);

  VALUE retArray = rb_ary_new2(rxCount);
  for(int i=0; i<rxCount; i++){
    rb_ary_store(retArray, i, UINT2NUM(rxBuf[i]));
  }
  return retArray;
}

.i2c_write_device(handle, txArray) ⇒ Object



287
288
289
290
291
292
293
294
295
296
297
298
299
300
# File 'ext/lgpio/lgpio.c', line 287

static VALUE i2c_write_device(VALUE self, VALUE handle, VALUE txArray){
  Check_Type(txArray, T_ARRAY);
  int count = rb_array_len(txArray);
  uint8_t txBuf[count];
  VALUE currentByte;
  for(int i=0; i<count; i++){
    currentByte = rb_ary_entry(txArray, i);
    Check_Type(currentByte, T_FIXNUM);
    txBuf[i] = NUM2CHR(currentByte);
  }

  int result = lgI2cWriteDevice(NUM2INT(handle), txBuf, count);
  return INT2NUM(result);
}

.i2c_zip(handle, txArray, rb_rxCount) ⇒ Object



316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
# File 'ext/lgpio/lgpio.c', line 316

static VALUE i2c_zip(VALUE self, VALUE handle, VALUE txArray, VALUE rb_rxCount){
  Check_Type(txArray, T_ARRAY);
  int txCount = rb_array_len(txArray);
  uint8_t txBuf[txCount];
  VALUE currentByte;
  for(int i=0; i<txCount; i++){
    currentByte = rb_ary_entry(txArray, i);
    Check_Type(currentByte, T_FIXNUM);
    txBuf[i] = NUM2CHR(currentByte);
  }

  int rxCount = NUM2INT(rb_rxCount);
  uint8_t rxBuf[rxCount+1];

  // Buffer size must be rxCount+1 or result is LG_BAD_I2C_RLEN
  int result = lgI2cZip(NUM2INT(handle), txBuf, txCount, rxBuf, rxCount+1);
  if(result < 0) return INT2NUM(result);

  if (rxCount == 0) return Qnil;
  VALUE retArray = rb_ary_new2(rxCount);
  for(int i=0; i<rxCount; i++){
    rb_ary_store(retArray, i, UINT2NUM(rxBuf[i]));
  }
  return retArray;
}

.micro_delay(micros) ⇒ Object

Generic Helpers



45
46
47
48
# File 'ext/lgpio/lgpio.c', line 45

static VALUE rbMicroDelay(VALUE self, VALUE micros) {
  microDelay(NUM2ULL(micros));
  return Qnil;
}

.one_wire_bit_read(rbHandle, rbGPIO) ⇒ Object

**************************************************************************



559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
# File 'ext/lgpio/lgpio.c', line 559

static VALUE one_wire_bit_read(VALUE self, VALUE rbHandle, VALUE rbGPIO) {
  int handle  = NUM2INT(rbHandle);
  int gpio    = NUM2INT(rbGPIO);
  uint8_t bit = 1;
  struct timespec start;
  struct timespec now;

  // Start the read slot.
  lgGpioWrite(handle, gpio, 0);
  microDelay(1);
  lgGpioWrite(handle, gpio, 1);

  // Poll for 60us to see if pin goes low.
  clock_gettime(CLOCK_MONOTONIC, &start);
  now = start;
  while(nanoDiff(&now, &start) < 60000){
    if (lgGpioRead(handle, gpio) == 0) bit = 0;
    clock_gettime(CLOCK_MONOTONIC, &now);
  }
  return UINT2NUM(bit);
}

.one_wire_bit_write(rbHandle, rbGPIO, rbBit) ⇒ Object



581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
# File 'ext/lgpio/lgpio.c', line 581

static VALUE one_wire_bit_write(VALUE self, VALUE rbHandle, VALUE rbGPIO, VALUE rbBit) {
  int handle  = NUM2INT(rbHandle);
  int gpio    = NUM2INT(rbGPIO);
  uint8_t bit = NUM2CHR(rbBit);

  // Write slot starts by going low for at least 1us.
  lgGpioWrite(handle, gpio, 0);
  microDelay(1);

  // If 0, keep it low for the rest of the 60us write slot, then release.
  if (bit == 0) {
    microDelay(59);
    lgGpioWrite(handle, gpio, 1);
  // If 1, release first, then wait the rest of the 60us slot.
  } else {
    lgGpioWrite(handle, gpio, 1);
    microDelay(59);
  }
  // Minimum 1us recovery time after each slot.
  microDelay(1);
  return Qnil;
}

.one_wire_reset(rbHandle, rbGPIO) ⇒ Object



604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
# File 'ext/lgpio/lgpio.c', line 604

static VALUE one_wire_reset(VALUE self, VALUE rbHandle, VALUE rbGPIO) {
  int handle = NUM2INT(rbHandle);
  int gpio   = NUM2INT(rbGPIO);
  struct timespec start;
  uint8_t presence = 1;

  // Hold low for 500us to reset, then go high.
  lgGpioFree(handle, gpio);
  lgGpioClaimOutput(handle, LG_SET_OPEN_DRAIN | LG_SET_PULL_UP, gpio, 0);
  microDelay(500);
  lgGpioWrite(handle, gpio, 1);

  // Poll for 250us. If a device pulls the line low, return 0 (device present).
  clock_gettime(CLOCK_MONOTONIC, &start);
  while(nanosSince(&start) < 250000){
    if (lgGpioRead(handle, gpio) == 0) presence = 0;
  }

  return UINT2NUM(presence);
}

.spi_close(handle) ⇒ Object



350
351
352
353
# File 'ext/lgpio/lgpio.c', line 350

static VALUE spi_close(VALUE self, VALUE handle){
  int result = lgSpiClose(NUM2INT(handle));
  return INT2NUM(result);
}

.spi_open(spiDev, spiChan, spiBaud, spiFlags) ⇒ Object

**************************************************************************



345
346
347
348
# File 'ext/lgpio/lgpio.c', line 345

static VALUE spi_open(VALUE self, VALUE spiDev, VALUE spiChan, VALUE spiBaud, VALUE spiFlags){
  int handle = lgSpiOpen(NUM2INT(spiDev), NUM2INT(spiChan), NUM2INT(spiBaud), NUM2INT(spiFlags));
  return INT2NUM(handle);
}

.spi_read(handle, rxCount) ⇒ Object



355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
# File 'ext/lgpio/lgpio.c', line 355

static VALUE spi_read(VALUE self, VALUE handle, VALUE rxCount){
  int count = NUM2INT(rxCount);

  // Not sure if this needs null termination like I2C. +1 won't hurt.
  uint8_t rxBuf[count+1];

  int result = lgSpiRead(NUM2INT(handle), rxBuf, count);
  if(result < 0) return INT2NUM(result);

  VALUE retArray = rb_ary_new2(count);
  for(int i=0; i<count; i++){
    rb_ary_store(retArray, i, UINT2NUM(rxBuf[i]));
  }
  return retArray;
}

.spi_write(handle, txArray) ⇒ Object



371
372
373
374
375
376
377
378
379
380
381
382
383
384
# File 'ext/lgpio/lgpio.c', line 371

static VALUE spi_write(VALUE self, VALUE handle, VALUE txArray){
  Check_Type(txArray, T_ARRAY);
  int count = rb_array_len(txArray);
  uint8_t txBuf[count];
  VALUE currentByte;
  for(int i=0; i<count; i++){
    currentByte = rb_ary_entry(txArray, i);
    Check_Type(currentByte, T_FIXNUM);
    txBuf[i] = NUM2CHR(currentByte);
  }

  int result = lgSpiWrite(NUM2INT(handle), txBuf, count);
  return INT2NUM(result);
}

.spi_ws2812_write(handle, pixelArray) ⇒ Object



419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
# File 'ext/lgpio/lgpio.c', line 419

static VALUE spi_ws2812_write(VALUE self, VALUE handle, VALUE pixelArray){
  Check_Type(pixelArray, T_ARRAY);
  int count = rb_array_len(pixelArray);

  // Pull low for at least one byte at 2.4 Mhz before data, and 90 after.
  int zeroesBefore = 1;
  int zeroesAfter  = 90;
  int txBufLength  = zeroesBefore + (count*3) + zeroesAfter;
  uint8_t txBuf[txBufLength];
  for (int i=0; i<txBufLength; i++) { txBuf[i] = 0; }

  VALUE    currentByte_rb;
  uint8_t  currentByte;
  uint8_t  currentBit;
  uint32_t temp;

  for (int i=0; i<count; i++){
    temp = 0;
    currentByte_rb = rb_ary_entry(pixelArray, i);
    Check_Type(currentByte_rb, T_FIXNUM);
    currentByte = NUM2CHR(currentByte_rb);

    for (int i=7; i>=0; i--) {
      currentBit = (currentByte & (1 << i));
      temp = temp << 3;
      temp = (currentBit == 0) ? (temp | 0b100) : (temp | 0b110);
    }

    txBuf[zeroesBefore+(i*3)]   = (temp >> 16) & 0xFF;
    txBuf[zeroesBefore+(i*3)+1] = (temp >> 8) & 0xFF;
    txBuf[zeroesBefore+(i*3)+2] = temp & 0xFF;
  }

  int result = lgSpiWrite(NUM2INT(handle), txBuf, txBufLength);
  return INT2NUM(result);
}

.spi_xfer(handle, txArray, rxLength) ⇒ Object



386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
# File 'ext/lgpio/lgpio.c', line 386

static VALUE spi_xfer(VALUE self, VALUE handle, VALUE txArray, VALUE rxLength){
  Check_Type(txArray, T_ARRAY);
  int txCount = rb_array_len(txArray);
  int rxCount = NUM2INT(rxLength);
  int count   = txCount;
  if (rxCount > txCount) count = rxCount;

  uint8_t txBuf[count];
  // Not sure if this needs null termination like I2C. +1 won't hurt.
  uint8_t rxBuf[count+1];

  // Add given bytes to transmit.
  VALUE currentByte;
  for(int i=0; i<txCount; i++){
    currentByte = rb_ary_entry(txArray, i);
    Check_Type(currentByte, T_FIXNUM);
    txBuf[i] = NUM2CHR(currentByte);
  }
  // Extend with zeroes if reading more than writing.
  if (count > txCount) {
    for(int i=txCount; i<count; i++) txBuf[i] = 0;
  }

  int result = lgSpiXfer(NUM2INT(handle), txBuf, rxBuf, count);
  if(result < 0) return INT2NUM(result);

  VALUE retArray = rb_ary_new2(rxCount);
  for(int i=0; i<rxCount; i++){
    rb_ary_store(retArray, i, UINT2NUM(rxBuf[i]));
  }
  return retArray;
}

.tx_busy(handle, gpio, kind) ⇒ Object

**************************************************************************



184
185
186
187
# File 'ext/lgpio/lgpio.c', line 184

static VALUE tx_busy(VALUE self, VALUE handle, VALUE gpio, VALUE kind) {
  int result = lgTxBusy(NUM2INT(handle), NUM2INT(gpio), NUM2INT(kind));
  return INT2NUM(result);
}

.tx_pulse(handle, gpio, on, off, offset, cycles) ⇒ Object



194
195
196
197
# File 'ext/lgpio/lgpio.c', line 194

static VALUE tx_pulse(VALUE self, VALUE handle, VALUE gpio, VALUE on, VALUE off, VALUE offset, VALUE cycles) {
  int result = lgTxPulse(NUM2INT(handle), NUM2INT(gpio), NUM2INT(on), NUM2INT(off), NUM2INT(offset), NUM2INT(cycles));
  return INT2NUM(result);
}

.tx_pwm(handle, gpio, freq, duty, offset, cycles) ⇒ Object



199
200
201
202
# File 'ext/lgpio/lgpio.c', line 199

static VALUE tx_pwm(VALUE self, VALUE handle, VALUE gpio, VALUE freq, VALUE duty, VALUE offset, VALUE cycles) {
  int result = lgTxPwm(NUM2INT(handle), NUM2INT(gpio), NUM2INT(freq), NUM2DBL(duty), NUM2INT(offset), NUM2INT(cycles));
  return INT2NUM(result);
}

.tx_room(handle, gpio, kind) ⇒ Object



189
190
191
192
# File 'ext/lgpio/lgpio.c', line 189

static VALUE tx_room(VALUE self, VALUE handle, VALUE gpio, VALUE kind) {
  int result = lgTxRoom(NUM2INT(handle), NUM2INT(gpio), NUM2INT(kind));
  return INT2NUM(result);
}

.tx_servo(handle, gpio, width, freq, offset, cycles) ⇒ Object

Don’t use this. Servo will jitter.



204
205
206
207
# File 'ext/lgpio/lgpio.c', line 204

static VALUE tx_servo(VALUE self, VALUE handle, VALUE gpio, VALUE width, VALUE freq, VALUE offset, VALUE cycles) {
  int result = lgTxServo(NUM2INT(handle), NUM2INT(gpio), NUM2INT(width), NUM2INT(freq), NUM2INT(offset), NUM2INT(cycles));
  return INT2NUM(result);
}

.tx_wave(handle, lead_gpio, pulses) ⇒ Object



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'ext/lgpio/lgpio.c', line 209

static VALUE tx_wave(VALUE self, VALUE handle, VALUE lead_gpio, VALUE pulses) {
  // Copy Ruby array to array of lgPulse_t.
  Check_Type(pulses, T_ARRAY);
  int       pulseCount = rb_array_len(pulses);
  lgPulse_t pulsesOut[pulseCount];
  VALUE     rbPulse;
  int       i;
  for(i=0; i<pulseCount; i++) {
    rbPulse            = rb_ary_entry(pulses, i);
    pulsesOut[i].bits  = NUM2UINT(rb_ary_entry(rbPulse, 0));
    pulsesOut[i].mask  = NUM2UINT(rb_ary_entry(rbPulse, 1));
    pulsesOut[i].delay = NUM2INT (rb_ary_entry(rbPulse, 2));
  }

  // Add it to wave queue.
  int result = lgTxWave(NUM2INT(handle), NUM2INT(lead_gpio), pulseCount, pulsesOut);
  return INT2NUM(result);
}