From a8acc4f92f5955d635f7ae0d3cdea024bf11ec9f Mon Sep 17 00:00:00 2001 From: fatimaxsen Date: Thu, 3 Jul 2025 10:35:24 +0300 Subject: [PATCH] Upload files to "/" --- Spark .ubl | 843 ++++++++++++++++++++++++++++++++++++++++++++++ Spark_Analog.ubl | 32 ++ Spark_Digital.ubl | 96 ++++++ Spark_I2C.ubl | 52 +++ Spark_MP.ubl | 65 ++++ 5 files changed, 1088 insertions(+) create mode 100644 Spark .ubl create mode 100644 Spark_Analog.ubl create mode 100644 Spark_Digital.ubl create mode 100644 Spark_I2C.ubl create mode 100644 Spark_MP.ubl diff --git a/Spark .ubl b/Spark .ubl new file mode 100644 index 0000000..fa3ee45 --- /dev/null +++ b/Spark .ubl @@ -0,0 +1,843 @@ +module 'Spark' 'cat;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 ModeMenu Horizontal Vertical +choices OnOffMenu On Off +choices VideoMenu Inverse Normal +choices DispTypeMenu 'OLED_0.96in' 'OLED_2.42in' +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= 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) +} + diff --git a/Spark_Analog.ubl b/Spark_Analog.ubl new file mode 100644 index 0000000..2e4aee9 --- /dev/null +++ b/Spark_Analog.ubl @@ -0,0 +1,32 @@ +module Spark_Analog 'cat;Operators' +author 'FABLAB BH' +version 1 1 +description '' + + choices analog_pins '3' '4' '6' '7' '8' + 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)) +} + diff --git a/Spark_Digital.ubl b/Spark_Digital.ubl new file mode 100644 index 0000000..8823e0f --- /dev/null +++ b/Spark_Digital.ubl @@ -0,0 +1,96 @@ +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)) +} + diff --git a/Spark_I2C.ubl b/Spark_I2C.ubl new file mode 100644 index 0000000..d1c5d49 --- /dev/null +++ b/Spark_I2C.ubl @@ -0,0 +1,52 @@ +module Spark_I2C 'cat;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' '_Motor Direction _' 'menu.direction' '10' + +to Direction Direction { + if (Direction == ('[data:toString]' 'counter-clockwise')) { + return (booleanConstant false) + } else { + return (booleanConstant true) + } +} + +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 + } +} + diff --git a/Spark_MP.ubl b/Spark_MP.ubl new file mode 100644 index 0000000..2b0b9f1 --- /dev/null +++ b/Spark_MP.ubl @@ -0,0 +1,65 @@ +module Spark_MP 'cat;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 +} +