module main
author unknown
version 1 0 
description ''


module 'Gesture (PAJ7620)' Input
author 'José García'
version 1 0 
tags sensor gesture 
description 'Support for PAJ7620 gesture sensor.
The "read" block returns the name of the detected gesture.
Based on github.com/Seeed-Studio/Gesture_PAJ7620'
variables '_paj7620 initialized' 

  spec 'r' 'paj7620 read' 'paj7620 read'
  spec ' ' '_paj7620 setup' '_paj7620 setup'
  spec 'r' 'paj7620 connected' 'paj7620 connected'
  spec ' ' '_paj7620 setup bank0' '_paj7620 setup bank0'
  spec ' ' '_paj7620 setup bank1' '_paj7620 setup bank1'

to '_paj7620 setup' {
  if ('paj7620 connected') {
    '_paj7620 setup bank0'
    '_paj7620 setup bank1'
    i2cSet (hexToInt '73') (hexToInt '65') (hexToInt '12')
    i2cSet (hexToInt '73') (hexToInt 'EF') 0
    '_paj7620 initialized' = 1
  }
}

to '_paj7620 setup bank0' {
  i2cSet (hexToInt '73') (hexToInt 'EF') 0
  local 'i' 1
  local 'list' '3229
3301
3400
3501
3600
3707
3817
3906
3A12
3F00
4002
41FF
4201
462D
470F
483C
4900
4A1E
4B00
4C20
4D00
4E1A
4F14
5000
5110
5200
5C02
5D00
5E10
5F3F
6027
6128
6200
6303
64F7
6503
66D9
6703
6801
69C8
6A40
6D04
6E00
6F00
7080
7100
7200
7300
74F0
7500
8042
8144
8204
8320
8420
8500
8610
8700
8805
8918
8A10
8B01
8C37
8D00
8EF0
8F81
9006
9106
921E
930D
940A
950A
960C
9705
980A
9941
9A14
9B0A
9C3F
9D33
9EAE
9FF9
A048
A113
A210
A308
A430
A519
A610
A708
A824
A904
AA1E
AB1E
CC19
CD0B
CE13
CF64
D021
D10F
D288
E001
E104
E241
E3D6
E400
E50C
E60A
E700
E800
E900
EE07'
  repeatUntil (i > (size list)) {
    local 'reg' ('[data:copyFromTo]' list i (i + 1))
    local 'val' ('[data:copyFromTo]' list (i + 2) (i + 4))
    i2cSet (hexToInt '73') (hexToInt reg) (hexToInt val)
    i += 5
    waitMicros 10
  }
}

to '_paj7620 setup bank1' {
  i2cSet (hexToInt '73') (hexToInt 'EF') 1
  local 'i' 1
  local 'list' '001E
011E
020F
0310
0402
0500
06B0
0704
080D
090E
0A9C
0B04
0C05
0D0F
0E02
0F12
1002
1102
1200
1301
1405
1507
1605
1707
1801
1904
1A05
1B0C
1C2A
1D01
1E00
2100
2200
2300
2501
2600
2739
287F
2908
3003
3100
321A
331A
3407
3507
3601
37FF
3836
3907
3A00
3EFF
3F00
4077
4140
4200
4330
44A0
455C
4600
4700
4858
4A1E
4B1E
4C00
4D00
4EA0
4F80
5000
5100
5200
5300
5400
5780
5910
5A08
5B94
5CE8
5D08
5E3D
5F99
6045
6140
632D
6402
6596
6600
6797
6801
69CD
6A01
6BB0
6C04
6D2C
6E01
6F32
7100
7201
7335
7400
7533
7631
7701
7C84
7D03
7E01'
  repeatUntil (i > (size list)) {
    local 'reg' ('[data:copyFromTo]' list i (i + 1))
    local 'val' ('[data:copyFromTo]' list (i + 2) (i + 4))
    i2cSet (hexToInt '73') (hexToInt reg) (hexToInt val)
    i += 5
    waitMicros 10
  }
}

to 'paj7620 connected' {
  return (and ((i2cGet (hexToInt '73') 0) == 32) ((i2cGet (hexToInt '73') 1) == 118))
}

to 'paj7620 read' {
  if ((v '_paj7620 initialized') == 0) {'_paj7620 setup'}
  local 'msg' '?'
  local 'g' (i2cGet (hexToInt '73') (hexToInt '43'))
  if ((g & 1) != 0) {
    msg = 'right'
  } ((g & 2) != 0) {
    msg = 'left'
  } ((g & 4) != 0) {
    msg = 'up'
  } ((g & 8) != 0) {
    msg = 'down'
  } ((g & 16) != 0) {
    msg = 'fordward'
  } ((g & 32) != 0) {
    msg = 'backward'
  } ((g & 64) != 0) {
    msg = 'clockwise'
  } ((g & 128) != 0) {
    msg = 'anti-clockwise'
  }
  return msg
}


module Servo Output
author MicroBlocks
version 1 4 
tags servo motor angle rotation position 
description 'Control both positional (angle) and rotational servo motors.
'
variables _servoPin _servoPulseWidth 

  spec ' ' 'setServoAngle' 'set servo _ to _ degrees (-90 to 90)' 'num num' 1 90
  spec ' ' 'setServoSpeed' 'set servo _ to speed _ (-100 to 100)' 'num num' 1 100
  spec ' ' 'stopServo' 'stop servo _' 'num' 1
  spec 'r' '_servoIndex' '_servoIndex _' 'num' 1
  spec ' ' '_servoPulse' '_servoPulse pin _ usecs _' 'num num' 1 1500
  spec ' ' '_servoUpdateLoop' '_servoUpdateLoop'

to '_servoIndex' which {
  if (_servoPin == 0) {
    _servoPin = ('[data:makeList]')
    _servoPulseWidth = ('[data:makeList]')
    sendBroadcast '_servoUpdateLoop'
  }
  local 'i' ('[data:find]' which _servoPin)
  if (i < 0) {
    comment 'Add new pin'
    '[data:addLast]' which _servoPin
    '[data:addLast]' 1500 _servoPulseWidth
    i = (size _servoPin)
  }
  return i
}

to '_servoPulse' pin usecs {
  if (usecs == 0) {
    comment 'Servo stopped; do nothing'
    return 0
  }
  usecs = (maximum 500 (minimum usecs 2900))
  comment 'Split wait into a long wait followed by a wait of <= 30 usecs for greater accuracy'
  local 'endTime' ((microsOp) + usecs)
  digitalWriteOp pin true
  waitMicros (usecs - 30)
  waitMicros (endTime - (microsOp))
  digitalWriteOp pin false
}

to '_servoUpdateLoop' {
  forever {
    if (_servoPin != 0) {
      comment 'If the _servoPin list is not 0, update the servos'
      for i (size _servoPin) {
        local 'pin' (at i _servoPin)
        local 'usecs' (at i _servoPulseWidth)
        if (and (pin >= 0) (usecs != 0)) {
          '_servoPulse' pin usecs
        }
      }
      waitMillis 15
    }
  }
}

to setServoAngle which degrees optionalReverse {
  local 'reversed' false
  if ((pushArgCount) > 2) {
    reversed = optionalReverse
  }
  if reversed {
    degrees = (0 - degrees)
  }
  local 'pulseWidth' (1500 - (10 * degrees))
  if ('[io:hasServo]') {
    '[io:setServo]' which pulseWidth
  } else {
    atPut ('_servoIndex' which) _servoPulseWidth pulseWidth
  }
}

to setServoSpeed which speed optionalReverse {
  local 'reversed' false
  if ((pushArgCount) > 2) {
    reversed = optionalReverse
  }
  if reversed {
    speed = (0 - speed)
  }
  local 'pulseWidth' (1500 - (10 * speed))
  if ((absoluteValue speed) < 2) {
    pulseWidth = 0
  }
  if ('[io:hasServo]') {
    '[io:setServo]' which pulseWidth
  } else {
    atPut ('_servoIndex' which) _servoPulseWidth pulseWidth
  }
}

to stopServo which {
  if ('[io:hasServo]') {
    '[io:setServo]' which 0
  } else {
    atPut ('_servoIndex' which) _servoPulseWidth 0
  }
}


module Spark Input
author 'FABLAB BH credits Turgut for the OLED Graphics'
version 1 1 
depends '/Spark_Digital' '/Spark_Analog' '/Spark_MP' '/Spark_PWM' '/Spark_I2C' 
choices DispTypeMenu 'OLED_0.96in' 'OLED_2.42in' 
choices OnOffMenu On Off 
choices VideoMenu Inverse Normal 
choices ModeMenu Horizontal Vertical 
description 'Supports 0.96in and 2.42in OLED Displays with SD1306 and SD1309 chipsets. Comm mode is I2C or SPI.
Changes:
- always display buffer
- defer display updates block
- remove reveal
- switch to x (0-127), y (0-63)
- Pruned commands and vars
- textX and textY
- Text at any x and y
- handles newLines
- removed dependencies
- unified data format for chars, sprites, and images
- image draw at any x,y
- filled rectangle
- image draw bug fix
- stack overflow fix
- improve conversion ops, i2c io, rect fill, img processing, and buffer displays
- reduce i2c buffer to 128 bytes
- reduce i2c buffer to 64 bytes
- correct internal draws, clean-up vars, restore _clearDisplay
'
variables OLEDReady OLEDi2cAddr _GDBuffer _cDecTBL _comma _cTABLE _comMode _dcPin _delayGDUpd _displayType _eol _resetPin _textX _textY _dataPrefix _byteCount _imgData _imgWidth _imgHeight 

  spec ' ' 'OLEDInit_I2C' 'initialize i2c _ address(hex) _ reset pin# _ flip _' 'str.DispTypeMenu auto str bool' 'OLED_0.96in' '3C' '-' false
  spec ' ' 'OLEDInit_SPI' 'initialize spi _ d/c pin# _ reset pin# _ flip _' 'str.DispTypeMenu auto auto bool' 'OLED_2.42in' 16 8 false
  spec ' ' 'OLEDwrite' 'write _ at x _ y _ inverse _' 'auto auto auto bool' 'Hello!' 0 0 false
  spec ' ' 'OLEDshowGDBuffer' 'show display buffer'
  spec ' ' 'OLEDclear' 'clear'
  spec ' ' 'OLEDcontrast' 'set contrast (1-4) _' 'auto' 2
  spec ' ' 'OLEDdrawCircle' 'draw circle at x _ y _ radius _ erase _' 'auto auto auto bool' 64 32 '10' false
  spec ' ' 'OLEDdrawImage' 'draw image _ at x _ y _' 'auto auto auto' 0 0 0
  spec ' ' 'OLEDdrawLine' 'draw line from x _ y _ to x _ y _ erase _' 'auto auto auto auto bool' 0 0 127 63 false
  spec ' ' 'OLEDdrawRect' 'draw rectangle x _ y _ w _ h _ erase _ rounding(3-15) _' 'auto auto auto auto bool auto' 0 0 127 63 false 0
  spec ' ' 'OLEDfillRect' 'fill rectangle x _ y _ w _ h _ erase _' 'auto auto auto auto bool' 20 20 30 20 false
  spec ' ' '_OLEDflip' '_flip display top _' 'bool' false
  spec 'r' 'OLEDmakeImage' 'make image _' 'microbitDisplay' 33084991
  spec ' ' 'OLEDpixel' 'set pixel x _ y _ erase _' 'auto auto bool' 0 0 false
  spec ' ' 'OLEDsetVideo' 'set video _' 'str.VideoMenu' 'Inverse'
  spec 'r' 'OLEDwru' 'cursor location'
  spec ' ' 'defer display updates' 'defer display updates'
  spec ' ' '_GDDRAMoff' '_GDDRAMoff'
  spec ' ' '_GDDRAMon' '_GDDRAMon'
  spec ' ' '_OLEDcursorReset' '_cursor reset'
  spec ' ' '_OLEDsetDisplay' '_set display _' 'str.OnOffMenu' 'On'
  spec ' ' '_OLEDreset' '_set reset Pin# _' 'auto' '0'
  spec ' ' '_SPIWriteCmd' '_SPIWriteCmd'
  spec ' ' '_SPIWriteData' '_SPIWriteData'
  spec ' ' '_T1' '_T1'
  spec ' ' '_T2' '_T2'
  spec ' ' '_T3' '_T3'
  spec 'r' '_cBMP' '_cBMP _ InvYN _' 'auto bool' '' false
  spec ' ' '_clearDisplay' '_clearDisplay'
  spec ' ' '_corner' '_corner _ _ _ _ _' 'auto auto auto auto bool' 'TL' 32 1 0 true
  spec 'r' '_dec2hex' '_dec2hex _' 'auto' 0
  spec ' ' '_initChars' '_initChars'
  spec ' ' '_initCheck' '_initCheck'
  spec ' ' '_initDisplayHW' '_initDisplayHW'
  spec ' ' '_initLibrary' '_initLibrary'
  spec ' ' '_process image data' '_process image data _' 'auto' ' '
  spec ' ' '_sendCmd' '_sendCmd _' 'auto' ''
  spec ' ' '_verifyXY' '_verifyXY _ _' 'auto auto' 0 0

to OLEDInit_I2C dispType i2cAddr resetPin flip {
  comment 'Sets display type and interface and initializes HW settings.
Do NOT set a ResetPin# unless one exists on the display hardware.
NOTE:
Displays supported:
- OLED 0.96in (SD1306 chip) and
- OLED 2.42" (SD1309 chip)
Both displays are 128x64 pixels or 16x8 characters in size.
Displays come in dual mode version (i2c and spi) and pure i2c.
Pure i2c models do not have a Reset pin.

flip setting controls display hardware write direction:
- false: top to bottom
- true: bottom to top'
  _comma = ('[data:unicodeString]' 44)
  _comMode = 'i2c'
  OLEDi2cAddr = (hexToInt ('[data:join]' ('[data:unicodeString]' 32) i2cAddr))
  _resetPin = resetPin
  _displayType = (ifExpression (dispType == 'OLED_0.96in') 9 6)
  '_initDisplayHW'
  if flip {
    '_OLEDflip' true
  }
  '_initLibrary'
  OLEDclear
}

to OLEDInit_SPI dispType dcPin resetPin flip {
  comment 'Sets display type and interface and initializes HW settings.
SPI four wire in Mode-0 is supported. Max speed=10000000.

Do NOT set a ResetPin# unless one exists on the display hardware.
NOTE:
Displays supported:
- OLED 0.96in (SD1306 chip) and
- OLED 2.42" (SD1309 chip)
Both displays are 128x64 pixels or 16x8 characters in size.
Displays come in dual mode version (i2c and spi) and pure i2c.
Pure i2c models do not have a Reset pin.
flip setting controls display hardware write direction:
- false: top to bottom
- true: bottom to top'
  _comma = ('[data:unicodeString]' 44)
  _comMode = 'spi'
  _dcPin = dcPin
  if (_displayType != 0) {
    return
  }
  if (dispType == 'OLED_0.96in') {
    _displayType = 6
    _resetPin = resetPin
  } else {
    _displayType = 9
    _resetPin = resetPin
  }
  '[sensors:spiSetup]' 10000000
  '_initDisplayHW'
  if flip {
    '_OLEDflip' true
  }
  '_initLibrary'
  OLEDclear
}

to OLEDclear {
  comment 'Set bounds to FullScreen and CLEARs display
and GDBuffer.'
  _GDBuffer = ('[data:newByteArray]' 1024)
  '_initCheck'
  '_OLEDcursorReset'
  OLEDshowGDBuffer
}

to OLEDcontrast contrast {
  comment 'Sets the brightness control of the display to one of four values.
1 is the least bright, 4 is the brightest setting.'
  '_initCheck'
  local 'cLevels' ('[data:makeList]' 0 '1F' '2F' 'F0')
  if (and (contrast >= 1) (contrast <= 4)) {
    local 'i2cCmd' ('[data:join]' '81' _comma (at contrast cLevels))
    '_sendCmd' i2cCmd
  } else {
    sayIt 'Error in CONTRAST Level'
  }
}

to OLEDdrawCircle cx cy r erase {
  comment 'Bresenham Circle:
Draws circles, even partially bigger than the display.
x: 0-127
y: 0-63
void plotCircle(int xm, int ym, int r)
{
   int x = -r, y = 0, err = 2-2*r; /* II. Quadrant */
   do {
      setPixel(xm-x, ym+y); /*   I. Quadrant */
      setPixel(xm-y, ym-x); /*  II. Quadrant */
      setPixel(xm+x, ym-y); /* III. Quadrant */
      setPixel(xm+y, ym+x); /*  IV. Quadrant */
      r = err;
      if (r <= y) err += ++y*2+1;           /* e_xy+e_y < 0 */
      if (r > x || err > y) err += ++x*2+1; /* e_xy+e_x > 0 or no 2nd y-step */
   } while (x < 0);
}'
  '_initCheck'
  local 'oldDelayGDUpd' _delayGDUpd
  _delayGDUpd = (booleanConstant true)
  local 'x' (-1 * r)
  local 'y' 0
  local 'err' (2 - (2 * r))
  repeatUntil (x >= 0) {
    OLEDpixel (cx - x) (cy + y) erase
    OLEDpixel (cx - y) (cy - x) erase
    OLEDpixel (cx + x) (cy - y) erase
    OLEDpixel (cx + y) (cy + x) erase
    r = err
    if (r <= y) {
      y += 1
      err = (err + ((y * 2) + 1))
    }
    if (or (r > x) (err > y)) {
      x += 1
      err = (err + ((x * 2) + 1))
    }
  }
  _delayGDUpd = oldDelayGDUpd
  if (not _delayGDUpd) {
    OLEDshowGDBuffer
  }
}

to OLEDdrawImage image x y {
  comment '_imgHeight has to be mod8 or 1-8'
  if (0 == image) {
    return 0
  }
  local 'oldDelayGDUpd' _delayGDUpd
  _delayGDUpd = (booleanConstant true)
  for row# (maximum 1 ((minimum _imgHeight (64 - y)) / 8)) {
    local 'GDidx' ((((y / 8) * 128) + x) + 1)
    local 'imgDispl' ((row# - 1) * _imgWidth)
    for byte# (minimum _imgWidth (128 - x)) {
      comment 'If y is on page boundary, just copy'
      if (0 == (y % 8)) {
        atPut GDidx _GDBuffer (at (imgDispl + byte#) image)
        GDidx += 1
        if (GDidx > 1024) {
          _delayGDUpd = oldDelayGDUpd
          if (not _delayGDUpd) {
            OLEDshowGDBuffer
          }
          return 0
        }
      } else {
        comment 'Else, copy GDLowBits + shiftedByte + GDHiBits to GDBuffer and GDBuffer +128'
        local 'shiftedByte' ('_dec2hex' ((at (imgDispl + byte#) image) << (y % 8)))
        local 'temp' 0
        local 'tempHI' ('[data:copyFromTo]' shiftedByte 1 2)
        local 'tempLO' ('[data:copyFromTo]' shiftedByte 3 4)
        local 'GDLowBits' ((1 << (y % 8)) - 1)
        local 'GDHiBits' (255 - GDLowBits)
        tempLO = ((hexToInt tempLO) | ((at GDidx _GDBuffer) & GDLowBits))
        atPut GDidx _GDBuffer tempLO
        if ((GDidx + 128) <= 1024) {
          tempHI = ((hexToInt tempHI) | ((at (GDidx + 128) _GDBuffer) & GDHiBits))
          atPut (GDidx + 128) _GDBuffer tempHI
        }
        GDidx += 1
        if (GDidx > 1024) {
          _delayGDUpd = oldDelayGDUpd
          if (not _delayGDUpd) {
            OLEDshowGDBuffer
          }
          return 0
        }
      }
      waitMillis 0
    }
    y += 8
  }
  _delayGDUpd = oldDelayGDUpd
  if (not _delayGDUpd) {
    OLEDshowGDBuffer
  }
}

to OLEDdrawLine x0 y0 x1 y1 erase {
  comment 'Draws a line from x0,y0 to x1,y1 using the Bresenham Algorithm
x: 0-127
y: 0-63
plotLine(int x0, int y0, int x1, int y1)
    dx =  abs(x1-x0);
    sx = x0<x1 ? 1 : -1;
    dy = -abs(y1-y0);
    sy = y0<y1 ? 1 : -1;
    err = dx+dy;  /* error value e_xy */
    while (true)   /* loop */
        plot(x0, y0);
        if (x0 == x1 && y0 == y1) break;
        e2 = 2*err;
        if (e2 >= dy) /* e_xy+e_x > 0 */
            err += dy;
            x0 += sx;
        end if
        if (e2 <= dx) /* e_xy+e_y < 0 */
            err += dx;
            y0 += sy;
        end if
    end while'
  '_initCheck'
  local 'oldDelayGDUpd' _delayGDUpd
  _delayGDUpd = (booleanConstant true)
  results = ('[data:makeList]')
  local 'dx' (absoluteValue (x1 - x0))
  local 'dy' (-1 * (absoluteValue (y1 - y0)))
  local 'err' (dx + dy)
  local 'e2' 0
  local 'done' (booleanConstant false)
  if (x0 < x1) {
    local 'sx' 1
  } else {
    local 'sx' -1
  }
  if (y0 < y1) {
    local 'sy' 1
  } else {
    local 'sy' -1
  }
  repeatUntil done {
    OLEDpixel x0 y0 erase
    if (and (x0 == x1) (y0 == y1)) {
      done = (booleanConstant true)
    }
    e2 = (2 * err)
    if (e2 >= dy) {
      err += dy
      x0 += sx
    }
    if (e2 <= dx) {
      err += dx
      y0 += sy
    }
  }
  _delayGDUpd = oldDelayGDUpd
  if (not _delayGDUpd) {
    OLEDshowGDBuffer
  }
}

to OLEDdrawRect TLx TLy width height erase cornerRad {
  comment 'Draw Rectangle with optional rounded corners with radius R.
Does not check for reversed rectangle coordinates for round corners.'
  '_initCheck'
  local 'oldDelayGDUpd' _delayGDUpd
  _delayGDUpd = (booleanConstant true)
  local 'BRx' (TLx + width)
  local 'BRy' (TLy + height)
  if (cornerRad >= 3) {
    '_corner' 'TL' TLx TLy cornerRad erase
    '_corner' 'TR' BRx TLy cornerRad erase
    '_corner' 'BR' BRx BRy cornerRad erase
    '_corner' 'BL' TLx BRy cornerRad erase
    comment 'TOP - Adjust x'
    OLEDdrawLine (TLx + cornerRad) TLy ((BRx - 1) - cornerRad) TLy erase
    comment 'RIGHT- Adjust y'
    OLEDdrawLine BRx ((TLy + 1) + cornerRad) BRx ((BRy - 1) - cornerRad) erase
    comment 'BOTTOM - Adjust x'
    OLEDdrawLine ((BRx - 1) - cornerRad) BRy ((TLx + 1) + cornerRad) BRy erase
    comment 'LEFT - Adjust y'
    OLEDdrawLine TLx ((BRy - 1) - cornerRad) TLx ((TLy + 1) + cornerRad) erase
  } else {
    OLEDdrawLine TLx TLy BRx TLy erase
    OLEDdrawLine BRx (TLy + 1) BRx BRy erase
    OLEDdrawLine (BRx - 1) BRy TLx BRy erase
    OLEDdrawLine TLx (BRy - 1) TLx (TLy + 1) erase
  }
  _delayGDUpd = oldDelayGDUpd
  if (not _delayGDUpd) {
    OLEDshowGDBuffer
  }
}

to OLEDfillRect x y w h erase {
  local 'oldDelayGDUpd' _delayGDUpd
  _delayGDUpd = (booleanConstant true)
  for row ('[data:range]' 0 (h - 1)) {
    for col ('[data:range]' 0 (w - 1)) {
      OLEDpixel (x + col) (y + row) erase
    }
  }
  _delayGDUpd = oldDelayGDUpd
  if (not _delayGDUpd) {
    OLEDshowGDBuffer
  }
}

to OLEDmakeImage spr# {
  comment 'Receives a spr# representing 5x5 image matrix.
Converts it to a HOR array of 5 VERT bitmap numbers.
This can be displayed with the draw image block.
sprNum max is 33554431'
  '_initCheck'
  local 'spriteList' ('[data:newByteArray]' 5)
  local 'val' 0
  for col 5 {
    for row ('[data:asByteArray]' ('[data:makeList]' 0 5 10 15 20)) {
      local 'bit' (col + row)
      local 'vertBit#' (bit / 5)
      if ((spr# & (1 << (bit - 1))) != 0) {
        if (col != 5) {
          val += (1 << vertBit#)
        } else {
          val += (1 << (vertBit# - 1))
        }
      }
    }
    atPut col spriteList val
    val = 0
  }
  _imgWidth = 5
  _imgHeight = 5
  return spriteList
}

to OLEDpixel x y erase {
  comment 'Places a pixel at x,y in the virtual GDBuffer
Use OLEDshowGDBuffer to display it
8192 Pixels over 1024 Bytes
x: 0-127
y: 0-63
page#: 0-7
pagePixel#: 0-7
GDIndex: 1-1024

RangeCheck:
verify x and y are in range of display limits
if X <= num <= Y'
  '_initCheck'
  local 'pagePixel#' (y % 8)
  local 'GDIndex' ((x + ((y / 8) * 128)) + 1)
  local 'byteBMP' (at GDIndex _GDBuffer)
  byteBMP = (ifExpression (not erase) (byteBMP | (1 << pagePixel#)) (byteBMP & ('~' (1 << pagePixel#))))
  atPut GDIndex _GDBuffer byteBMP
}

to OLEDsetVideo videoMode {
  comment 'Switches the entire display:
Inverse: inverse video mode (bit 0 = on)
Normal: normal video mode (bit 1 = on).
Any image on the display will be preserved when mode changes.'
  '_initCheck'
  if (videoMode == 'Inverse') {
    local 'i2cCmd' 'A7'
  } else {
    local 'i2cCmd' 'A6'
  }
  '_sendCmd' i2cCmd
}

to OLEDshowGDBuffer {
  comment 'Copies contents of virtual _GDBuffer to display
i2c:
   in 60 byte chunks for speed.
   1 byte is used for the command 40
spi:
   fastest is dump buffer
 _GDBuffer is in decimal'
  '_initCheck'
  if (_comMode == 'i2c') {
    local 'idx' 0
    repeat 17 {
      '[sensors:i2cWrite]' OLEDi2cAddr ('[data:join]' _dataPrefix ('[data:copyFromTo]' _GDBuffer idx (idx + 60)))
      idx += 61
    }
  } else {
    '_SPIWriteData'
    '[sensors:spiExchange]' ('[data:copyFromTo]' _GDBuffer 1)
  }
  _delayGDUpd = (booleanConstant false)
}

to OLEDwrite string x y invFlag {
  comment 'Writes strings to display at any x,y; processing CR LF and wrapping at col x.
_textX and _textY are next write locations.'
  '_initCheck'
  local 'oldDelayGDUpd' _delayGDUpd
  _delayGDUpd = (booleanConstant true)
  '_verifyXY' x y
  local 'origX' x
  if (not (isType string 'string')) {
    string = ('[data:join]' '' string)
  }
  for char string {
    comment 'If in table process it - LINE SET is not supported.'
    if (('[data:find]' char _cTABLE) != -1) {
      OLEDdrawImage ('_cBMP' char invFlag) x y
      x += 8
      if (x > 127) {
        x = origX
        y += 8
        if (y > 63) {
          y = 0
        }
      }
    } (13 == ('[data:unicodeAt]' 1 char)) {
      noop
    } (10 == ('[data:unicodeAt]' 1 char)) {
      x = origX
      y += 8
      if (y > 63) {
        y = 0
      }
    } else {
      comment 'bad char - STOP'
      sayIt 'Invalid CHAR value:' char 'uniCode:' ('[data:unicodeAt]' 1 char)
      stopTask
    }
  }
  _textX = x
  _textY = y
  _delayGDUpd = oldDelayGDUpd
  if (not _delayGDUpd) {
    OLEDshowGDBuffer
  }
}

to OLEDwru {
  comment 'Next Row and Column to print
_textY, _textX'
  return ('[data:asByteArray]' ('[data:makeList]' _textY _textX))
}

to '_GDDRAMoff' {
  comment 'Displays a full empty screen of reverse video.
It disengages the hardware GDBuffer. '
  local 'i2cCmd' 'A5'
  '_sendCmd' i2cCmd
}

to '_GDDRAMon' {
  comment 'It disables the GDDRAMoff mode and engages the hardware GDBuffer for display content.'
  local 'i2cCmd' 'A4'
  '_sendCmd' i2cCmd
}

to '_OLEDcursorReset' {
  comment 'Sets display bounds to full range and resets cursor
to the origin top-left (0,0)
Rows: 0-7
Cols: 0-127
Cursor position is affected by any display operation
and also by OLEDColMode block.'
  '_initCheck'
  local 'cmdString' '22,00,07,21,00,7F'
  '_sendCmd' cmdString
  _textX = 0
  _textY = 0
}

to '_OLEDflip' flip {
  comment 'Flips the display initialization horizontally or vertically.
Horizontal or vertical is based on the pin connector location.'
  if flip {
    '_sendCmd' 'A0,C0'
  } else {
    '_sendCmd' 'A1,C8'
  }
}

to '_OLEDreset' pin {
  comment 'Does a power off and on on the display,
thus forcing a hardware initialization.'
  digitalWriteOp pin false
  waitMillis 1
  digitalWriteOp pin true
  waitMillis 1
}

to '_OLEDsetDisplay' onoff {
  comment 'Puts the display into
Off:SLEEP   On:WAKE   mode.
Images on display are preserved.'
  '_initCheck'
  if (onoff == 'On') {
    local 'i2cCmd' 'AF'
  } else {
    local 'i2cCmd' 'AE'
  }
  '_sendCmd' i2cCmd
}

to '_SPIWriteCmd' {
  comment 'In SPI mode, we send either a write command
or write data control code. Then follow it with
the appropriate command/data bundle.'
  digitalWriteOp _dcPin false
}

to '_SPIWriteData' {
  comment 'In SPI mode, we send either a write command
or write data control code. Then follow it with
the appropriate command/data bundle.'
  digitalWriteOp _dcPin true
}

to '_T1' {
  comment 'THIN-SS Character Set
Range: space - ?'
  local '_cHEX1' '00000000000000000000005F00000000000007000007000000147F14147F140000242A6B6B2A12000046261008646200304A454D324848000000040300000000001C224100000000000041221C000000082A1C1C1C2A08000008083E080800000000806000000000000808080808080000000060000000000040201008040200003E615149453E000044427F4040000000625151494966000022414949493600101814527F5010000027454545453900003C4A4949493000000301710905030000364949494936000006494949291E00000000660000000000008066000000000008142241000000002424242424240000000041221408000002010151090600'
  local 'idx' 1
  for i 256 {
    atPut i _cDecTBL (hexToInt ('[data:copyFromTo]' _cHEX1 idx (idx + 1)))
    idx += 2
  }
  _cHEX1 = ''
}

to '_T2' {
  comment 'THIN-SS Character Set
Range: @ - _ (underscore)'
  local '_cHEX2' '003E415D55551E00007C121111127C0000417F4949493600001C22414141220000417F4141221C0000417F495D41630000417F491D010300001C224151517200007F080808087F000000417F4100000000304040413F010000417F081422414000417F4140406000007F01020402017F007F010204087F00003E414141413E0000417F4909090600001E212131215E4000417F49192946000026494949493200000301417F410103003F404040403F00000F10204020100F003F40403840403F004122140814224100010244784402010043615149454361007F4141410000000102040810204000004141417F00000008040201020408008080808080808080'
  local 'idx' 1
  for i 256 {
    atPut (256 + i) _cDecTBL (hexToInt ('[data:copyFromTo]' _cHEX2 idx (idx + 1)))
    idx += 2
  }
  _cHEX2 = ''
}

to '_T3' {
  comment 'THIN-SS Character Set
Range: '' - . (last char)'
  local '_cHEX3' '0000000304000000002054545454784000017F304848483000384444444428000030484848317F4000385454545418000000487E490102000098A4A4A4A4780400417F08040478000000447D400000000060808080847D0000017F10284440000000417F40000000007C040478040478007C08040404780000384444444438000084FC98242418000018242498FC840000447C480404180000485454545424000004043F44442000003C404040207C00000C10204020100C003C40403840403C0044281028440000009CA0A0A0A07C00004464544C44000000080836414100000000007700000000000041413608080000020101020201000000000000000000'
  local 'idx' 1
  for i 256 {
    atPut (512 + i) _cDecTBL (hexToInt ('[data:copyFromTo]' _cHEX3 idx (idx + 1)))
    idx += 2
  }
  _cHEX3 = ''
}

to '_cBMP' char invFlag {
  comment 'Returns DEC char bitmap from _cHexTbl and
optionally converts it to inverse (XOR).
Line segments are NOT supported.
A: 00,7c,12,11,12,7c,00
dec:  0,124,18,17,17,124,0
inv:    255,131,237,238,238,131,255'
  local 'key' (((('[data:unicodeAt]' 1 char) - 32) * 8) + 1)
  local 'charList' ('[data:copyFromTo]' _cDecTBL key (key + 7))
  comment 'inverse'
  if invFlag {
    for item# (size charList) {
      atPut item# charList ((at item# charList) ^ 255)
    }
  }
  _imgWidth = 8
  _imgHeight = 8
  return charList
}

to '_clearDisplay' {
  comment 'Clear Screen without initializing _GDBuffer'
  '_initCheck'
  '_OLEDcursorReset'
  if ('i2c' == _comMode) {
    repeat 17 {
      '[sensors:i2cWrite]' OLEDi2cAddr ('[data:join]' _dataPrefix ('[data:newByteArray]' 60))
    }
    '[sensors:i2cWrite]' OLEDi2cAddr ('[data:join]' _dataPrefix ('[data:newByteArray]' 4))
  } else {
    '_SPIWriteData'
    '[sensors:spiExchange]' ('[data:newByteArray]' 1024)
  }
}

to '_corner' loc cx cy r erase {
  comment 'Calculates and displays the rounded corners for the rectangles.
loc is one of TL, TR, BL, BR ... topLeft, topright, bottomleft, bottomright
cx,cy are the corner coordinates for the rounded corner.
r is the radius in pixels of the arc to be calculated.'
  local 'x' (-1 * r)
  local 'y' 0
  local 'err' (2 - (2 * r))
  if (loc == 'TL') {
    cx += r
    cy += r
  } (loc == 'TR') {
    cx += (-1 * r)
    cy += r
  } (loc == 'BL') {
    cx += r
    cy += (-1 * r)
  } (loc == 'BR') {
    cx += (-1 * r)
    cy += (-1 * r)
  }
  repeatUntil (x >= 0) {
    if (loc == 'TL') {
      OLEDpixel (cx + x) (cy - y) erase
    } (loc == 'TR') {
      OLEDpixel (cx + y) (cy + x) erase
    } (loc == 'BL') {
      OLEDpixel (cx - y) (cy - x) erase
    } (loc == 'BR') {
      OLEDpixel (cx - x) (cy + y) erase
    }
    r = err
    if (r <= y) {
      y += 1
      err = (err + ((y * 2) + 1))
    }
    if (or (r > x) (err > y)) {
      x += 1
      err = (err + ((x * 2) + 1))
    }
  }
}

to '_dec2hex' num {
  comment 'Fast version w/o inversion. (~115uSecs)'
  local '_hexTbl' '0123456789ABCDEF'
  local 'hexNum' ''
  repeatUntil (num < 0) {
    local 'temp' ('[data:join]' (at ((num % 16) + 1) _hexTbl) hexNum)
    hexNum = temp
    num = (ifExpression ((num / 16) != 0) (num / 16) -1)
  }
  comment 'If not half-byte length, pad it.'
  hexNum = ('[data:join]' ('[data:copyFromTo]' '000' 1 (4 - (size hexNum))) hexNum)
  return hexNum
}

to '_initChars' {
  comment 'Creates the character set used in the Library (96 characters)
used JOIN  for SPACE (uni-32) character so it won''t be deleted by mistake.
For each character, _cDecTbl is updated with 8 byte array values.'
  _cTABLE = ('[data:join]' ('[data:unicodeString]' 32) '!"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~.')
  '_T1'
  '_T2'
  '_T3'
}

to '_initCheck' {
  comment 'Verifies Library initialization status.'
  if (not OLEDReady) {
    sayIt 'Display needs to be initialized before using the library blocks.'
    stopTask
  }
}

to '_initDisplayHW' {
  comment '*** DO NOT CHANGE THESE WITHOUT UNDERSTANDING THEIR MEANINGS ***
*** IT CAN MAKE THE DISPLAY NOT OPERATE CORRECTLY                          ***

Initializes display HW timings
OLED INITIALIZATION STRINGS:
1306: pins are on top
1309: pins are on the right

A8 3F - Multiplex Ratio 0F-3F (16mux to 64mux)
D3 00 - Display Offset (vertical) 00-63
40    - Display Start Line 40-7F (40:0)
A0    - Set Segment Remap A0: Remap 0:0, A1: 127:0                 [A1]
C0    - Scan Direction C0:0-127, C8:127-0                                     [C8]
DA 12 - COM pin hw config 02:double-high 12:normal bits
81 F0  - Set contrast 00-FF (00:dimmest, FF:brightest)                  [F0]
A4    - A4:display shows GDRAM, A5:display all ON pixels
A6    - A6:Normal video, A7:Inverse video
D5 F0 - Set display clock HB:OSC freq / LB:divide ratio (00-FF)
D9 22 - Set pre-charge period HB:Phase2 / LB:Phase1 (1-15 DCLK)
DB 20 - Set Vcomh deselect level 20:1306(~0.77xVcc), 34:1309(~0.78xVcc)
8D 14 - Charge Pump Setting 10:disable CP, 14:enable CP
20 00 - Set HORIZONTAL mode
AF    - Display ON/OFF AE:off (sleep mode), AF:on'
  if (_resetPin != '-') {
    '_OLEDreset' _resetPin
  }
  if (9 == _displayType) {
    local 'initCmd' 'A8,3F,D3,00,40,A1,C8,DA,12,81,F0,A4,A6,D5,70,D9,22,DB,34,8D,14,20,00,AF'
  } else {
    local 'initCmd' 'A8,3F,D3,00,40,A1,C8,DA,12,81,F0,A4,A6,D5,70,D9,22,DB,20,8D,14,20,00,AF'
  }
  '_sendCmd' initCmd
}

to '_initLibrary' {
  comment 'Sets all Library variables and initializes the display hardware.
It also initializes the virtual GDBuffer, and clears the display.
NOTE:
Displays supported: OLED1306 (0.96in) and OLED1309 (2.42"), selected via boolean position.
OLED1309 requires the connection of RESET pin to a digital pin.
Both displays are 128x64 pixels or 16x8 characters in size.
Make sure the character hex tables are \n (LF) terminated.
Otherwise, extra lines are added in between and it gets messed up.
eg: A: 00,7C,12,11,11,12,7C,00\n
Max i2c IO is 64 bytes: buffered writes need to be max that size - 16 x 64'
  _comma = ('[data:unicodeString]' 44)
  _eol = ('[data:unicodeString]' 10)
  comment 'Col starts are in HEX'
  _dataPrefix = ('[data:newByteArray]' 1 (hexToInt '40'))
  comment 'There is no FF/255 in th cHexTBL.
this value is used to build the byteArray.'
  _cDecTBL = ('[data:newByteArray]' 768 255)
  _GDBuffer = ('[data:newByteArray]' 1024)
  _textX = 0
  _textY = 0
  _delayGDUpd = (booleanConstant false)
  '_initChars'
  OLEDReady = (booleanConstant true)
  '_OLEDsetDisplay' 'On'
  repeat 2 {
    setUserLED true
    waitMillis 50
    setUserLED false
    waitMillis 50
  }
}

to '_process image data' image {
  comment 'Processes the new hex image data format.
Each _imgHex gets added to _imgData in DEC byteArray format.
_byteCount keeps track of total bytes processed.
_imgWidth and _imgHeight (mod8) are dimensions.'
  local '_ptr' 1
  comment '_imgData is not initialized yet.'
  if (or (0 == _imgData) (not (isType _imgData 'byte array'))) {
    _imgWidth = (hexToInt ('[data:copyFromTo]' image 1 2))
    _imgHeight = (hexToInt ('[data:copyFromTo]' image 3 4))
    image = ('[data:copyFromTo]' image 5)
    comment 'If _imgHeight is partial byte, adjust to full byte'
    if (not (0 == (_imgHeight % 8))) {
      _imgHeight += (8 - (_imgHeight % 8))
    }
    _imgData = ('[data:newByteArray]' ((_imgWidth * _imgHeight) / 8))
  }
  for byte ('[data:range]' 1 (size image) 2) {
    atPut (_byteCount + _ptr) _imgData (hexToInt ('[data:copyFromTo]' image byte (byte + 1)))
    _ptr += 1
  }
  _byteCount += (_ptr - 1)
}

to '_sendCmd' cmdString {
  comment 'Input is a comma sep. STRING.
MAKE SURE ALL  INPUT PARAMETERS ARE HEX'
  local '_cList' ('[data:split]' cmdString _comma)
  local 'cmdPrefix' (hexToInt '80')
  if ('i2c' == _comMode) {
    for cmd _cList {
      '[sensors:i2cWrite]' OLEDi2cAddr ('[data:asByteArray]' ('[data:makeList]' cmdPrefix (hexToInt cmd)))
    }
  } else {
    '_SPIWriteCmd'
    for cmd _cList {
      spiSend (hexToInt cmd)
    }
  }
}

to '_verifyXY' x y {
  if (and (and (x >= 0) (x <= 127)) (and (y >= 0) (y <= 63))) {
    return 0
  } else {
    sayIt 'x or y value error:' ('[data:unicodeString]' 10) 'x:' x ' y:' y
    stopTask
  }
}

to 'defer display updates' {
  _delayGDUpd = (booleanConstant true)
}


module Spark_Analog Operators
author 'FABLAB BH'
version 1 1 
choices analog_pins '3' '4' '6' '7' '8' 
description ''

  spec 'r' '_Analog Pins' '_Analog Pins _' 'num' 3
  spec 'r' 'Film Pressure Pin' 'Film Pressure Pin _' 'menu.analog_pins' 3
  spec 'r' 'PhotoResistance Pin' 'Photoresistance Pin _' 'menu.analog_pins' 3
  spec 'r' 'Potentiometer' 'Potentiometer Pin _' 'menu.analog_pins' 3
  spec 'r' 'Steam Sensor' 'Steam Sensor _' 'menu.analog_pins' 3

to 'Analog Pins' Pin {
  return (at Pin ('[data:makeList]' 0 0 4 39 0 36 35 34 0))
}

to 'Film Pressure Pin' Pin {
  return (analogReadOp ('Analog Pins' Pin))
}

to 'PhotoResistance Pin' Pin {
  return (analogReadOp ('Analog Pins' Pin))
}

to Potentiometer Pin {
  return (analogReadOp ('Analog Pins' Pin))
}

to 'Steam Sensor' Pin {
  return (analogReadOp ('Analog Pins' Pin))
}


module Spark_Digital Data
author 'FABLAB BH'
version 1 1 
depends '_Temperature Humidity (DHT11, DHT22)' 
choices digital_pins '1' '2' '3' '4' '6' '7' '8' '9' 
description ''

  spec 'r' 'Button Pin' 'Button Pin _' 'menu.digital_pins' 1
  spec 'r' '_DigitalPins' '_DigitalPins _' 'menu.digital_pins' 1
  spec 'r' 'Inverted Button Pin' 'Inverted Button Pin _' 'menu.digital_pins' 1
  spec 'r' 'Photo Interrupter Pin' 'Photo Interrupter Pin _' 'menu.digital_pins' 1
  spec 'r' 'Tilt Switch Pin' 'Tilt Switch Pin _' 'menu.digital_pins' 1
  spec 'r' 'Touch Pin' 'Touch Pin _' 'menu.digital_pins' 1
  spec 'r' 'Humidity Pin' 'Humidity Pin _' 'menu.digital_pins' 1
  spec 'r' 'Temperature Pin' 'Temperature Pin _' 'menu.digital_pins' 1
  space
  space
  spec ' ' 'Buzzer2' 'Buzzer Pin _ State _' 'menu.digital_pins bool' 1 false
  spec ' ' 'LED' 'LED Pin _ State _' 'menu.digital_pins bool' 1 false
  spec ' ' 'Horn' 'Horn Pin _ State _' 'menu.digital_pins bool' 1 false
  spec ' ' 'Relay Pin' 'Relay Pin _ State _' 'menu.digital_pins bool' 1 false
  space
  spec ' ' 'Buzzer' 'Buzzer Pin _ Tone _' 'menu.digital_pins num' 1 1000
  spec ' ' 'LED2 Pin' 'LED Pin _ Brightness _' 'menu.digital_pins num' 1 1000
  spec ' ' 'Horn Pin' 'Horn Pin _ Tone _' 'menu.digital_pins num' 1 1000

to 'Button Pin' Pin {
  local 'Read1' (digitalReadOp (DigitalPins Pin) 'up')
  if (Read1 == (booleanConstant true)) {
    return (not Read1)
  } else {
    return (booleanConstant true)
  }
}

to Buzzer Pin Tone {
  analogWriteOp (DigitalPins Pin) Tone
}

to Buzzer2 Pin State {
  digitalWriteOp (DigitalPins Pin) State
}

to DigitalPins Pin {
  return (at Pin ('[data:makeList]' 13 2 26 27 0 23 16 5 18))
}

to Horn Pin State {
  digitalWriteOp (DigitalPins Pin) State
}

to 'Horn Pin' Pin Tone {
  analogWriteOp (DigitalPins Pin) Tone
}

to 'Humidity Pin' Pin {
  return (humidity_DHT11 (DigitalPins Pin))
}

to 'Inverted Button Pin' Pins {
  local 'Read2' (digitalReadOp (DigitalPins Pin) 'up')
  if (Read2 == (booleanConstant false)) {
    return Read2
  } else {
    return (booleanConstant true)
  }
}

to LED Pin State {
  digitalWriteOp (DigitalPins Pin) State
}

to 'LED2 Pin' Pin Brightness {
  analogWriteOp (DigitalPins Pin) Brightness
}

to 'Photo Interrupter Pin' Pin {
  return (digitalReadOp (DigitalPins Pin))
}

to 'Relay Pin' Pin State {
  digitalWriteOp (DigitalPins Pin) State
}

to 'Temperature Pin' Pin {
  return (temperature_DHT11 (DigitalPins Pin))
}

to 'Tilt Switch Pin' Pin {
  return (digitalReadOp (DigitalPins Pin))
}

to 'Touch Pin' Pin {
  return (digitalReadOp (DigitalPins Pin))
}


module Spark_I2C Output
author FABLAB
version 1 1 
depends '_Gesture (PAJ7620)' 
choices direction clockwise 'counter-clockwise' 
description ''
variables Gesture 

  spec 'r' 'Gesture Read' 'Gesture Read'
  space
  spec ' ' 'Motor Driver A' 'Motor Driver A Direction _ Speed _' 'menu.direction num' 'clockwise' 10
  spec ' ' 'Motor Driver B' 'Motor Driver B Direction _ Speed _' 'menu.direction num' 'clockwise' 10
  spec 'r' '_Direction' '_Direction _' 'menu.direction' 'clockwise'

to 'Gesture Read' {
  return ('paj7620 read')
}

to 'Motor Driver A' Direction Speed {
  if ((Direction Direction) == (booleanConstant true)) {
    i2cSet 0 1 Speed
    i2cSet 0 2 0
  } ((Direction Direction) == (booleanConstant false)) {
    i2cSet 0 1 0
    i2cSet 0 2 Speed
  } else {
    i2cSet 0 1 0
    i2cSet 0 2 0
  }
}

to 'Motor Driver B' Direction Speed {
  if ((Direction Direction) == (booleanConstant true)) {
    i2cSet 0 3 Speed
    i2cSet 0 4 0
  } ((Direction Direction) == (booleanConstant false)) {
    i2cSet 0 3 0
    i2cSet 0 4 Speed
  } else {
    i2cSet 0 3 0
    i2cSet 0 4 0
  }
}


module Spark_MP Variables
author FABLAB
version 1 1 
choices MP_pins '1' '9' 
description ''

  spec 'r' 'Ultrasonic Pin' 'Ultrasonic Pin _' 'menu.MP_pins' 1
  spec 'r' '_Multipins' 'Multipins _' 'menu.MP_pins' '1'
  space
  spec ' ' 'RGBLED3' 'RGBLED Pin _ R _ G _ B _' 'menu.MP_pins num num num' 1 50 50 50
  spec ' ' 'RGBLED3 Pin' 'RGBLED Pin _ R _ G _ B _' 'menu.MP_pins bool bool bool' 1 true true true
  spec ' ' 'Traffic Light' 'Traffic Light Pin _ R _ Y _ G _' 'menu.MP_pins bool bool bool' 1 true true true
  spec ' ' 'Traffic Light Pin' 'Traffic Light Pin _ R _ Y _ G _' 'menu.MP_pins num num num' 1 255 255 255

to Multipins Pin {
  return (at Pin ('[data:makeList]' 12 0 0 0 0 0 0 0 17))
}

to RGBLED3 Pin Red Green Blue {
  analogWriteOp (Multipins Pin) Red
  analogWriteOp ((Multipins Pin) + 1) Green
  analogWriteOp ((Multipins Pin) + 2) Blue
}

to 'RGBLED3 Pin' Pin Red Green Blue {
  digitalWriteOp (Multipins Pin) Red
  digitalWriteOp ((Multipins Pin) + 1) Green
  digitalWriteOp ((Multipins Pin) + 2) Blue
}

to 'Traffic Light' Pin Red Yellow Green {
  digitalWriteOp (Multipins Pin) Red
  digitalWriteOp ((Multipins Pin) + 1) Yellow
  digitalWriteOp ((Multipins Pin) + 2) Green
}

to 'Traffic Light Pin' Pin Red Yellow Green {
  analogWriteOp (Multipins Pin) Red
  analogWriteOp ((Multipins Pin) + 1) Yellow
  analogWriteOp ((Multipins Pin) + 2) Green
}

to 'Ultrasonic Pin' Pin {
  comment 'Contributed by Joan Guillén and Josep Ferràndiz'
  digitalWriteOp ((Multipins Pin) + 1) false
  waitMicros 2
  digitalWriteOp ((Multipins Pin) + 1) true
  waitMicros 50
  digitalWriteOp ((Multipins Pin) + 1) false
  local 'start' (microsOp)
  waitUntil (or (not (digitalReadOp ((Multipins Pin) + 2))) (((microsOp) - start) > 23320))
  waitUntil (or (digitalReadOp ((Multipins Pin) + 2)) (((microsOp) - start) > 23320))
  if (((microsOp) - start) > 23320) {
    comment 'Distance sensor not ready; return the last distance reading'
    return _sr04_last
  }
  comment 'Pulse sent. Measure time until echo is detected.'
  start = (microsOp)
  waitUntil (or (not (digitalReadOp ((Multipins Pin) + 2))) (((microsOp) - start) > 23320))
  _sr04_last = ((10 * ((microsOp) - start)) / 583)
  comment 'Leave some time for reverberations to die away.'
  waitMillis 10
  return _sr04_last
}


module Spark_PWM Control
author 'FABLAB BH'
version 1 1 
depends _Servo 
choices PWM_pins2 '3' '4' '6' '7' '8' 
choices PWM_pins '1' '9' 
choices direction clockwise 'counter-clockwise' 
choices servo_pins '32' '33' 
description ''

  spec 'r' '_PWM Pin' '_PWM Pin _' 'menu.PWM_pins' 1
  spec 'r' '_Direction' '_Direction _' 'menu.direction' 'clockwise'
  spec ' ' 'Fan Motor3' 'Fan Motor Pin _ Speed _ (0-100)' 'menu.PWM_pins2 num' 3 50
  spec ' ' 'Fan Motor4' 'Fan Motor Pin _ Speed _ (0-1023)' 'menu.PWM_pins2 num' 3 50
  space
  spec ' ' 'Fan Motor' 'Fan Motor Pin _ Direction _ Speed _ (0-100)' 'menu.PWM_pins menu.direction num' 1 'clockwise' 50
  spec ' ' 'Fan Motor2' 'Fan Motor Pin _ Direction _ Speed _ (0-1023)' 'menu.PWM_pins menu.direction num' 1 'clockwise' 50
  space
  spec ' ' 'Servo' 'Servo Motor Pin _ Speed _ (-100 to 100)' 'menu.servo_pins num' 33 50
  spec ' ' 'Servo Motor Pin' 'Servo Motor Pin _ Degrees _ (-90 to 90)' 'menu.servo_pins num' 33 90

to Direction Direction {
  if (Direction == ('[data:toString]' 'counter-clockwise')) {
    return (booleanConstant false)
  } else {
    return (booleanConstant true)
  }
}

to 'Fan Motor' Pin Direction Speed {
  if (and (Speed > 0) (Speed <= 100)) {
    local 'PWM' (absoluteValue (((Speed - 1) * ((1023 - 1) / 99)) + 1))
    if ((Direction Direction) == (not true)) {
      if (and (PWM > 0) (PWM < 1024)) {
        digitalWriteOp ('PWM Pin' Pin) true
        analogWriteOp (('PWM Pin' Pin) + 1) (1023 - PWM)
      }
    } else {
      if (and (PWM > 0) (PWM < 1024)) {
        digitalWriteOp ('PWM Pin' Pin) false
        analogWriteOp (('PWM Pin' Pin) + 1) PWM
      }
    }
  } (Speed == 0) {
    digitalWriteOp ('PWM Pin' Pin) false
    digitalWriteOp (('PWM Pin' Pin) + 1) false
  } else {
    sayIt 'The range is between 0 and 100'
  }
}

to 'Fan Motor2' Pin Direction Speed {
  if (and (Speed > 0) (Speed <= 1023)) {
    if ((Direction Direction) == (not true)) {
      digitalWriteOp ('PWM Pin' Pin) true
      analogWriteOp (('PWM Pin' Pin) + 1) (1023 - Speed)
    } else {
      digitalWriteOp ('PWM Pin' Pin) false
      analogWriteOp (('PWM Pin' Pin) + 1) Speed
    }
  } (Speed == 0) {
    digitalWriteOp ('PWM Pin' Pin) false
    digitalWriteOp (('PWM Pin' Pin) + 1) false
  } else {
    sayIt 'The range is between 0 and 1023'
  }
}

to 'Fan Motor3' Pin Speed {
  if (and (Speed > 0) (Speed <= 100)) {
    local 'PWM' (absoluteValue (((Speed - 1) * ((1023 - 1) / 99)) + 1))
    analogWriteOp ('PWM Pin' Pin) PWM
  } (Speed == 0) {
    digitalWriteOp ('PWM Pin' Pin) false
  } else {
    sayIt 'The range is between 0 and 100'
  }
}

to 'Fan Motor4' Pin Speed {
  if (and (Speed > 0) (Speed <= 1023)) {
    analogWriteOp ('PWM Pin' Pin) Speed
  } (Speed == 0) {
    digitalWriteOp ('PWM Pin' Pin) false
  } else {
    sayIt 'The range is between 0 and 1023'
  }
}

to 'PWM Pin' Pin {
  return (at Pin ('[data:makeList]' 13 0 26 27 0 23 16 5 18))
}

to Servo Pin Speed {
  setServoSpeed Pin Speed
}

to 'Servo Motor Pin' Pin Degrees {
  setServoAngle Pin Degrees
}


module 'Temperature Humidity (DHT11, DHT22)' Input
author MicroBlocks
version 1 3 
tags sensor dht11 dht22 temperature humidity 
description 'Support for the DHT11 and DHT22 environmental sensors. These sensors provide temperature and humidity readings.
'
variables _dht_temperature _dht_humidity _dhtData _dhtLastReadTime data 

  spec 'r' 'temperature_DHT11' 'temperature (Celsius) DHT11 pin _' 'auto' 4
  spec 'r' 'humidity_DHT11' 'humidity DHT11 pin _' 'auto' 4
  spec 'r' 'temperature_DHT22' 'temperature (Celsius) DHT22 pin _' 'auto' 4
  spec 'r' 'humidity_DHT22' 'humidity DHT22 pin _' 'auto' 4
  spec ' ' '_dhtReadData' '_dhtReadData pin _' 'auto any' 4
  spec 'r' '_dhtChecksumOkay' '_dhtChecksumOkay' 'any'
  spec ' ' '_dhtUpdate' '_dhtUpdate _ isDHT11 _' 'auto bool any' 4 true
  spec 'r' '_dhtReady' '_dhtReady' 'any'
  spec ' ' '_dhtCaptureData' '_dhtCaptureData _' 'num' 4

to '_dhtCaptureData' pin {
  '[sensors:captureStart]' pin
  waitMillis 10
  local 'pulses' ('[sensors:captureEnd]')
  local 'pulseCount' (size pulses)
  if (pulseCount < 80) {
    return 0
  } (pulseCount > 80) {
    pulses = ('[data:copyFromTo]' pulses (pulseCount - 79))
  }
  data = pulses
  local 'byte' 0
  for i 40 {
    if ((at ((2 * i) - 1) pulses) > 40) {
      comment 'Long pulse - appends a "1" bit'
      byte += 1
    }
    if ((i % 8) == 0) {
      atPut (i / 8) _dhtData byte
      byte = 0
    } else {
      byte = (byte << 1)
    }
  }
}

to '_dhtChecksumOkay' {
  if (not (isType _dhtData 'list')) {return (booleanConstant false)}
  local 'checksum' 0
  for i 4 {
    checksum += (at i _dhtData)
  }
  checksum = (checksum & 255)
  return (checksum == (at 5 _dhtData))
}

to '_dhtReadData' pin {
  comment 'Create DHT data array the first time'
  if (_dhtData == 0) {
    _dhtData = (newList 5)
  }
  comment 'fill with 1''s set checksum will be bad if read fails'
  atPut 'all' _dhtData 1
  comment 'Pull pin low for >18msec to request data'
  digitalWriteOp pin false
  waitMillis 20
  local 'useDHTPrimitive' (booleanConstant true)
  if useDHTPrimitive {
    '_dhtCaptureData' pin
    return 0
  }
  comment 'Read DHT start pulses (H L H L)'
  waitUntil (digitalReadOp pin)
  waitUntil (not (digitalReadOp pin))
  waitUntil (digitalReadOp pin)
  waitUntil (not (digitalReadOp pin))
  local 'i' 1
  local 'byte' 0
  local 'bit' 1
  comment 'Read 40 bits (5 bytes)'
  repeat 40 {
    waitUntil (digitalReadOp pin)
    local 'start' (microsOp)
    waitUntil (not (digitalReadOp pin))
    if (((microsOp) - start) > 40) {
      comment 'Long pulse - append a "1" bit'
      byte += 1
    }
    if (bit == 8) {
      atPut i _dhtData byte
      i += 1
      byte = 0
      bit = 1
    } else {
      byte = (byte << 1)
      bit += 1
    }
    waitUntil (not (digitalReadOp pin))
  }
}

to '_dhtReady' {
  local 'elapsed' ((millisOp) - _dhtLastReadTime)
  return (or (elapsed < 0) (elapsed > 2000))
}

to '_dhtUpdate' pin isDHT11 {
  if ('_dhtReady') {
    _dht_temperature = 0
    _dht_humidity = 0
    '_dhtReadData' pin
    _dhtLastReadTime = (millisOp)
  }
  if ('_dhtChecksumOkay') {
    if isDHT11 {
      _dht_temperature = (at 3 _dhtData)
      _dht_humidity = (at 1 _dhtData)
    } else {
      local 'n' (((at 1 _dhtData) * 256) + (at 2 _dhtData))
      _dht_humidity = ((n + 5) / 10)
      n = ((((at 3 _dhtData) & 127) * 256) + (at 4 _dhtData))
      if (((at 3 _dhtData) & 128) != 0) {
        n = (0 - n)
      }
      _dht_temperature = ((n + 5) / 10)
    }
  }
}

to humidity_DHT11 pin {
  '_dhtUpdate' pin true
  return _dht_humidity
}

to humidity_DHT22 pin {
  '_dhtUpdate' pin false
  return _dht_humidity
}

to temperature_DHT11 pin {
  '_dhtUpdate' pin true
  return _dht_temperature
}

to temperature_DHT22 pin {
  '_dhtUpdate' pin false
  return _dht_temperature
}

