Raspberry BASIC

Recent Posts

Pages: 1 [2] 3 4
11
BBC BASIC / Interfacing with a DHT11/12/22 sensor
« Last post by Richard Russell on June 03, 2019, 04:21:14 PM »
The BBC BASIC program below interfaces with a DHT11/12 or DHT22 humidity and temperature sensor connected to a Raspberry Pi GPIO pin.  These sensors use a proprietary serial data format on a one-wire bidirectional bus, which has to be decoded in software.

Because of the variable latency associated with a user-mode program reading the GPIO, the data cannot always be decoded reliably.  The code uses a number of strategies to minimize this problem but mis-reads must be expected and dealt with (e.g. by means of retries) in any application using it.  Note that the DHT11/12 may be polled no faster than once per second and the DHT22 no faster than once every two seconds.

The code has been written to be functional rather than pretty!

Code: BBC BASIC
  1.       REM DHT11/12/22 sensor interface for Raspberry Pi 3/3+ (Raspbian)
  2.       REM (c) Richard Russell, http://www.rtrussell.co.uk/, 03-Jun-2019
  3.  
  4.       INSTALL @lib$ + "gpiolib"
  5.       GPIO% = FN_gpio_setup
  6.       PIN% = 2 : REM BCM pin no.
  7.  
  8.       @% = &2010A
  9.       REPEAT
  10.         CASE FN_dht_read(GPIO%, PIN%, humidity, temperature) OF
  11.           WHEN 0: PRINT TIME$ "  Humidity = "; humidity "%, temperature = "; temperature "C"
  12.           WHEN 1: PRINT TIME$ "  DHT11/12/22 read failed: wrong number of transitions"
  13.           WHEN 2: PRINT TIME$ "  DHT11/12/22 read failed: checksum error"
  14.           WHEN 3: PRINT TIME$ "  DHT11/12/22 read failed: no response"
  15.         ENDCASE
  16.         WAIT 200
  17.       UNTIL FALSE
  18.       END
  19.  
  20.       REM Read from DHT11/12/22, G% is value returned from FN_gpio_setup, P% is BCM pin number:
  21.       DEF FN_dht_read(G%, P%, RETURN humidity, RETURN temperature)
  22.       LOCAL B%, C%, I%, J%, M%, N%, O%, T%, d&(), t%() : N% = 6000 : REM Adjust for CPU speed
  23.       DIM d&(4), t%(90), C% LOCAL N%*4 + 3
  24.       B% = G% + &34 : M% = 1 << P%
  25.  
  26.       REM Initialise the GPIO pin to be used, happens only on first call:
  27.       PRIVATE initialised
  28.       IF NOT initialised THEN
  29.         PROC_gpio_inp(G%, P%) : PROC_gpio_pull(G%, 2) : REM pull-up
  30.         PROC_gpio_pullclk0(G%, 1 << P%) : PROC_gpio_pullclk0(G%, 0)
  31.         initialised = TRUE
  32.         WAIT 10
  33.       ENDIF
  34.  
  35.       REM Send the start signal to the DHT11/12/22 and sample the data stream it responds with:
  36.       PROC_gpio_out(G%,P%) : G%!&28 = M% : REM Set data line to output and low
  37.       WAIT 2                             : REM Wait 20 ms
  38.       G%!&1C = M% : PROC_gpio_inp(G%,P%) : REM Set data line high and to input
  39.       FOR I% = C% TO C% + N%*4 STEP 4 !I%=!B% : NEXT : REM Sample at ~1 us intervals
  40.  
  41.       REM Scan the captured data for transitions and store their positions in an array:
  42.       FOR I% = C% + 32 TO C% + N%*4 STEP 4
  43.         IF !I% AND M% EOR O% t%(J%) = I% : O% EOR= M% : J% += 1 : IF J% > DIM(t%(),1) EXIT FOR
  44.       NEXT
  45.       IF J% < 5 THEN = 3 : REM If fewer than 5 transitions report no response
  46.       IF O% = 0 ERROR 100, "Sampling period not long enough to capture entire data stream"
  47.  
  48.       REM Measure the total 'low' time (except for the initial pulse) to establish timebase:
  49.       FOR I% = 1 TO J%-2 STEP 2 : T% += t%(I%+1) - t%(I%) : NEXT : T% DIV= 41
  50.  
  51.       REM If too few transitions attempt to infer where the missing pulse(s) was/were:
  52.       IF J% = 79 PROC_dht_fix(t%(), J%)
  53.       IF J% = 81 PROC_dht_fix(t%(), J%)
  54.       IF J% <> 83 THEN = 1 : REM Report uncorrectable wrong number of transitions
  55.  
  56.       REM Decode data using only the high-to-low transitions:
  57.       FOR I% = 0 TO 39 : d&(I% DIV 8) = d&(I% DIV 8) * 2 - ((t%(I%*2+3) - t%(I%*2+1) > 2 * T%)) : NEXT
  58.       IF d&(4) <> (SUM(d&()) - d&(4) AND &FF) THEN
  59.         REM If checksum error attempt to decode using only the low-to-high transitions:
  60.         FOR I% = 0 TO 39 : d&(I% DIV 8) = d&(I% DIV 8) * 2 - ((t%(I%*2+4) - t%(I%*2+2) > 2 * T%)) : NEXT
  61.       ELSE IF d&(4) <> (SUM(d&()) - d&(4) AND &FF) THEN ;
  62.         REM If still a checksum error attempt to decode using widths of high pulses:
  63.         FOR I% = 0 TO 39 : d&(I% DIV 8) = d&(I% DIV 8) * 2 - ((t%(I%*2+3) - t%(I%*2+2) > T%)) : NEXT
  64.       ENDIF
  65.       IF d&(4) <> (SUM(d&()) - d&(4) AND &FF) THEN = 2 : REM Report uncorrectable checksum error
  66.  
  67.       REM Get the humidity and temperature; REM or unREM as required for DHT11/12 or DHT22:
  68.       humidity = d&(0) + d&(1) / 10 : temperature = d&(2) + d&(3) / 10 : REM DHT11/12
  69.       REM humidity = (d&(0) * 256 + d&(1)) / 10 : REM DHT22
  70.       REM temperature = ((d&(2) AND &7F) * 256 + d&(3)) / 10 : IF d&(2) >= &80 temperature *= -1 : REM DHT22
  71.       = 0
  72.  
  73.       REM If the number of transitions was wrong attempt to insert the 'missing' pulse:
  74.       DEF PROC_dht_fix(t%(), RETURN J%)
  75.       LOCAL I%, M%, S%, T%
  76.       FOR I% = 1 TO J%-2 STEP 2
  77.         T% = t%(I%+1) - t%(I%)
  78.         IF T% > M% M% = T% : S% = I%
  79.       NEXT
  80.       FOR I% = J%+1 TO S%+3 STEP -1
  81.         t%(I%) = t%(I%-2)
  82.       NEXT
  83.       t%(S%+1) = t%(S%) + M% * 2 / 5 + 0.5 : REM new rising edge
  84.       t%(S%+2) = t%(S%) + M% * 3 / 5 + 0.5 : REM new falling edge
  85.       J% += 2
  86.       ENDPROC
  87.  
12
ScriptBasic / IUP GUI Toolkit
« Last post by John Spikowski on May 19, 2019, 06:51:37 AM »
I created an IUP distibution for the Raspberry Pi 3B class boards. I also include the IUP extension module for ScriptBasic.

IUP (Portable User Interface) is a multi-platform toolkit for building graphical user interfaces.
IUP Project Site
IUP Download


CD (Canvas Draw) is a vector graphics toolkit with device independent output.
CD Project Site
CD Download


IM (Imaging) is a toolkit for image representation, storage, capture and processing.
IM Project Site
IM Download


ScriptBasic IUP Extension Module Download


Install Instructions

Download / extract each of the zips into a temporary work directory. Run sudo ./install in the IUP, CD and IM directories. If you want to install the development files, run sudo ./install_dev as well. Copy the iup.bas to your /usr/local/include/scriba directory. Copy the pui.so to your /usr/local/lib/scriba directory.

IUP ScriptBasic Online Dictionary
Code: Script BASIC
  1. IMPORT iup.bas
  2.  
  3. servers[0]="dict.org"
  4. servers[1]="dict1.us.dict.org"
  5. servers[2]="all.dict.org"
  6.  
  7. about="""This is a Demo
  8. of the IUP GUI Binding
  9. for Scriptbasic"""
  10.  
  11. ' Initialize IUP
  12. Iup::Open()
  13.  
  14. ' Create main window
  15.  
  16. win = Iup::Create("dialog")
  17.   Iup::SetAttributes(win, "TITLE=\"ScriptBasic IUP Online Dictionary\", SIZE=500x300")
  18.   Iup::SetCallback(win,"CLOSE_CB",ADDRESS(Win_exit()))
  19.  
  20. ' Create container to house ALL GUI objects
  21.  
  22. vbox = Iup::Create("vbox")
  23.   Iup::SetAttributes(vbox, "MARGIN=10x10")
  24.  
  25. ' Create server panel
  26.  
  27. topBox = Iup::Create("hbox")
  28.   Iup::SetAttributes(topBox, "GAP=10")
  29.   Iup::Append(vbox, topBox)
  30. serverFrame = Iup::Create("frame")
  31.   Iup::SetAttributes(serverFrame, "TITLE=Servers, EXPAND=YES")
  32.   Iup::Append(topBox, serverFrame)
  33. serverBox = Iup::Create("hbox")
  34.   Iup::SetAttributes(serverBox, "GAP=5")
  35.   Iup::Append(serverFrame, serverBox)
  36. serverCombo = Iup::Create("list")
  37.   Iup::SetAttributes(serverCombo, "DROPDOWN=YES, SIZE=120x, EXPAND=HORIZONTAL, VALUE=1")
  38.   Iup::Append(serverBox, serverCombo)
  39.   Iup::SetCallback(serverCombo, "ACTION", ADDRESS(serverCombo_selected()))
  40. btnFetch = Iup::Create("button")
  41.   Iup::SetAttributes(btnFetch, "TITLE=Fetch, SIZE = 50x")
  42.   Iup::Append(serverBox, btnFetch)
  43.   Iup::SetCallback(btnFetch, "ACTION", ADDRESS(btnFetch_clicked()))
  44.  
  45. ' Create control panel
  46.  
  47. controlFrame = Iup::Create("frame")
  48.   Iup::SetAttributes(controlFrame, "TITLE=Controls")
  49.   Iup::Append(topBox, controlFrame)
  50. controlBox = Iup::Create("hbox")
  51.   Iup::SetAttributes(controlBox, "GAP=5")
  52.   Iup::Append(controlFrame, controlBox)
  53. btnAbout = Iup::Create("button")
  54.   Iup::SetAttributes(btnAbout, "TITLE=About, SIZE = 50x")
  55.   Iup::Append(controlBox, btnAbout)
  56.   Iup::SetCallback(btnAbout, "ACTION", ADDRESS(btnAbout_clicked()))
  57. btnClear = Iup::Create("button")
  58.   Iup::SetAttributes(btnClear, "TITLE=Clear, SIZE = 50x")
  59.   Iup::Append(controlBox, btnClear)
  60.   Iup::SetCallback(btnClear, "ACTION", ADDRESS(btnClear_clicked()))
  61. btnExit = Iup::Create("button")
  62.   Iup::SetAttributes(btnExit, "TITLE=Exit, SIZE = 50x")
  63.   Iup::Append(controlBox, btnExit)
  64.   Iup::SetCallback(btnExit,"ACTION",ADDRESS(Win_exit()))
  65.  
  66. ' Create dictionary panel
  67.  
  68. dictFrame = Iup::Create("frame")
  69.   Iup::SetAttributes(dictFrame, "TITLE=Dictionaries")
  70.   Iup::Append(vbox, dictFrame)
  71. serverList = Iup::Create("list")
  72.   Iup::SetAttributes(serverList, "EXPAND=YES, VISIBLELINES=1")
  73.   Iup::Append(dictFrame, serverList)
  74.   Iup::SetCallback(serverList, "ACTION", ADDRESS(serverList_selected()))
  75.  
  76. ' Create text part
  77.  
  78. transFrame = IUP::Create("frame")
  79.   Iup::SetAttributes(transFrame, "TITLE=Translation")
  80.   Iup::Append(vbox, transFrame)
  81. text = Iup::Create("text")
  82.   Iup::SetAttributes(text, "MULTILINE=YES, EXPAND=YES")
  83.   Iup::Append(transFrame, text)
  84.  
  85. ' Create entry and search button
  86.  
  87. bottomBox = Iup::Create("hbox")
  88.   Iup::SetAttributes(bottomBox, "GAP=10")
  89.   Iup::Append(vbox, bottomBox)
  90. label = Iup::Create("label")
  91.   Iup::SetAttributes(label, "TITLE=\"Enter Word to Search For:\", SIZE=x12")
  92.   Iup::Append(bottomBox, label)
  93. entry = Iup::Create("text")
  94.   Iup::SetAttributes(entry, "EXPAND=HORIZONTAL")
  95.   Iup::Append(bottomBox, entry)
  96. btnSearch = Iup::Create("button")
  97.   Iup::SetAttributes(btnSearch,"TITLE=Search, SIZE=50x")
  98.   Iup::Append(bottomBox, btnSearch)
  99.   Iup::SetCallback(btnSearch, "ACTION", ADDRESS(btnSearch_clicked()))
  100. chkAll = Iup::Create("toggle")
  101.   Iup::SetAttributes(chkAll, "TITLE=ALL, SIZE=x12")
  102.   Iup::Append(bottomBox, chkAll)
  103. chkUTF = Iup::Create("toggle")
  104.   Iup::SetAttributes(chkUTF, "TITLE=UTF-8, SIZE=x12")
  105.   Iup::Append(bottomBox, chkUTF)
  106.  
  107. ' Add the main GUI container to the Window
  108.  
  109. Iup::Append(win, vbox)
  110.  
  111. ' Setup dialog defaults
  112.  
  113. Iup::Show(win)
  114. Iup::SetFocus(btnFetch)
  115. FOR i = 0 TO UBOUND(servers)
  116.   Iup::SetAttribute(serverCombo, "APPENDITEM", servers[i])
  117. NEXT
  118. Iup::SetAttribute(serverCombo, "VALUE", "1")
  119. Iup::Update(serverCombo)
  120. server_selection = servers[0]
  121.  
  122. ' Main processing loop
  123.  
  124. Iup::MainLoop()
  125. Iup::Close()
  126. END
  127.  
  128. ' Callback routines
  129.  
  130. SUB Win_exit
  131.   Iup::ExitLoop = TRUE
  132. END SUB
  133.  
  134. SUB btnAbout_clicked
  135.   Iup::Message("ABOUT", about)
  136. END SUB
  137.  
  138. SUB serverCombo_selected
  139.   server_selection = Iup::GetListText()
  140. END SUB
  141.  
  142. SUB serverList_selected
  143.   whichDictionary = Iup::GetListText()
  144. END SUB
  145.  
  146. SUB btnFetch_clicked
  147.   LOCAL dat, total, count
  148.   ON ERROR GOTO G_NetError
  149.   OPEN server_selection & ":2628" FOR SOCKET AS #1
  150.   PRINT#1,"SHOW DB\n"
  151.   LINE INPUT#1, dat
  152.   LINE INPUT#1, dat
  153.   count = 0
  154.   WHILE LEFT(dat, 1) <> "."
  155.     LINE INPUT#1, dat
  156.     IF LEFT(dat, 1) <> "." THEN total[count] = TRIM(dat)
  157.     count+=1
  158.   WEND
  159.   PRINT#1,"QUIT\n"
  160.   CLOSE(#1)
  161.   FOR cnt = 0 TO count - 2
  162.     Iup::SetAttribute(serverList, "APPENDITEM", total[cnt])
  163.   NEXT
  164.   Iup::SetAttribute(serverList, "VALUE", "1")
  165.   Iup::Update(serverCombo)
  166.   whichDictionary = total[0]
  167.   EXIT SUB
  168.  
  169.   G_NetError:
  170.   PRINT "Server ",server_selection," not available. (",ERROR,")\n"
  171. END SUB
  172.  
  173. SUB btnClear_clicked
  174.   Iup::ClearList(serverList)
  175.   Iup::SetAttribute(text, "VALUE", "")
  176.   Iup::SetAttribute(entry, "VALUE", "")
  177. END SUB
  178.  
  179. SUB btnSearch_clicked
  180.   LOCAL dict, dat, total, info
  181.   IUP::SetAttribute(text, "VALUE","Fetching....")
  182.   ON ERROR GOTO L_NetError
  183.   dict = LEFT(whichDictionary, INSTR(whichDictionary, " "))
  184.   OPEN server_selection & ":2628" FOR SOCKET AS 1
  185.   IF Iup::GetAttribute(chkAll, "VALUE") THEN
  186.     PRINT#1,"DEFINE * " & Iup::GetAttribute(entry,"VALUE") & "\n"
  187.   ELSE
  188.     PRINT#1,"DEFINE " & dict & " " & Iup::GetAttribute(entry,"VALUE") & "\n"
  189.   END IF
  190.   REPEAT
  191.     LINE INPUT#1, dat
  192.     IF LEFT(dat, 3) = "151" THEN
  193.       total$ &= "------------------------------\r\n"
  194.       total$ &= RIGHT(dat, LEN(dat) - LEN(Iup::GetAttribute(entry, "VALUE")) - LEN(dict))
  195.       total$ &= "------------------------------\r\n"
  196.       REPEAT
  197.         LINE INPUT#1, info
  198.         info = REPLACE(info, CHR(34), CHR(92) & CHR(34))
  199.         IF LEFT(info, 1) <> "." THEN total &= TRIM(info) & "\n"
  200.       UNTIL LEFT(info, 1) = "."
  201.       total &= "\n"
  202.     END IF
  203.   UNTIL LEFT(dat, 3) = "250" OR VAL(LEFT(dat, 3)) > 499
  204.   PRINT#1,"QUIT\n"
  205.   CLOSE(#1)
  206.   IF LEFT(dat, 3) = "552" THEN
  207.     total = "No match found."
  208.   ELSE IF LEFT(dat, 3) = "501" THEN
  209.     total = "Select a dictionary first!"
  210.   ELSE IF LEFT(dat, 3) = "550" THEN
  211.     total = "Invalid database!"
  212.   END IF
  213.   Iup::SetAttribute(text, "VALUE", total)
  214. EXIT SUB
  215.  
  216. L_NetError:
  217.   dat[0] = "Could not lookup word! (" & ERROR & ")"
  218.   Iup::SetAttribute(text, "VALUE", dat)
  219. END SUB
  220.  
13
BBC BASIC / BBC BASIC for SDL 2.0 version 1.03a released
« Last post by Richard Russell on May 13, 2019, 01:21:02 PM »
I have released version 1.03a of BBC BASIC for SDL 2.0, the cross-platform programming language for Windows, MacOS, Linux, Raspbian (Raspberry Pi), Android and iOS.  The changes in this version are as follows:

  • IDEs / Compiler

    BBCEdit: Andy Parkes' alternative IDE has been updated to fix a few bugs.

    SDLIDE: The Search BASIC Programs utility has been ported from BB4W and can be found in the Utilities menu.  It searches for a given string in both tokenised (.bbc) and plain-text (.bas) programs, recursively searching sub-directories.

  • BASIC Interpreter / Run Time Engine

    @dir$ and @lib$ now use backslash path delimiters consistently in Windows.  This is only a cosmetic change, since Windows will accept forward slashes at the API level, but eliminates an anomaly.

    Mouse wheel rotations are now ignored at the immediate-mode prompt and in the INPUT statement.

  • Libraries

    The dlglib.bbc library has been extended to support multi-column list boxes.

    The File Selector dialogue used in recorder.bbc and compiler.bbc has been hived-off into a separate library, filedlg.bbc, so that it is easier to use from other programs.

  • Example Programs

    mandel.bbc: This has been completely rewritten so that the calculations are performed on the GPU rather than the CPU, making it no longer x86-specific (and allowing it to run in iOS despite assembler code not being permitted).

This new version may be downloaded, for all the supported platforms, from the usual location.  The GitHub repository  has been updated (used to build the MacOS, Raspberry Pi, iOS and 64-bit Linux editions, currently).
14
BBC BASIC / Re: Simple GPIO demo
« Last post by John Spikowski on April 30, 2019, 10:44:31 PM »
/dev/i2c-* is what I used for the ScriptBasic SHAT extension module.

Thanks for the info how this stuff works!
15
BBC BASIC / Re: Simple GPIO demo
« Last post by Richard Russell on April 30, 2019, 10:19:02 PM »
Have you had any luck with the RPi Sense HAT board? Will your GPIO library allow use of the Sense HAT emulator that comes with Raspbian?

I don't have a Sense HAT here.  My understanding is that it's an I2C device and therefore not really accessible via the GPIO (I know that the I2C clock and data lines appear on GPIO pins, but it would be a bit daft to try to interface with I2C devices that way!).   So to that extent my GPIO library isn't really relevant to the Sense HAT, but BBC BASIC could no doubt access it via the virtual I2C device at /dev/i2c-*.
16
BBC BASIC / Re: Simple GPIO demo
« Last post by John Spikowski on April 30, 2019, 08:29:37 PM »
 Very cool Richard. Have you had any luck with the RPi Sense HAT board? Will your GPIO library allow use of the Sense HAT emulator that comes with Raspbian?
17
BBC BASIC / Simple GPIO demo
« Last post by Richard Russell on April 30, 2019, 05:00:57 PM »
This is a very simple demo of the Raspberry Pi's GPIO being controlled by BBC BASIC, using the supplied 'gpiolib' library.  It cycles through six of the outputs, setting each one high in sequence.  The code is listed below, and this is the result (with LEDs fitted to monitor the outputs):



Code: [Select]
      REM Initialise GPIO:
      INSTALL @lib$ + "gpiolib"
      GPIO% = FN_gpio_setup

      REM Pin numbers to activate, in sequence:
      DATA 17, 23, 25, 12, 16, 26

      REM Set to input first:
      RESTORE
      FOR I% = 1 TO 6
        READ pin%
        PROC_gpio_inp(GPIO%, pin%)
      NEXT

      REM Set pins to output:
      RESTORE
      FOR I% = 1 TO 6
        READ pin%
        PROC_gpio_out(GPIO%, pin%)
      NEXT

      REM Cycle LEDs in sequence:
      REPEAT
        RESTORE
        FOR I% = 1 TO 6
          READ pin%
          PROC_gpio_set(GPIO%, 2^pin%)
          WAIT 20
          PROC_gpio_clr(GPIO%, 2^pin%)
        NEXT
      UNTIL FALSE
      END
18
ScriptBasic / Sense HAT Unchained
« Last post by John Spikowski on April 27, 2019, 06:12:51 AM »
Sense HAT Unchained

The LED and Joystick functions will be in a separate extension module called SLED.

Code: C
  1. /* Raspberry Pi Sense HAT
  2. UXLIBS: -lpthread -lm -lc /usr/lib/gcc/arm-linux-gnueabihf/6/libgcc.a
  3. */
  4.  
  5. #include <stdio.h>
  6. #include <unistd.h>
  7. #include <stdlib.h>
  8. #include <stdint.h>
  9. #include <string.h>
  10. #include <fcntl.h>
  11. #include <sys/ioctl.h>
  12. #include <linux/i2c-dev.h>
  13. #include "../../basext.h"
  14.  
  15.  
  16. /***************************
  17.  Extension Module Functions
  18. ***************************/
  19.  
  20. typedef struct _ModuleObject {
  21.   void *HandleArray;
  22. }ModuleObject,*pModuleObject;
  23.  
  24.  
  25. besVERSION_NEGOTIATE
  26.   return (int)INTERFACE_VERSION;
  27. besEND
  28.  
  29.  
  30. besSUB_START
  31.   pModuleObject p;
  32.  
  33.   besMODULEPOINTER = besALLOC(sizeof(ModuleObject));
  34.   if( besMODULEPOINTER == NULL )return 0;
  35.  
  36.   p = (pModuleObject)besMODULEPOINTER;
  37.   return 0;
  38. besEND
  39.  
  40.  
  41. besSUB_FINISH
  42.   pModuleObject p;
  43.  
  44.   p = (pModuleObject)besMODULEPOINTER;
  45.   if( p == NULL )return 0;
  46.   return 0;
  47. besEND
  48.  
  49.  
  50. /***************
  51.  GPIO Functions
  52. ***************/
  53.  
  54. // I2C file handles
  55. static int file_bus = -1; // i2c bus
  56. static int file_hum = -1; // humidity/temp sensor
  57. static int file_pres = -1; // pressure sensor
  58. static int file_acc = -1; // accelerometer/gyro
  59. static int file_mag = -1; // magnetometer
  60.  
  61. static int i2cRead(int iHandle, unsigned char ucAddr, unsigned char *buf, int iLen);
  62. static int i2cWrite(int iHandle, unsigned char ucAddr, unsigned char *buf, int iLen);
  63. // humidity/temp calibration values
  64. static int H0_rH_x2, H1_rH_x2, T0_degC_x8;
  65. static int T1_degC_x8, H0_T0_OUT;
  66. static int H1_T0_OUT, T0_OUT, T1_OUT;
  67.  
  68. static int i2cRead(int iHandle, unsigned char ucAddr, unsigned char *buf, int iLen)
  69. {
  70. int rc;
  71.  
  72.   rc = write(iHandle, &ucAddr, 1);
  73.   if (rc == 1)
  74.   {
  75.     rc = read(iHandle, buf, iLen);
  76.   }
  77.   return rc;
  78. } /* i2cRead() */
  79.  
  80. static int i2cWrite(int iHandle, unsigned char ucAddr, unsigned char *buf, int iLen)
  81. {
  82. unsigned char ucTemp[512];
  83. int rc;
  84.  
  85.   if (iLen > 511 || iLen < 1 || buf == NULL)
  86.     return -1; // invalid write
  87.  
  88.   ucTemp[0] = ucAddr; // send the register number first
  89.   memcpy(&ucTemp[1], buf, iLen); // followed by the data
  90.   rc = write(iHandle, ucTemp, iLen+1);
  91.   return rc-1;
  92.  
  93. } /* i2cWrite() */
  94.  
  95.  
  96. besFUNCTION(shInit)
  97.   int iChannel;
  98.  
  99.   besARGUMENTS("i")
  100.     &iChannel
  101.   besARGEND
  102.  
  103.   unsigned char ucTemp[32];
  104.   char filename[32];
  105.  
  106.   sprintf(filename, "/dev/i2c-%d", iChannel);
  107.   if ((file_bus = open(filename, O_RDWR)) < 0)
  108.   {
  109.     fprintf(stderr, "Failed to open the i2c bus\n");
  110.     besRETURN_LONG(-1);
  111.   }
  112.  
  113.  
  114.   file_acc = open(filename, O_RDWR);
  115.   if (ioctl(file_acc, I2C_SLAVE, 0x6a) < 0)
  116.   {
  117.     fprintf(stderr, "Failed to acquire bus for accelerometer\n");
  118.     goto badexit;
  119.   }
  120.  
  121.   file_mag = open(filename, O_RDWR);
  122.   if (ioctl(file_mag, I2C_SLAVE, 0x1c) < 0)
  123.   {
  124.     fprintf(stderr, "Failed to acquire bus for magnetometer\n");
  125.     goto badexit;
  126.   }
  127.  
  128.   file_hum = open(filename, O_RDWR);
  129.   if (ioctl(file_hum, I2C_SLAVE, 0x5f) < 0)
  130.   {
  131.     fprintf(stderr, "Failed to acquire bus for Humidity sensor\n");
  132.     goto badexit;
  133.   }
  134.   file_pres = open(filename, O_RDWR);
  135.   if (ioctl(file_pres, I2C_SLAVE, 0x5C) < 0)
  136.   {
  137.     fprintf(stderr, "Failed to aquire bus for Pressure sensor\n");
  138.     goto badexit;
  139.   }
  140.   // Prepare humidity sensor
  141.   i2cRead(file_hum, 0x10, ucTemp, 1); // AV_CONF
  142.   ucTemp[0] &= 0xc0;
  143.   ucTemp[0] |= 0x1b; // avgt=16, avgh=32
  144.   i2cWrite(file_hum, 0x10, ucTemp, 1);
  145.  
  146.   i2cRead(file_hum, 0x20+0x80, ucTemp, 3); // get CTRL_REG 1-3
  147.   ucTemp[0] &= 0x78; // keep reserved bits
  148.   ucTemp[0] |= 0x81; // turn on + 1Hz sample rate
  149.   ucTemp[1] &= 0x7c; // turn off heater + boot + one shot
  150.   i2cWrite(file_hum, 0x20+0x80, ucTemp, 3); // turn on + set sample rate
  151.  
  152.   // Get the H/T calibration values
  153.   i2cRead(file_hum, 0x30+0x80, ucTemp, 16);
  154.   H0_rH_x2 = ucTemp[0];
  155.   H1_rH_x2 = ucTemp[1];
  156.   T0_degC_x8 = ucTemp[2];
  157.   T1_degC_x8 = ucTemp[3];
  158.   T0_degC_x8 |= ((ucTemp[5] & 0x3) << 8); // 2 msb bits
  159.   T1_degC_x8 |= ((ucTemp[5] & 0xc) << 6);
  160.   H0_T0_OUT = ucTemp[6] | (ucTemp[7] << 8);
  161.   H1_T0_OUT = ucTemp[10] | (ucTemp[11] << 8);
  162.   T0_OUT = ucTemp[12] | (ucTemp[13] << 8);
  163.   T1_OUT = ucTemp[14] | (ucTemp[15] << 8);
  164.   if (H0_T0_OUT > 32767) H0_T0_OUT -= 65536; // signed
  165.   if (H1_T0_OUT > 32767) H1_T0_OUT -= 65536;
  166.   if (T0_OUT > 32767) T0_OUT -= 65536;
  167.   if (T1_OUT > 32767) T1_OUT -= 65536;
  168.  
  169.   // prepare pressure sensor
  170.   ucTemp[0] = 0x90; // turn on and set 1Hz update
  171.   i2cWrite(file_pres, 0x20, ucTemp, 1);
  172.  
  173.   // Init magnetometer
  174.   ucTemp[0] = 0x48; // output data rate/power mode
  175.   ucTemp[1] = 0x00; // default scale
  176.   ucTemp[2] = 0x00; // continuous conversion
  177.   ucTemp[3] = 0x08; // high performance mode
  178.   i2cWrite(file_mag, 0x20+0x80, ucTemp, 4);
  179.  
  180.   // Init accelerometer/gyroscope
  181.   ucTemp[0] = 0x60; // 119hz accel
  182.   i2cWrite(file_acc, 0x20, ucTemp, 1);
  183.   ucTemp[0] = 0x38; // enable gyro on all axes
  184.   i2cWrite(file_acc, 0x1e, ucTemp, 1);
  185.         ucTemp[0] = 0x28; // data rate + full scale + bw selection
  186.   // bits:        ODR_G2 | ODR_G1 | ODR_G0 | FS_G1 | FS_G0 | 0 | BW_G1 | BW_G0
  187.   // 0x28 = 14.9hz, 500dps
  188.   i2cWrite(file_acc, 0x10, ucTemp, 1); // gyro ctrl_reg1
  189.  
  190.   besRETURN_LONG(1);
  191.  
  192.   // problems opening the I2C handles/addresses
  193.   badexit:
  194.   if (file_hum != -1)
  195.   {
  196.     close(file_hum);
  197.     file_hum = -1;
  198.   }
  199.   if (file_pres != -1)
  200.   {
  201.     close(file_pres);
  202.     file_pres = -1;
  203.   }
  204.   if (file_acc != -1)
  205.   {
  206.     close(file_acc);
  207.     file_acc = -1;
  208.   }
  209.   if (file_mag != -1)
  210.   {
  211.     close(file_mag);
  212.     file_mag = -1;
  213.   }
  214.   besRETURN_LONG(0);
  215. besEND
  216.  
  217.  
  218. besFUNCTION(shGetAccel)
  219.   VARIABLE Argument1;
  220.   VARIABLE Argument2;
  221.   VARIABLE Argument3;
  222.   unsigned long __refcount_;
  223.   LEFTVALUE Lval1;
  224.   LEFTVALUE Lval2;
  225.   LEFTVALUE Lval3;
  226.  
  227.   Argument1 = besARGUMENT(1);
  228.   besLEFTVALUE(Argument1,Lval1);
  229.   besRELEASE(*Lval1);
  230.   *Lval1 = NULL;
  231.  
  232.   Argument2 = besARGUMENT(2);
  233.   besLEFTVALUE(Argument2,Lval2);
  234.   besRELEASE(*Lval2);
  235.   *Lval2 = NULL;
  236.  
  237.   Argument3 = besARGUMENT(3);
  238.   besLEFTVALUE(Argument3,Lval3);
  239.   besRELEASE(*Lval3);
  240.   *Lval3 = NULL;
  241.  
  242.   unsigned char ucTemp[8];
  243.   int rc;
  244.  
  245.   *Lval1 = besNEWLONG;
  246.   *Lval2 = besNEWLONG;
  247.   *Lval3 = besNEWLONG;
  248.  
  249.   rc = i2cRead(file_acc, 0x28+0x80, ucTemp, 6);
  250.   if (rc == 6)
  251.   {
  252.     int x, y, z;
  253.  
  254.     x = ucTemp[0] + (ucTemp[1] << 8);
  255.     y = ucTemp[2] + (ucTemp[3] << 8);
  256.     z = ucTemp[4] + (ucTemp[5] << 8);
  257.     // fix the signed values
  258.     if (x > 32767) x -= 65536;
  259.     if (y > 32767) y -= 65536;
  260.     if (z > 32767) z -= 65536;
  261.  
  262.     LONGVALUE(*Lval1) = x;
  263.     LONGVALUE(*Lval2) = y;
  264.     LONGVALUE(*Lval3) = z;
  265.     besRETURN_LONG(1);
  266.   }
  267.   besRETURN_LONG(0);
  268. besEND
  269.  
  270.  
  271. besFUNCTION(shGetGyro)
  272.   VARIABLE Argument1;
  273.   VARIABLE Argument2;
  274.   VARIABLE Argument3;
  275.   unsigned long __refcount_;
  276.   LEFTVALUE Lval1;
  277.   LEFTVALUE Lval2;
  278.   LEFTVALUE Lval3;
  279.  
  280.   Argument1 = besARGUMENT(1);
  281.   besLEFTVALUE(Argument1,Lval1);
  282.   besRELEASE(*Lval1);
  283.   *Lval1 = NULL;
  284.  
  285.   Argument2 = besARGUMENT(2);
  286.   besLEFTVALUE(Argument2,Lval2);
  287.   besRELEASE(*Lval2);
  288.   *Lval2 = NULL;
  289.  
  290.   Argument3 = besARGUMENT(3);
  291.   besLEFTVALUE(Argument3,Lval3);
  292.   besRELEASE(*Lval3);
  293.   *Lval3 = NULL;
  294.  
  295.   unsigned char ucTemp[8];
  296.   int rc;
  297.  
  298.   *Lval1 = besNEWLONG;
  299.   *Lval2 = besNEWLONG;
  300.   *Lval3 = besNEWLONG;
  301.  
  302.   rc = i2cRead(file_acc, 0x18+0x80, ucTemp, 6);
  303.   if (rc == 6)
  304.   {
  305.     LONGVALUE(*Lval1) = ucTemp[0] + (ucTemp[1] << 8);
  306.     LONGVALUE(*Lval2) = ucTemp[2] + (ucTemp[3] << 8);
  307.     LONGVALUE(*Lval3) = ucTemp[4] + (ucTemp[5] << 8);
  308.     besRETURN_LONG(1);
  309.   }
  310.   besRETURN_LONG(0);
  311. besEND
  312.  
  313.  
  314. besFUNCTION(shGetMagneto)
  315.   VARIABLE Argument1;
  316.   VARIABLE Argument2;
  317.   VARIABLE Argument3;
  318.   unsigned long __refcount_;
  319.   LEFTVALUE Lval1;
  320.   LEFTVALUE Lval2;
  321.   LEFTVALUE Lval3;
  322.  
  323.   Argument1 = besARGUMENT(1);
  324.   besLEFTVALUE(Argument1,Lval1);
  325.   besRELEASE(*Lval1);
  326.   *Lval1 = NULL;
  327.  
  328.   Argument2 = besARGUMENT(2);
  329.   besLEFTVALUE(Argument2,Lval2);
  330.   besRELEASE(*Lval2);
  331.   *Lval2 = NULL;
  332.  
  333.   Argument3 = besARGUMENT(3);
  334.   besLEFTVALUE(Argument3,Lval3);
  335.   besRELEASE(*Lval3);
  336.   *Lval3 = NULL;
  337.  
  338.   unsigned char ucTemp[8];
  339.   int rc;
  340.  
  341.   *Lval1 = besNEWLONG;
  342.   *Lval2 = besNEWLONG;
  343.   *Lval3 = besNEWLONG;
  344.  
  345.   rc = i2cRead(file_mag, 0x28+0x80, ucTemp, 6);
  346.   if (rc == 6)
  347.   {
  348.     int x, y, z;
  349.     x = ucTemp[0] + (ucTemp[1] << 8);
  350.     y = ucTemp[2] + (ucTemp[3] << 8);
  351.     z = ucTemp[4] + (ucTemp[5] << 8);
  352.     // fix signed values
  353.     if (x > 32767) x -= 65536;
  354.     if (y > 32767) y -= 65536;
  355.     if (z > 32767) z -= 65536;
  356.  
  357.     LONGVALUE(*Lval1) = x;
  358.     LONGVALUE(*Lval2) = y;
  359.     LONGVALUE(*Lval3) = z;
  360.     besRETURN_LONG(1);
  361.   }
  362.   besRETURN_LONG(0);
  363. besEND
  364.  
  365. besFUNCTION(shGetPressure)
  366.   VARIABLE Argument1;
  367.   VARIABLE Argument2;
  368.   unsigned long __refcount_;
  369.   LEFTVALUE Lval1;
  370.   LEFTVALUE Lval2;
  371.  
  372.   Argument1 = besARGUMENT(1);
  373.   besLEFTVALUE(Argument1,Lval1);
  374.   besRELEASE(*Lval1);
  375.   *Lval1 = NULL;
  376.  
  377.   Argument2 = besARGUMENT(2);
  378.   besLEFTVALUE(Argument2,Lval2);
  379.   besRELEASE(*Lval2);
  380.   *Lval2 = NULL;
  381.  
  382.   unsigned char ucTemp[8];
  383.   int rc, P, T;
  384.  
  385.   *Lval1 = besNEWLONG;
  386.   *Lval2 = besNEWLONG;
  387.  
  388.   if (file_pres != -1)
  389.   {
  390.     rc = i2cRead(file_pres, 0x28+0x80, ucTemp, 5);
  391.     if (rc == 5)
  392.     {
  393.       P = ucTemp[0] + (ucTemp[1]<<8) + (ucTemp[2]<<16);
  394.       LONGVALUE(*Lval1) = P / 4096; //hPa
  395.       T = ucTemp[3] + (ucTemp[4] << 8);
  396.       if (T > 32767) T -= 65536; // twos compliment
  397.       T = 425 + (T / 48); // 42.5 + T value/480
  398.       LONGVALUE(*Lval2) = T;
  399.     }
  400.     besRETURN_LONG(1);
  401.   }
  402.   besRETURN_LONG(0);
  403. besEND
  404.  
  405.  
  406. besFUNCTION(shGetTempHumid)
  407.   VARIABLE Argument1;
  408.   VARIABLE Argument2;
  409.   unsigned long __refcount_;
  410.   LEFTVALUE Lval1;
  411.   LEFTVALUE Lval2;
  412.  
  413.   Argument1 = besARGUMENT(1);
  414.   besLEFTVALUE(Argument1,Lval1);
  415.   besRELEASE(*Lval1);
  416.   *Lval1 = NULL;
  417.  
  418.   Argument2 = besARGUMENT(2);
  419.   besLEFTVALUE(Argument2,Lval2);
  420.   besRELEASE(*Lval2);
  421.   *Lval2 = NULL;
  422.  
  423.   unsigned char ucTemp[4];
  424.   int rc;
  425.   int H_T_out, T_out, T0_degC, T1_degC;
  426.   int H0_rh, H1_rh;
  427.   int tmp;
  428.  
  429.   *Lval1 = besNEWLONG;
  430.   *Lval2 = besNEWLONG;
  431.  
  432.   rc = i2cRead(file_hum, 0x28+0x80, ucTemp, 4);
  433.   if (rc == 4)
  434.   {
  435.     H_T_out = ucTemp[0] + (ucTemp[1] << 8);
  436.     T_out = ucTemp[2] + (ucTemp[3] << 8);
  437.     if (H_T_out > 32767) H_T_out -=65536;
  438.     if (T_out > 32767) T_out -= 65536;
  439.     T0_degC = T0_degC_x8 / 8;
  440.     T1_degC = T1_degC_x8 / 8;
  441.     H0_rh = H0_rH_x2 / 2;
  442.     H1_rh = H1_rH_x2 / 2;
  443.     tmp = (H_T_out - H0_T0_OUT) * (H1_rh - H0_rh)*10;
  444.     LONGVALUE(*Lval2) = tmp / (H1_T0_OUT - H0_T0_OUT) + H0_rh*10;
  445.     tmp = (T_out - T0_OUT) * (T1_degC - T0_degC)*10;
  446.     LONGVALUE(*Lval1) = tmp / (T1_OUT - T0_OUT) + T0_degC*10;
  447.     besRETURN_LONG(1);
  448.   }
  449.   besRETURN_LONG(0); // not ready
  450. besEND
  451.  
  452. besFUNCTION(shShutdown)
  453.   // Close all I2C file handles
  454.   if (file_bus != -1) close(file_bus);
  455.   if (file_hum != -1) close(file_hum);
  456.   if (file_pres != -1) close(file_pres);
  457.   if (file_acc != -1) close(file_acc);
  458.   if (file_mag != -1) close(file_mag);
  459.   file_bus = file_hum = file_pres = file_acc = file_mag = -1;
  460. besEND
  461.  

Code: Script BASIC
  1. ' Raspberry Pi Sense HAT
  2.  
  3. MODULE SHAT
  4.  
  5. DECLARE SUB  ::Init          ALIAS  "shInit"          LIB  "shat"
  6. DECLARE SUB  ::GetAccel      ALIAS  "shGetAccel"      LIB  "shat"
  7. DECLARE SUB  ::GetGyro       ALIAS  "shGetGyro"       LIB  "shat"
  8. DECLARE SUB  ::GetMagneto    ALIAS  "shGetMagneto"    LIB  "shat"
  9. DECLARE SUB  ::GetPressure   ALIAS  "shGetPressure"   LIB  "shat"
  10. DECLARE SUB  ::GetTempHumid  ALIAS  "shGetTempHumid"  LIB  "shat"
  11. DECLARE SUB  ::Shutdown      ALIAS  "shShutdown"      LIB  "shat"
  12.  
  13. END MODULE
  14.  


Code: Script BASIC
  1. IMPORT shat.bas
  2.  
  3. SHAT::Init(1)
  4.  
  5. SHAT::GetPressure(pressure, ptemp)
  6. SHAT::GetTempHumid(htemp, humid)
  7. SHAT::GetAccel(Ax, Ay, Az)
  8. SHAT::GetMagneto(Mx, My, Mz)
  9. SHAT::GetGyro(Gx, Gy, Gz)
  10.  
  11. PRINT "Pressure: ", pressure, "\n"
  12. PRINT "P-Temp: ", ptemp,"\n"
  13. PRINT "Humidity: ", humid,"\n"
  14. PRINT "H-Temp: ", htemp,"\n"
  15. PRINT "Accel-x: ", Ax, "\n"
  16. PRINT "Accel-y: ", Ay, "\n"
  17. PRINT "Accel-z: ", Az, "\n"
  18. PRINT "Mag-x: ", Mx, "\n"
  19. PRINT "Mag-y: ", My, "\n"
  20. PRINT "Mag-z: ", Mz, "\n"
  21. PRINT "Gyro-x: ", Gx, "\n"
  22. PRINT "Gyro-y: ", Gy, "\n"
  23. PRINT "Gyro-z: ", Gz, "\n"
  24.  
  25. SHAT::Shutdown
  26.  


pi@RPi3B:~/sbrpi/examples $ time scriba testhat.sb
Pressure: 1026
P-Temp: 320
Humidity: 287
H-Temp: 325
Accel-x: -443
Accel-y: -186
Accel-z: 15830
Mag-x: -1050
Mag-y: 2290
Mag-z: -1314
Gyro-x: 211
Gyro-y: 65435
Gyro-z: 74

real   0m0.043s
user   0m0.014s
sys   0m0.013s
pi@RPi3B:~/sbrpi/examples $



19
ScriptBasic / Re: RPi GPIO Support
« Last post by John Spikowski on April 26, 2019, 07:36:36 PM »
Hippy,

I believe the routines themselves are doing the low level memory access. I would like to know how I can use this library with the RPi Sense HAT board/emulator.
20
ScriptBasic / Re: RPi GPIO Support
« Last post by John Spikowski on April 26, 2019, 06:58:30 AM »
I was looking at the fb.h include and for grins I tried this little script. To my surprise the Sense HAT LEDs turned on. (one bright green and two blueish)

I have no idea what this did but it's interesting just opening the device with ScriptBasic produced a visible response.

Code: Script BASIC
  1. OPEN "/dev/fb1" FOR BINARY AS #1
  2. PRINT #1, 0x4600
  3. CLOSE(1)
  4.  

#define FBIOGET_VSCREENINFO   0x4600

Pages: 1 [2] 3 4