mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Merge pull request #1785 from openmv/pylint
misc: Add Python linter workflow.
This commit is contained in:
commit
a9e5c41a71
51
.github/workflows/python-linter.yml
vendored
Normal file
51
.github/workflows/python-linter.yml
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
|
||||||
|
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
||||||
|
|
||||||
|
name: '🔎 Python Linter'
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
paths:
|
||||||
|
- 'scripts/libraries/*.py'
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
types:
|
||||||
|
- opened
|
||||||
|
- reopened
|
||||||
|
- synchronize
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
paths:
|
||||||
|
- 'scripts/libraries/*.py'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
python-version: ["3.10"]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: '⏳ Checkout repository'
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: '🐍 Set up Python ${{ matrix.python-version }}'
|
||||||
|
uses: actions/setup-python@v3
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.python-version }}
|
||||||
|
|
||||||
|
- name: '🛠 Install dependencies'
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
python -m pip install flake8 pytest
|
||||||
|
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
|
||||||
|
|
||||||
|
- name: '😾 Lint with flake8'
|
||||||
|
run: |
|
||||||
|
# stop the build if there are Python syntax errors or undefined names
|
||||||
|
flake8 --count --select=E9,F63,F7,F82 --ignore=F821 --show-source --statistics scripts/libraries/
|
||||||
|
flake8 --count --max-complexity=15 --max-line-length=120 --ignore=F821,E722,E741,C901,E713,W605,E203,W503,F841,F403,F405 --statistics scripts/libraries/
|
||||||
63
scripts/libraries/I2C_Lidar_Lite_V3_example_code.py
Normal file
63
scripts/libraries/I2C_Lidar_Lite_V3_example_code.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# OpenMV M7 I2C interface with Garmin Lidar Lite V3 - By: Grant Phillips - Sun Apr 8 2018
|
||||||
|
|
||||||
|
|
||||||
|
# Returns a basic distance reading from the lidar in cm for the target point and prints to console
|
||||||
|
# Uses default lidar settings. For more advanced settings, see the I2C commands in the manual:
|
||||||
|
# https://static.garmin.com/pumac/LIDAR_Lite_v3_Operation_Manual_and_Technical_Specifications.pdf
|
||||||
|
|
||||||
|
# I2C Control of LIDAR Lite V3
|
||||||
|
# 1. Write 0x04 to register 0x00
|
||||||
|
# 2. Read register 0x01. Repeat until bit 0 (LSB) goes low.
|
||||||
|
# 3. Read two bytes from 0x8f (high byte 0x0f then low byte 0x10) to obtain 16 bit measurement in cm
|
||||||
|
|
||||||
|
# HARDWARE CONNECTIONS:
|
||||||
|
# Connect the lidar SCL line (green) to I2C 2 SCL on openMV (Pin 4)
|
||||||
|
# Connect the lidar SDA line (blue) to I2C 2 SDA on openMV (pin 5)
|
||||||
|
# 680uF filter capacitor in parallel with the lidar
|
||||||
|
# 10k pullup resistors on the SCL and SDA lines to +5Vdc
|
||||||
|
|
||||||
|
|
||||||
|
import pyb
|
||||||
|
from pyb import I2C
|
||||||
|
|
||||||
|
|
||||||
|
lidarReady = bytearray([0xFF]) # holds the returned data for ready check
|
||||||
|
lidarReadyCheck = bytes([1]) # to compare bit 0 of lidarReady
|
||||||
|
|
||||||
|
startBuf = bytearray([0x00, 0x04]) # step 1 address and data
|
||||||
|
readyBuf = bytearray([0x01]) # step 2 address for readiness check
|
||||||
|
distBuf = bytearray([0x8F]) # step 3 address for distance reading
|
||||||
|
distance = -1 # variable for distance reading
|
||||||
|
|
||||||
|
# I2C setup
|
||||||
|
Lidar = I2C(2, I2C.MASTER) # initialise I2C 2 bus in master mode
|
||||||
|
|
||||||
|
|
||||||
|
while True:
|
||||||
|
distance = -1 # reset to -1 so we know when we get a real reading
|
||||||
|
|
||||||
|
try: # handles errors thrown up if we have an I2C error
|
||||||
|
# Step 1 Write 0x04 to register 0x00
|
||||||
|
Lidar.send(startBuf, 0x62) # this is making it read (laser visible)
|
||||||
|
|
||||||
|
# Step 2 Read register 0x01 and wait for bit 0 to go low
|
||||||
|
while lidarReady[0] & readyBuf[0]:
|
||||||
|
Lidar.send(readyBuf, 0x62)
|
||||||
|
lidarReady = Lidar.recv(1, 0x62)
|
||||||
|
pyb.delay(50) # This seems to help reduce errors on the I2C bus
|
||||||
|
lidarReady = bytearray([0xFF]) # reset the ready check data for next reading
|
||||||
|
|
||||||
|
# Step 3 Read the distance measurement from 0x8f (0x0f and 0x10)
|
||||||
|
Lidar.send(distBuf, 0x62)
|
||||||
|
dist = Lidar.recv(2, 0x62)
|
||||||
|
distance = dist[0]
|
||||||
|
distance <<= 8 # move 2 bytes into a 16 bit int
|
||||||
|
distance |= dist[1]
|
||||||
|
pyb.delay(100) # allow time between readings, can go faster but more errors
|
||||||
|
|
||||||
|
except OSError: # reninitialise i2c bus if error
|
||||||
|
Lidar.init(I2C.MASTER)
|
||||||
|
print("error, reinitialising")
|
||||||
|
|
||||||
|
if distance > -1:
|
||||||
|
print("Distance:", distance, "cm")
|
||||||
@ -1,3 +1,6 @@
|
|||||||
from apds9960.device import APDS9960, uAPDS9960
|
from apds9960.device import APDS9960, uAPDS9960
|
||||||
|
|
||||||
__all__ = [ 'APDS9960', 'uAPDS9960', ]
|
__all__ = [
|
||||||
|
"APDS9960",
|
||||||
|
"uAPDS9960",
|
||||||
|
]
|
||||||
|
|||||||
@ -7,7 +7,7 @@ APDS9960_GESTURE_SENSITIVITY_1 = 50
|
|||||||
APDS9960_GESTURE_SENSITIVITY_2 = 20
|
APDS9960_GESTURE_SENSITIVITY_2 = 20
|
||||||
|
|
||||||
# APDS9960 device IDs
|
# APDS9960 device IDs
|
||||||
APDS9960_DEV_ID = [0xab, 0x9c, 0xa8, -0x55]
|
APDS9960_DEV_ID = [0xAB, 0x9C, 0xA8, -0x55]
|
||||||
|
|
||||||
# APDS9960 times
|
# APDS9960 times
|
||||||
APDS9960_TIME_FIFO_PAUSE = 30
|
APDS9960_TIME_FIFO_PAUSE = 30
|
||||||
@ -21,11 +21,11 @@ APDS9960_REG_AILTH = 0x85
|
|||||||
APDS9960_REG_AIHTL = 0x86
|
APDS9960_REG_AIHTL = 0x86
|
||||||
APDS9960_REG_AIHTH = 0x87
|
APDS9960_REG_AIHTH = 0x87
|
||||||
APDS9960_REG_PILT = 0x89
|
APDS9960_REG_PILT = 0x89
|
||||||
APDS9960_REG_PIHT = 0x8b
|
APDS9960_REG_PIHT = 0x8B
|
||||||
APDS9960_REG_PERS = 0x8c
|
APDS9960_REG_PERS = 0x8C
|
||||||
APDS9960_REG_CONFIG1 = 0x8d
|
APDS9960_REG_CONFIG1 = 0x8D
|
||||||
APDS9960_REG_PPULSE = 0x8e
|
APDS9960_REG_PPULSE = 0x8E
|
||||||
APDS9960_REG_CONTROL = 0x8f
|
APDS9960_REG_CONTROL = 0x8F
|
||||||
APDS9960_REG_CONFIG2 = 0x90
|
APDS9960_REG_CONFIG2 = 0x90
|
||||||
APDS9960_REG_ID = 0x92
|
APDS9960_REG_ID = 0x92
|
||||||
APDS9960_REG_STATUS = 0x93
|
APDS9960_REG_STATUS = 0x93
|
||||||
@ -35,40 +35,40 @@ APDS9960_REG_RDATAL = 0x96
|
|||||||
APDS9960_REG_RDATAH = 0x97
|
APDS9960_REG_RDATAH = 0x97
|
||||||
APDS9960_REG_GDATAL = 0x98
|
APDS9960_REG_GDATAL = 0x98
|
||||||
APDS9960_REG_GDATAH = 0x99
|
APDS9960_REG_GDATAH = 0x99
|
||||||
APDS9960_REG_BDATAL = 0x9a
|
APDS9960_REG_BDATAL = 0x9A
|
||||||
APDS9960_REG_BDATAH = 0x9b
|
APDS9960_REG_BDATAH = 0x9B
|
||||||
APDS9960_REG_PDATA = 0x9c
|
APDS9960_REG_PDATA = 0x9C
|
||||||
APDS9960_REG_POFFSET_UR = 0x9d
|
APDS9960_REG_POFFSET_UR = 0x9D
|
||||||
APDS9960_REG_POFFSET_DL = 0x9e
|
APDS9960_REG_POFFSET_DL = 0x9E
|
||||||
APDS9960_REG_CONFIG3 = 0x9f
|
APDS9960_REG_CONFIG3 = 0x9F
|
||||||
APDS9960_REG_GPENTH = 0xa0
|
APDS9960_REG_GPENTH = 0xA0
|
||||||
APDS9960_REG_GEXTH = 0xa1
|
APDS9960_REG_GEXTH = 0xA1
|
||||||
APDS9960_REG_GCONF1 = 0xa2
|
APDS9960_REG_GCONF1 = 0xA2
|
||||||
APDS9960_REG_GCONF2 = 0xa3
|
APDS9960_REG_GCONF2 = 0xA3
|
||||||
APDS9960_REG_GOFFSET_U = 0xa4
|
APDS9960_REG_GOFFSET_U = 0xA4
|
||||||
APDS9960_REG_GOFFSET_D = 0xa5
|
APDS9960_REG_GOFFSET_D = 0xA5
|
||||||
APDS9960_REG_GOFFSET_L = 0xa7
|
APDS9960_REG_GOFFSET_L = 0xA7
|
||||||
APDS9960_REG_GOFFSET_R = 0xa9
|
APDS9960_REG_GOFFSET_R = 0xA9
|
||||||
APDS9960_REG_GPULSE = 0xa6
|
APDS9960_REG_GPULSE = 0xA6
|
||||||
APDS9960_REG_GCONF3 = 0xaA
|
APDS9960_REG_GCONF3 = 0xAA
|
||||||
APDS9960_REG_GCONF4 = 0xaB
|
APDS9960_REG_GCONF4 = 0xAB
|
||||||
APDS9960_REG_GFLVL = 0xae
|
APDS9960_REG_GFLVL = 0xAE
|
||||||
APDS9960_REG_GSTATUS = 0xaf
|
APDS9960_REG_GSTATUS = 0xAF
|
||||||
APDS9960_REG_IFORCE = 0xe4
|
APDS9960_REG_IFORCE = 0xE4
|
||||||
APDS9960_REG_PICLEAR = 0xe5
|
APDS9960_REG_PICLEAR = 0xE5
|
||||||
APDS9960_REG_CICLEAR = 0xe6
|
APDS9960_REG_CICLEAR = 0xE6
|
||||||
APDS9960_REG_AICLEAR = 0xe7
|
APDS9960_REG_AICLEAR = 0xE7
|
||||||
APDS9960_REG_GFIFO_U = 0xfc
|
APDS9960_REG_GFIFO_U = 0xFC
|
||||||
APDS9960_REG_GFIFO_D = 0xfd
|
APDS9960_REG_GFIFO_D = 0xFD
|
||||||
APDS9960_REG_GFIFO_L = 0xfe
|
APDS9960_REG_GFIFO_L = 0xFE
|
||||||
APDS9960_REG_GFIFO_R = 0xff
|
APDS9960_REG_GFIFO_R = 0xFF
|
||||||
|
|
||||||
# APDS9960 bit fields
|
# APDS9960 bit fields
|
||||||
APDS9960_BIT_PON = 0b00000001
|
APDS9960_BIT_PON = 0b00000001
|
||||||
APDS9960_BIT_AEN = 0b00000010
|
APDS9960_BIT_AEN = 0b00000010
|
||||||
APDS9960_BIT_PEN = 0b00000100
|
APDS9960_BIT_PEN = 0b00000100
|
||||||
APDS9960_BIT_WEN = 0b00001000
|
APDS9960_BIT_WEN = 0b00001000
|
||||||
APSD9960_BIT_AIEN =0b00010000
|
APSD9960_BIT_AIEN = 0b00010000
|
||||||
APDS9960_BIT_PIEN = 0b00100000
|
APDS9960_BIT_PIEN = 0b00100000
|
||||||
APDS9960_BIT_GEN = 0b01000000
|
APDS9960_BIT_GEN = 0b01000000
|
||||||
APDS9960_BIT_GVALID = 0b00000001
|
APDS9960_BIT_GVALID = 0b00000001
|
||||||
@ -111,7 +111,7 @@ APDS9960_GGAIN_8X = 3
|
|||||||
APDS9960_LED_BOOST_100 = 0
|
APDS9960_LED_BOOST_100 = 0
|
||||||
APDS9960_LED_BOOST_150 = 1
|
APDS9960_LED_BOOST_150 = 1
|
||||||
APDS9960_LED_BOOST_200 = 2
|
APDS9960_LED_BOOST_200 = 2
|
||||||
APDS9960_LED_BOOST_300 = 3
|
APDS9960_LED_BOOST_300 = 3
|
||||||
|
|
||||||
# Gesture wait time values
|
# Gesture wait time values
|
||||||
APDS9960_GWTIME_0MS = 0
|
APDS9960_GWTIME_0MS = 0
|
||||||
@ -124,33 +124,33 @@ APDS9960_GWTIME_30_8MS = 6
|
|||||||
APDS9960_GWTIME_39_2MS = 7
|
APDS9960_GWTIME_39_2MS = 7
|
||||||
|
|
||||||
# Default values
|
# Default values
|
||||||
APDS9960_DEFAULT_ATIME = 219 # 103ms
|
APDS9960_DEFAULT_ATIME = 219 # 103ms
|
||||||
APDS9960_DEFAULT_WTIME = 246 # 27ms
|
APDS9960_DEFAULT_WTIME = 246 # 27ms
|
||||||
APDS9960_DEFAULT_PROX_PPULSE = 0x87 # 16us, 8 pulses
|
APDS9960_DEFAULT_PROX_PPULSE = 0x87 # 16us, 8 pulses
|
||||||
APDS9960_DEFAULT_GESTURE_PPULSE = 0x89 # 16us, 10 pulses
|
APDS9960_DEFAULT_GESTURE_PPULSE = 0x89 # 16us, 10 pulses
|
||||||
APDS9960_DEFAULT_POFFSET_UR = 0 # 0 offset
|
APDS9960_DEFAULT_POFFSET_UR = 0 # 0 offset
|
||||||
APDS9960_DEFAULT_POFFSET_DL = 0 # 0 offset
|
APDS9960_DEFAULT_POFFSET_DL = 0 # 0 offset
|
||||||
APDS9960_DEFAULT_CONFIG1 = 0x60 # No 12x wait (WTIME) factor
|
APDS9960_DEFAULT_CONFIG1 = 0x60 # No 12x wait (WTIME) factor
|
||||||
APDS9960_DEFAULT_LDRIVE = APDS9960_LED_DRIVE_100MA
|
APDS9960_DEFAULT_LDRIVE = APDS9960_LED_DRIVE_100MA
|
||||||
APDS9960_DEFAULT_PGAIN = APDS9960_PGAIN_4X
|
APDS9960_DEFAULT_PGAIN = APDS9960_PGAIN_4X
|
||||||
APDS9960_DEFAULT_AGAIN = APDS9960_AGAIN_4X
|
APDS9960_DEFAULT_AGAIN = APDS9960_AGAIN_4X
|
||||||
APDS9960_DEFAULT_PILT = 0 # Low proximity threshold
|
APDS9960_DEFAULT_PILT = 0 # Low proximity threshold
|
||||||
APDS9960_DEFAULT_PIHT = 50 # High proximity threshold
|
APDS9960_DEFAULT_PIHT = 50 # High proximity threshold
|
||||||
APDS9960_DEFAULT_AILT = 0xffff # Force interrupt for calibration
|
APDS9960_DEFAULT_AILT = 0xFFFF # Force interrupt for calibration
|
||||||
APDS9960_DEFAULT_AIHT = 0
|
APDS9960_DEFAULT_AIHT = 0
|
||||||
APDS9960_DEFAULT_PERS = 0x11 # 2 consecutive prox or ALS for int.
|
APDS9960_DEFAULT_PERS = 0x11 # 2 consecutive prox or ALS for int.
|
||||||
APDS9960_DEFAULT_CONFIG2 = 0x01 # No saturation interrupts or LED boost
|
APDS9960_DEFAULT_CONFIG2 = 0x01 # No saturation interrupts or LED boost
|
||||||
APDS9960_DEFAULT_CONFIG3 = 0 # Enable all photodiodes, no SAI
|
APDS9960_DEFAULT_CONFIG3 = 0 # Enable all photodiodes, no SAI
|
||||||
APDS9960_DEFAULT_GPENTH = 40 # Threshold for entering gesture mode
|
APDS9960_DEFAULT_GPENTH = 40 # Threshold for entering gesture mode
|
||||||
APDS9960_DEFAULT_GEXTH = 30 # Threshold for exiting gesture mode
|
APDS9960_DEFAULT_GEXTH = 30 # Threshold for exiting gesture mode
|
||||||
APDS9960_DEFAULT_GCONF1 = 0x40 # 4 gesture events for int., 1 for exit
|
APDS9960_DEFAULT_GCONF1 = 0x40 # 4 gesture events for int., 1 for exit
|
||||||
APDS9960_DEFAULT_GGAIN = APDS9960_GGAIN_4X
|
APDS9960_DEFAULT_GGAIN = APDS9960_GGAIN_4X
|
||||||
APDS9960_DEFAULT_GLDRIVE = APDS9960_LED_DRIVE_100MA
|
APDS9960_DEFAULT_GLDRIVE = APDS9960_LED_DRIVE_100MA
|
||||||
APDS9960_DEFAULT_GWTIME = APDS9960_GWTIME_2_8MS
|
APDS9960_DEFAULT_GWTIME = APDS9960_GWTIME_2_8MS
|
||||||
APDS9960_DEFAULT_GOFFSET = 0 # No offset scaling for gesture mode
|
APDS9960_DEFAULT_GOFFSET = 0 # No offset scaling for gesture mode
|
||||||
APDS9960_DEFAULT_GPULSE = 0xc9 # 32us, 10 pulses
|
APDS9960_DEFAULT_GPULSE = 0xC9 # 32us, 10 pulses
|
||||||
APDS9960_DEFAULT_GCONF3 = 0 # All photodiodes active during gesture
|
APDS9960_DEFAULT_GCONF3 = 0 # All photodiodes active during gesture
|
||||||
APDS9960_DEFAULT_GIEN = 0 # Disable gesture interrupts
|
APDS9960_DEFAULT_GIEN = 0 # Disable gesture interrupts
|
||||||
|
|
||||||
# gesture directions
|
# gesture directions
|
||||||
APDS9960_DIR_NONE = 0
|
APDS9960_DIR_NONE = 0
|
||||||
|
|||||||
@ -3,6 +3,7 @@ from apds9960.exceptions import *
|
|||||||
|
|
||||||
from time import sleep_ms
|
from time import sleep_ms
|
||||||
|
|
||||||
|
|
||||||
class APDS9960:
|
class APDS9960:
|
||||||
class GestureData:
|
class GestureData:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -78,7 +79,6 @@ class APDS9960:
|
|||||||
self._write_byte_data(APDS9960_REG_GCONF3, APDS9960_DEFAULT_GCONF3)
|
self._write_byte_data(APDS9960_REG_GCONF3, APDS9960_DEFAULT_GCONF3)
|
||||||
self.setGestureIntEnable(APDS9960_DEFAULT_GIEN)
|
self.setGestureIntEnable(APDS9960_DEFAULT_GIEN)
|
||||||
|
|
||||||
|
|
||||||
def getMode(self):
|
def getMode(self):
|
||||||
return self._read_byte_data(APDS9960_REG_ENABLE)
|
return self._read_byte_data(APDS9960_REG_ENABLE)
|
||||||
|
|
||||||
@ -92,19 +92,18 @@ class APDS9960:
|
|||||||
# change bit(s) in ENABLE register */
|
# change bit(s) in ENABLE register */
|
||||||
if mode == APDS9960_MODE_ALL:
|
if mode == APDS9960_MODE_ALL:
|
||||||
if enable:
|
if enable:
|
||||||
reg_val = 0x7f
|
reg_val = 0x7F
|
||||||
else:
|
else:
|
||||||
reg_val = 0x00
|
reg_val = 0x00
|
||||||
else:
|
else:
|
||||||
if enable:
|
if enable:
|
||||||
reg_val |= (1 << mode);
|
reg_val |= 1 << mode
|
||||||
else:
|
else:
|
||||||
reg_val &= ~(1 << mode);
|
reg_val &= ~(1 << mode)
|
||||||
|
|
||||||
# write value to ENABLE register
|
# write value to ENABLE register
|
||||||
self._write_byte_data(APDS9960_REG_ENABLE, reg_val)
|
self._write_byte_data(APDS9960_REG_ENABLE, reg_val)
|
||||||
|
|
||||||
|
|
||||||
# start the light (R/G/B/Ambient) sensor
|
# start the light (R/G/B/Ambient) sensor
|
||||||
def enableLightSensor(self, interrupts=True):
|
def enableLightSensor(self, interrupts=True):
|
||||||
self.setAmbientLightGain(APDS9960_DEFAULT_AGAIN)
|
self.setAmbientLightGain(APDS9960_DEFAULT_AGAIN)
|
||||||
@ -117,7 +116,6 @@ class APDS9960:
|
|||||||
self.setAmbientLightIntEnable(False)
|
self.setAmbientLightIntEnable(False)
|
||||||
self.setMode(APDS9960_MODE_AMBIENT_LIGHT, False)
|
self.setMode(APDS9960_MODE_AMBIENT_LIGHT, False)
|
||||||
|
|
||||||
|
|
||||||
# start the proximity sensor
|
# start the proximity sensor
|
||||||
def enableProximitySensor(self, interrupts=True):
|
def enableProximitySensor(self, interrupts=True):
|
||||||
self.setProximityGain(APDS9960_DEFAULT_PGAIN)
|
self.setProximityGain(APDS9960_DEFAULT_PGAIN)
|
||||||
@ -131,11 +129,10 @@ class APDS9960:
|
|||||||
self.setProximityIntEnable(False)
|
self.setProximityIntEnable(False)
|
||||||
self.setMode(APDS9960_MODE_PROXIMITY, False)
|
self.setMode(APDS9960_MODE_PROXIMITY, False)
|
||||||
|
|
||||||
|
|
||||||
# start the gesture recognition engine
|
# start the gesture recognition engine
|
||||||
def enableGestureSensor(self, interrupts=True):
|
def enableGestureSensor(self, interrupts=True):
|
||||||
self.resetGestureParameters()
|
self.resetGestureParameters()
|
||||||
self._write_byte_data(APDS9960_REG_WTIME, 0xff)
|
self._write_byte_data(APDS9960_REG_WTIME, 0xFF)
|
||||||
self._write_byte_data(APDS9960_REG_PPULSE, APDS9960_DEFAULT_GESTURE_PPULSE)
|
self._write_byte_data(APDS9960_REG_PPULSE, APDS9960_DEFAULT_GESTURE_PPULSE)
|
||||||
self.setLEDBoost(APDS9960_LED_BOOST_300)
|
self.setLEDBoost(APDS9960_LED_BOOST_300)
|
||||||
self.setGestureIntEnable(interrupts)
|
self.setGestureIntEnable(interrupts)
|
||||||
@ -152,16 +149,14 @@ class APDS9960:
|
|||||||
self.setGestureMode(False)
|
self.setGestureMode(False)
|
||||||
self.setMode(APDS9960_MODE_GESTURE, False)
|
self.setMode(APDS9960_MODE_GESTURE, False)
|
||||||
|
|
||||||
|
|
||||||
# check if there is a gesture available
|
# check if there is a gesture available
|
||||||
def isGestureAvailable(self):
|
def isGestureAvailable(self):
|
||||||
val = self._read_byte_data(APDS9960_REG_GSTATUS)
|
val = self._read_byte_data(APDS9960_REG_GSTATUS)
|
||||||
|
|
||||||
# shift and mask out GVALID bit
|
# shift and mask out GVALID bit
|
||||||
val &= APDS9960_BIT_GVALID;
|
val &= APDS9960_BIT_GVALID
|
||||||
|
|
||||||
return (val == APDS9960_BIT_GVALID)
|
|
||||||
|
|
||||||
|
return val == APDS9960_BIT_GVALID
|
||||||
|
|
||||||
# processes a gesture event and returns best guessed gesture
|
# processes a gesture event and returns best guessed gesture
|
||||||
def readGesture(self):
|
def readGesture(self):
|
||||||
@ -174,7 +169,7 @@ class APDS9960:
|
|||||||
return APDS9960_DIR_NONE
|
return APDS9960_DIR_NONE
|
||||||
|
|
||||||
# keep looping as long as gesture data is valid
|
# keep looping as long as gesture data is valid
|
||||||
while(self.isGestureAvailable()):
|
while self.isGestureAvailable():
|
||||||
# read the current FIFO level
|
# read the current FIFO level
|
||||||
fifo_level = self._read_byte_data(APDS9960_REG_GFLVL)
|
fifo_level = self._read_byte_data(APDS9960_REG_GFLVL)
|
||||||
|
|
||||||
@ -197,7 +192,7 @@ class APDS9960:
|
|||||||
# filter and process gesture data, decode near/far state
|
# filter and process gesture data, decode near/far state
|
||||||
if self.processGestureData():
|
if self.processGestureData():
|
||||||
if self.decodeGesture():
|
if self.decodeGesture():
|
||||||
#***TODO: U-Turn Gestures
|
# ***TODO: U-Turn Gestures
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# reset data
|
# reset data
|
||||||
@ -215,18 +210,14 @@ class APDS9960:
|
|||||||
self.resetGestureParameters()
|
self.resetGestureParameters()
|
||||||
return motion
|
return motion
|
||||||
|
|
||||||
|
|
||||||
# turn the APDS-9960 on
|
# turn the APDS-9960 on
|
||||||
def enablePower(self):
|
def enablePower(self):
|
||||||
self.setMode(APDS9960_MODE_POWER, True)
|
self.setMode(APDS9960_MODE_POWER, True)
|
||||||
|
|
||||||
|
|
||||||
def disablePower(self):
|
def disablePower(self):
|
||||||
# turn the APDS-9960 off
|
# turn the APDS-9960 off
|
||||||
self.setMode(APDS9960_MODE_POWER, False)
|
self.setMode(APDS9960_MODE_POWER, False)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# *******************************************************************************
|
# *******************************************************************************
|
||||||
# ambient light and color sensor controls
|
# ambient light and color sensor controls
|
||||||
# *******************************************************************************
|
# *******************************************************************************
|
||||||
@ -271,7 +262,6 @@ class APDS9960:
|
|||||||
|
|
||||||
return l + (h << 8)
|
return l + (h << 8)
|
||||||
|
|
||||||
|
|
||||||
# *******************************************************************************
|
# *******************************************************************************
|
||||||
# Proximity sensor controls
|
# Proximity sensor controls
|
||||||
# *******************************************************************************
|
# *******************************************************************************
|
||||||
@ -280,7 +270,6 @@ class APDS9960:
|
|||||||
def readProximity(self):
|
def readProximity(self):
|
||||||
return self._read_byte_data(APDS9960_REG_PDATA)
|
return self._read_byte_data(APDS9960_REG_PDATA)
|
||||||
|
|
||||||
|
|
||||||
# *******************************************************************************
|
# *******************************************************************************
|
||||||
# High-level gesture controls
|
# High-level gesture controls
|
||||||
# *******************************************************************************
|
# *******************************************************************************
|
||||||
@ -302,12 +291,11 @@ class APDS9960:
|
|||||||
self.gesture_state_ = 0
|
self.gesture_state_ = 0
|
||||||
self.gesture_motion_ = APDS9960_DIR_NONE
|
self.gesture_motion_ = APDS9960_DIR_NONE
|
||||||
|
|
||||||
|
|
||||||
def processGestureData(self):
|
def processGestureData(self):
|
||||||
"""Processes the raw gesture data to determine swipe direction
|
"""Processes the raw gesture data to determine swipe direction
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if near or far state seen, False otherwise.
|
bool: True if near or far state seen, False otherwise.
|
||||||
"""
|
"""
|
||||||
u_first = 0
|
u_first = 0
|
||||||
d_first = 0
|
d_first = 0
|
||||||
@ -326,11 +314,12 @@ class APDS9960:
|
|||||||
if self.gesture_data_.total_gestures <= 32 and self.gesture_data_.total_gestures > 0:
|
if self.gesture_data_.total_gestures <= 32 and self.gesture_data_.total_gestures > 0:
|
||||||
# find the first value in U/D/L/R above the threshold
|
# find the first value in U/D/L/R above the threshold
|
||||||
for i in range(0, self.gesture_data_.total_gestures):
|
for i in range(0, self.gesture_data_.total_gestures):
|
||||||
if self.gesture_data_.u_data[i] > APDS9960_GESTURE_THRESHOLD_OUT and \
|
if (
|
||||||
self.gesture_data_.d_data[i] > APDS9960_GESTURE_THRESHOLD_OUT and \
|
self.gesture_data_.u_data[i] > APDS9960_GESTURE_THRESHOLD_OUT
|
||||||
self.gesture_data_.l_data[i] > APDS9960_GESTURE_THRESHOLD_OUT and \
|
and self.gesture_data_.d_data[i] > APDS9960_GESTURE_THRESHOLD_OUT
|
||||||
self.gesture_data_.r_data[i] > APDS9960_GESTURE_THRESHOLD_OUT:
|
and self.gesture_data_.l_data[i] > APDS9960_GESTURE_THRESHOLD_OUT
|
||||||
|
and self.gesture_data_.r_data[i] > APDS9960_GESTURE_THRESHOLD_OUT
|
||||||
|
):
|
||||||
u_first = self.gesture_data_.u_data[i]
|
u_first = self.gesture_data_.u_data[i]
|
||||||
d_first = self.gesture_data_.d_data[i]
|
d_first = self.gesture_data_.d_data[i]
|
||||||
l_first = self.gesture_data_.l_data[i]
|
l_first = self.gesture_data_.l_data[i]
|
||||||
@ -338,16 +327,17 @@ class APDS9960:
|
|||||||
break
|
break
|
||||||
|
|
||||||
# if one of the _first values is 0, then there is no good data
|
# if one of the _first values is 0, then there is no good data
|
||||||
if u_first == 0 or d_first == 0 or l_first == 0 or r_first == 0:
|
if u_first == 0 or d_first == 0 or l_first == 0 or r_first == 0:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# find the last value in U/D/L/R above the threshold
|
# find the last value in U/D/L/R above the threshold
|
||||||
for i in reversed(range(0, self.gesture_data_.total_gestures)):
|
for i in reversed(range(0, self.gesture_data_.total_gestures)):
|
||||||
if self.gesture_data_.u_data[i] > APDS9960_GESTURE_THRESHOLD_OUT and \
|
if (
|
||||||
self.gesture_data_.d_data[i] > APDS9960_GESTURE_THRESHOLD_OUT and \
|
self.gesture_data_.u_data[i] > APDS9960_GESTURE_THRESHOLD_OUT
|
||||||
self.gesture_data_.l_data[i] > APDS9960_GESTURE_THRESHOLD_OUT and \
|
and self.gesture_data_.d_data[i] > APDS9960_GESTURE_THRESHOLD_OUT
|
||||||
self.gesture_data_.r_data[i] > APDS9960_GESTURE_THRESHOLD_OUT:
|
and self.gesture_data_.l_data[i] > APDS9960_GESTURE_THRESHOLD_OUT
|
||||||
|
and self.gesture_data_.r_data[i] > APDS9960_GESTURE_THRESHOLD_OUT
|
||||||
|
):
|
||||||
u_last = self.gesture_data_.u_data[i]
|
u_last = self.gesture_data_.u_data[i]
|
||||||
d_last = self.gesture_data_.d_data[i]
|
d_last = self.gesture_data_.d_data[i]
|
||||||
l_last = self.gesture_data_.l_data[i]
|
l_last = self.gesture_data_.l_data[i]
|
||||||
@ -386,9 +376,10 @@ class APDS9960:
|
|||||||
|
|
||||||
# determine Near/Far gesture
|
# determine Near/Far gesture
|
||||||
if self.gesture_ud_count_ == 0 and self.gesture_lr_count_ == 0:
|
if self.gesture_ud_count_ == 0 and self.gesture_lr_count_ == 0:
|
||||||
if abs(ud_delta) < APDS9960_GESTURE_SENSITIVITY_2 and \
|
if (
|
||||||
abs(lr_delta) < APDS9960_GESTURE_SENSITIVITY_2:
|
abs(ud_delta) < APDS9960_GESTURE_SENSITIVITY_2
|
||||||
|
and abs(lr_delta) < APDS9960_GESTURE_SENSITIVITY_2
|
||||||
|
):
|
||||||
if ud_delta == 0 and lr_delta == 0:
|
if ud_delta == 0 and lr_delta == 0:
|
||||||
self.gesture_near_count_ += 1
|
self.gesture_near_count_ += 1
|
||||||
elif ud_delta != 0 or lr_delta != 0:
|
elif ud_delta != 0 or lr_delta != 0:
|
||||||
@ -401,23 +392,23 @@ class APDS9960:
|
|||||||
self.gesture_state_ = APDS9960_STATE_FAR
|
self.gesture_state_ = APDS9960_STATE_FAR
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
if abs(ud_delta) < APDS9960_GESTURE_SENSITIVITY_2 and \
|
if (
|
||||||
abs(lr_delta) < APDS9960_GESTURE_SENSITIVITY_2:
|
abs(ud_delta) < APDS9960_GESTURE_SENSITIVITY_2
|
||||||
|
and abs(lr_delta) < APDS9960_GESTURE_SENSITIVITY_2
|
||||||
|
):
|
||||||
|
if ud_delta == 0 and lr_delta == 0:
|
||||||
|
self.gesture_near_count_ += 1
|
||||||
|
|
||||||
if ud_delta == 0 and lr_delta == 0:
|
if self.gesture_near_count_ >= 10:
|
||||||
self.gesture_near_count_ += 1
|
self.gesture_ud_count_ = 0
|
||||||
|
self.gesture_lr_count_ = 0
|
||||||
if self.gesture_near_count_ >= 10:
|
self.gesture_ud_delta_ = 0
|
||||||
self.gesture_ud_count_ = 0
|
self.gesture_lr_delta_ = 0
|
||||||
self.gesture_lr_count_ = 0
|
|
||||||
self.gesture_ud_delta_ = 0
|
|
||||||
self.gesture_lr_delta_ = 0
|
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def decodeGesture(self):
|
def decodeGesture(self):
|
||||||
"""Determines swipe direction or near/far state.
|
"""Determines swipe direction or near/far state."""
|
||||||
"""
|
|
||||||
|
|
||||||
# return if near or far event is detected
|
# return if near or far event is detected
|
||||||
if self.gesture_state_ == APDS9960_STATE_NEAR:
|
if self.gesture_state_ == APDS9960_STATE_NEAR:
|
||||||
@ -462,44 +453,37 @@ class APDS9960:
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
# *******************************************************************************
|
# *******************************************************************************
|
||||||
# Getters and setters for register values
|
# Getters and setters for register values
|
||||||
# *******************************************************************************
|
# *******************************************************************************
|
||||||
|
|
||||||
def getProxIntLowThresh(self):
|
def getProxIntLowThresh(self):
|
||||||
"""Returns the lower threshold for proximity detection
|
"""Returns the lower threshold for proximity detection"""
|
||||||
"""
|
|
||||||
return self._read_byte_data(APDS9960_REG_PILT)
|
return self._read_byte_data(APDS9960_REG_PILT)
|
||||||
|
|
||||||
def setProxIntLowThresh(self, threshold):
|
def setProxIntLowThresh(self, threshold):
|
||||||
"""Sets the lower threshold for proximity detection.
|
"""Sets the lower threshold for proximity detection."""
|
||||||
"""
|
|
||||||
self._write_byte_data(APDS9960_REG_PILT, threshold)
|
self._write_byte_data(APDS9960_REG_PILT, threshold)
|
||||||
|
|
||||||
|
|
||||||
def getProxIntHighThresh(self):
|
def getProxIntHighThresh(self):
|
||||||
"""Returns the high threshold for proximity detection.
|
"""Returns the high threshold for proximity detection."""
|
||||||
"""
|
|
||||||
return self._read_byte_data(APDS9960_REG_PIHT)
|
return self._read_byte_data(APDS9960_REG_PIHT)
|
||||||
|
|
||||||
def setProxIntHighThresh(self, threshold):
|
def setProxIntHighThresh(self, threshold):
|
||||||
"""Sets the high threshold for proximity detection.
|
"""Sets the high threshold for proximity detection."""
|
||||||
"""
|
|
||||||
self._write_byte_data(APDS9960_REG_PIHT, threshold)
|
self._write_byte_data(APDS9960_REG_PIHT, threshold)
|
||||||
|
|
||||||
|
|
||||||
def getLEDDrive(self):
|
def getLEDDrive(self):
|
||||||
"""Returns LED drive strength for proximity and ALS.
|
"""Returns LED drive strength for proximity and ALS.
|
||||||
|
|
||||||
Value LED Current
|
Value LED Current
|
||||||
0 100 mA
|
0 100 mA
|
||||||
1 50 mA
|
1 50 mA
|
||||||
2 25 mA
|
2 25 mA
|
||||||
3 12.5 mA
|
3 12.5 mA
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
int: the value of the LED drive strength
|
int: the value of the LED drive strength
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_CONTROL)
|
val = self._read_byte_data(APDS9960_REG_CONTROL)
|
||||||
|
|
||||||
@ -509,14 +493,14 @@ class APDS9960:
|
|||||||
def setLEDDrive(self, drive):
|
def setLEDDrive(self, drive):
|
||||||
"""Sets LED drive strength for proximity and ALS.
|
"""Sets LED drive strength for proximity and ALS.
|
||||||
|
|
||||||
Value LED Current
|
Value LED Current
|
||||||
0 100 mA
|
0 100 mA
|
||||||
1 50 mA
|
1 50 mA
|
||||||
2 25 mA
|
2 25 mA
|
||||||
3 12.5 mA
|
3 12.5 mA
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
drive (int): value for the LED drive strength
|
drive (int): value for the LED drive strength
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_CONTROL)
|
val = self._read_byte_data(APDS9960_REG_CONTROL)
|
||||||
|
|
||||||
@ -528,18 +512,17 @@ class APDS9960:
|
|||||||
|
|
||||||
self._write_byte_data(APDS9960_REG_CONTROL, val)
|
self._write_byte_data(APDS9960_REG_CONTROL, val)
|
||||||
|
|
||||||
|
|
||||||
def getProximityGain(self):
|
def getProximityGain(self):
|
||||||
"""Returns receiver gain for proximity detection.
|
"""Returns receiver gain for proximity detection.
|
||||||
|
|
||||||
Value Gain
|
Value Gain
|
||||||
0 1x
|
0 1x
|
||||||
1 2x
|
1 2x
|
||||||
2 4x
|
2 4x
|
||||||
3 8x
|
3 8x
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
int: the value of the proximity gain
|
int: the value of the proximity gain
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_CONTROL)
|
val = self._read_byte_data(APDS9960_REG_CONTROL)
|
||||||
|
|
||||||
@ -549,14 +532,14 @@ class APDS9960:
|
|||||||
def setProximityGain(self, drive):
|
def setProximityGain(self, drive):
|
||||||
"""Returns receiver gain for proximity detection.
|
"""Returns receiver gain for proximity detection.
|
||||||
|
|
||||||
Value Gain
|
Value Gain
|
||||||
0 1x
|
0 1x
|
||||||
1 2x
|
1 2x
|
||||||
2 4x
|
2 4x
|
||||||
3 8x
|
3 8x
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
drive (int): value for the proximity gain
|
drive (int): value for the proximity gain
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_CONTROL)
|
val = self._read_byte_data(APDS9960_REG_CONTROL)
|
||||||
|
|
||||||
@ -568,35 +551,34 @@ class APDS9960:
|
|||||||
|
|
||||||
self._write_byte_data(APDS9960_REG_CONTROL, val)
|
self._write_byte_data(APDS9960_REG_CONTROL, val)
|
||||||
|
|
||||||
|
|
||||||
def getAmbientLightGain(self):
|
def getAmbientLightGain(self):
|
||||||
"""Returns receiver gain for the ambient light sensor (ALS).
|
"""Returns receiver gain for the ambient light sensor (ALS).
|
||||||
|
|
||||||
Value Gain
|
Value Gain
|
||||||
0 1x
|
0 1x
|
||||||
1 4x
|
1 4x
|
||||||
2 16x
|
2 16x
|
||||||
3 64x
|
3 64x
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
int: the value of the ALS gain
|
int: the value of the ALS gain
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_CONTROL)
|
val = self._read_byte_data(APDS9960_REG_CONTROL)
|
||||||
|
|
||||||
# shift and mask out ADRIVE bits
|
# shift and mask out ADRIVE bits
|
||||||
return (val & 0b00000011)
|
return val & 0b00000011
|
||||||
|
|
||||||
def setAmbientLightGain(self, drive):
|
def setAmbientLightGain(self, drive):
|
||||||
"""Sets the receiver gain for the ambient light sensor (ALS).
|
"""Sets the receiver gain for the ambient light sensor (ALS).
|
||||||
|
|
||||||
Value Gain
|
Value Gain
|
||||||
0 1x
|
0 1x
|
||||||
1 4x
|
1 4x
|
||||||
2 16x
|
2 16x
|
||||||
3 64x
|
3 64x
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
drive (int): value for the ALS gain
|
drive (int): value for the ALS gain
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_CONTROL)
|
val = self._read_byte_data(APDS9960_REG_CONTROL)
|
||||||
|
|
||||||
@ -607,18 +589,17 @@ class APDS9960:
|
|||||||
|
|
||||||
self._write_byte_data(APDS9960_REG_CONTROL, val)
|
self._write_byte_data(APDS9960_REG_CONTROL, val)
|
||||||
|
|
||||||
|
|
||||||
def getLEDBoost(self):
|
def getLEDBoost(self):
|
||||||
"""Get the current LED boost value.
|
"""Get the current LED boost value.
|
||||||
|
|
||||||
Value Gain
|
Value Gain
|
||||||
0 100%
|
0 100%
|
||||||
1 150%
|
1 150%
|
||||||
2 200%
|
2 200%
|
||||||
3 300%
|
3 300%
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
int: the LED boost value
|
int: the LED boost value
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_CONFIG2)
|
val = self._read_byte_data(APDS9960_REG_CONFIG2)
|
||||||
|
|
||||||
@ -628,14 +609,14 @@ class APDS9960:
|
|||||||
def setLEDBoost(self, boost):
|
def setLEDBoost(self, boost):
|
||||||
"""Sets the LED current boost value.
|
"""Sets the LED current boost value.
|
||||||
|
|
||||||
Value Gain
|
Value Gain
|
||||||
0 100%
|
0 100%
|
||||||
1 150%
|
1 150%
|
||||||
2 200%
|
2 200%
|
||||||
3 300%
|
3 300%
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
boost (int): value for the LED boost
|
boost (int): value for the LED boost
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_CONFIG2)
|
val = self._read_byte_data(APDS9960_REG_CONFIG2)
|
||||||
|
|
||||||
@ -647,12 +628,11 @@ class APDS9960:
|
|||||||
|
|
||||||
self._write_byte_data(APDS9960_REG_CONFIG2, val)
|
self._write_byte_data(APDS9960_REG_CONFIG2, val)
|
||||||
|
|
||||||
|
|
||||||
def getProxGainCompEnable(self):
|
def getProxGainCompEnable(self):
|
||||||
"""Gets proximity gain compensation enable.
|
"""Gets proximity gain compensation enable.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if compensation is enabled, False if not
|
bool: True if compensation is enabled, False if not
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_CONFIG3)
|
val = self._read_byte_data(APDS9960_REG_CONFIG3)
|
||||||
|
|
||||||
@ -663,8 +643,8 @@ class APDS9960:
|
|||||||
def setProxGainCompEnable(self, enable):
|
def setProxGainCompEnable(self, enable):
|
||||||
"""Sets the proximity gain compensation enable.
|
"""Sets the proximity gain compensation enable.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
enable (bool): True to enable compensation, False to disable
|
enable (bool): True to enable compensation, False to disable
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_CONFIG3)
|
val = self._read_byte_data(APDS9960_REG_CONFIG3)
|
||||||
|
|
||||||
@ -675,20 +655,19 @@ class APDS9960:
|
|||||||
|
|
||||||
self._write_byte_data(APDS9960_REG_CONFIG3, val)
|
self._write_byte_data(APDS9960_REG_CONFIG3, val)
|
||||||
|
|
||||||
|
|
||||||
def getProxPhotoMask(self):
|
def getProxPhotoMask(self):
|
||||||
"""Gets the current mask for enabled/disabled proximity photodiodes.
|
"""Gets the current mask for enabled/disabled proximity photodiodes.
|
||||||
|
|
||||||
Bit Photodiode
|
Bit Photodiode
|
||||||
3 UP
|
3 UP
|
||||||
2 DOWN
|
2 DOWN
|
||||||
1 LEFT
|
1 LEFT
|
||||||
0 RIGHT
|
0 RIGHT
|
||||||
|
|
||||||
1 = disabled, 0 = enabled
|
1 = disabled, 0 = enabled
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
int: Current proximity mask for photodiodes.
|
int: Current proximity mask for photodiodes.
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_CONFIG3)
|
val = self._read_byte_data(APDS9960_REG_CONFIG3)
|
||||||
|
|
||||||
@ -698,16 +677,16 @@ class APDS9960:
|
|||||||
def setProxPhotoMask(self, mask):
|
def setProxPhotoMask(self, mask):
|
||||||
"""Sets the mask for enabling/disabling proximity photodiodes.
|
"""Sets the mask for enabling/disabling proximity photodiodes.
|
||||||
|
|
||||||
Bit Photodiode
|
Bit Photodiode
|
||||||
3 UP
|
3 UP
|
||||||
2 DOWN
|
2 DOWN
|
||||||
1 LEFT
|
1 LEFT
|
||||||
0 RIGHT
|
0 RIGHT
|
||||||
|
|
||||||
1 = disabled, 0 = enabled
|
1 = disabled, 0 = enabled
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
mask (int): 4-bit mask value
|
mask (int): 4-bit mask value
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_CONFIG3)
|
val = self._read_byte_data(APDS9960_REG_CONFIG3)
|
||||||
|
|
||||||
@ -718,52 +697,49 @@ class APDS9960:
|
|||||||
|
|
||||||
self._write_byte_data(APDS9960_REG_CONFIG3, val)
|
self._write_byte_data(APDS9960_REG_CONFIG3, val)
|
||||||
|
|
||||||
|
|
||||||
def getGestureEnterThresh(self):
|
def getGestureEnterThresh(self):
|
||||||
"""Gets the entry proximity threshold for gesture sensing.
|
"""Gets the entry proximity threshold for gesture sensing.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
int: current entry proximity threshold
|
int: current entry proximity threshold
|
||||||
"""
|
"""
|
||||||
return self._read_byte_data(APDS9960_REG_GPENTH)
|
return self._read_byte_data(APDS9960_REG_GPENTH)
|
||||||
|
|
||||||
def setGestureEnterThresh(self, threshold):
|
def setGestureEnterThresh(self, threshold):
|
||||||
"""Sets the entry proximity threshold for gesture sensing.
|
"""Sets the entry proximity threshold for gesture sensing.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
threshold (int): threshold proximity value needed to start gesture mode
|
threshold (int): threshold proximity value needed to start gesture mode
|
||||||
"""
|
"""
|
||||||
self._write_byte_data(APDS9960_REG_GPENTH, threshold)
|
self._write_byte_data(APDS9960_REG_GPENTH, threshold)
|
||||||
|
|
||||||
|
|
||||||
def getGestureExitThresh(self):
|
def getGestureExitThresh(self):
|
||||||
"""Gets the exit proximity threshold for gesture sensing.
|
"""Gets the exit proximity threshold for gesture sensing.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
int: current exit proximity threshold
|
int: current exit proximity threshold
|
||||||
"""
|
"""
|
||||||
return self._read_byte_data(APDS9960_REG_GEXTH)
|
return self._read_byte_data(APDS9960_REG_GEXTH)
|
||||||
|
|
||||||
def setGestureExitThresh(self, threshold):
|
def setGestureExitThresh(self, threshold):
|
||||||
"""Sets the exit proximity threshold for gesture sensing.
|
"""Sets the exit proximity threshold for gesture sensing.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
threshold (int): threshold proximity value needed to end gesture mode
|
threshold (int): threshold proximity value needed to end gesture mode
|
||||||
"""
|
"""
|
||||||
self._write_byte_data(APDS9960_REG_GEXTH, threshold)
|
self._write_byte_data(APDS9960_REG_GEXTH, threshold)
|
||||||
|
|
||||||
|
|
||||||
def getGestureGain(self):
|
def getGestureGain(self):
|
||||||
"""Gets the gain of the photodiode during gesture mode.
|
"""Gets the gain of the photodiode during gesture mode.
|
||||||
|
|
||||||
Value Gain
|
Value Gain
|
||||||
0 1x
|
0 1x
|
||||||
1 2x
|
1 2x
|
||||||
2 4x
|
2 4x
|
||||||
3 8x
|
3 8x
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
int: the current photodiode gain
|
int: the current photodiode gain
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_GCONF2)
|
val = self._read_byte_data(APDS9960_REG_GCONF2)
|
||||||
|
|
||||||
@ -773,14 +749,14 @@ class APDS9960:
|
|||||||
def setGestureGain(self, gain):
|
def setGestureGain(self, gain):
|
||||||
"""Sets the gain of the photodiode during gesture mode.
|
"""Sets the gain of the photodiode during gesture mode.
|
||||||
|
|
||||||
Value Gain
|
Value Gain
|
||||||
0 1x
|
0 1x
|
||||||
1 2x
|
1 2x
|
||||||
2 4x
|
2 4x
|
||||||
3 8x
|
3 8x
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
gain (int): the value for the photodiode gain
|
gain (int): the value for the photodiode gain
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_GCONF2)
|
val = self._read_byte_data(APDS9960_REG_GCONF2)
|
||||||
|
|
||||||
@ -792,18 +768,17 @@ class APDS9960:
|
|||||||
|
|
||||||
self._write_byte_data(APDS9960_REG_GCONF2, val)
|
self._write_byte_data(APDS9960_REG_GCONF2, val)
|
||||||
|
|
||||||
|
|
||||||
def getGestureLEDDrive(self):
|
def getGestureLEDDrive(self):
|
||||||
"""Gets the drive current of the LED during gesture mode.
|
"""Gets the drive current of the LED during gesture mode.
|
||||||
|
|
||||||
Value LED Current
|
Value LED Current
|
||||||
0 100 mA
|
0 100 mA
|
||||||
1 50 mA
|
1 50 mA
|
||||||
2 25 mA
|
2 25 mA
|
||||||
3 12.5 mA
|
3 12.5 mA
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
int: the LED drive current value
|
int: the LED drive current value
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_GCONF2)
|
val = self._read_byte_data(APDS9960_REG_GCONF2)
|
||||||
|
|
||||||
@ -813,41 +788,40 @@ class APDS9960:
|
|||||||
def setGestureLEDDrive(self, drive):
|
def setGestureLEDDrive(self, drive):
|
||||||
"""Sets LED drive strength for proximity and ALS.
|
"""Sets LED drive strength for proximity and ALS.
|
||||||
|
|
||||||
Value LED Current
|
Value LED Current
|
||||||
0 100 mA
|
0 100 mA
|
||||||
1 50 mA
|
1 50 mA
|
||||||
2 25 mA
|
2 25 mA
|
||||||
3 12.5 mA
|
3 12.5 mA
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
drive (int): value for the LED drive current
|
drive (int): value for the LED drive current
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_GCONF2)
|
val = self._read_byte_data(APDS9960_REG_GCONF2)
|
||||||
|
|
||||||
# set bits in register to given value
|
# set bits in register to given value
|
||||||
drive &= 0b00000011;
|
drive &= 0b00000011
|
||||||
drive = drive << 3;
|
drive = drive << 3
|
||||||
val &= 0b11100111;
|
val &= 0b11100111
|
||||||
val |= drive;
|
val |= drive
|
||||||
|
|
||||||
self._write_byte_data(APDS9960_REG_GCONF2, val)
|
self._write_byte_data(APDS9960_REG_GCONF2, val)
|
||||||
|
|
||||||
|
|
||||||
def getGestureWaitTime(self):
|
def getGestureWaitTime(self):
|
||||||
"""Gets the time in low power mode between gesture detections.
|
"""Gets the time in low power mode between gesture detections.
|
||||||
|
|
||||||
Value Wait time
|
Value Wait time
|
||||||
0 0 ms
|
0 0 ms
|
||||||
1 2.8 ms
|
1 2.8 ms
|
||||||
2 5.6 ms
|
2 5.6 ms
|
||||||
3 8.4 ms
|
3 8.4 ms
|
||||||
4 14.0 ms
|
4 14.0 ms
|
||||||
5 22.4 ms
|
5 22.4 ms
|
||||||
6 30.8 ms
|
6 30.8 ms
|
||||||
7 39.2 ms
|
7 39.2 ms
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
int: the current wait time between gestures
|
int: the current wait time between gestures
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_GCONF2)
|
val = self._read_byte_data(APDS9960_REG_GCONF2)
|
||||||
|
|
||||||
@ -857,18 +831,18 @@ class APDS9960:
|
|||||||
def setGestureWaitTime(self, time):
|
def setGestureWaitTime(self, time):
|
||||||
"""Sets the time in low power mode between gesture detections.
|
"""Sets the time in low power mode between gesture detections.
|
||||||
|
|
||||||
Value Wait time
|
Value Wait time
|
||||||
0 0 ms
|
0 0 ms
|
||||||
1 2.8 ms
|
1 2.8 ms
|
||||||
2 5.6 ms
|
2 5.6 ms
|
||||||
3 8.4 ms
|
3 8.4 ms
|
||||||
4 14.0 ms
|
4 14.0 ms
|
||||||
5 22.4 ms
|
5 22.4 ms
|
||||||
6 30.8 ms
|
6 30.8 ms
|
||||||
7 39.2 ms
|
7 39.2 ms
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
time (int): value for the wait time
|
time (int): value for the wait time
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_GCONF2)
|
val = self._read_byte_data(APDS9960_REG_GCONF2)
|
||||||
|
|
||||||
@ -879,84 +853,83 @@ class APDS9960:
|
|||||||
|
|
||||||
self._write_byte_data(APDS9960_REG_GCONF2, val)
|
self._write_byte_data(APDS9960_REG_GCONF2, val)
|
||||||
|
|
||||||
|
|
||||||
def getLightIntLowThreshold(self):
|
def getLightIntLowThreshold(self):
|
||||||
"""Gets the low threshold for ambient light interrupts.
|
"""Gets the low threshold for ambient light interrupts.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
int: threshold current low threshold stored on the APDS9960
|
int: threshold current low threshold stored on the APDS9960
|
||||||
"""
|
"""
|
||||||
return self._read_byte_data(APDS9960_REG_AILTL) | (self._read_byte_data(APDS9960_REG_AILTH) << 8)
|
return self._read_byte_data(APDS9960_REG_AILTL) | (
|
||||||
|
self._read_byte_data(APDS9960_REG_AILTH) << 8
|
||||||
|
)
|
||||||
|
|
||||||
def setLightIntLowThreshold(self, threshold):
|
def setLightIntLowThreshold(self, threshold):
|
||||||
"""Sets the low threshold for ambient light interrupts.
|
"""Sets the low threshold for ambient light interrupts.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
threshold (int): low threshold value for interrupt to trigger
|
threshold (int): low threshold value for interrupt to trigger
|
||||||
"""
|
"""
|
||||||
# break 16-bit threshold into 2 8-bit values
|
# break 16-bit threshold into 2 8-bit values
|
||||||
self._write_byte_data(APDS9960_REG_AILTL, threshold & 0x00ff)
|
self._write_byte_data(APDS9960_REG_AILTL, threshold & 0x00FF)
|
||||||
self._write_byte_data(APDS9960_REG_AILTH, (threshold & 0xff00) >> 8)
|
self._write_byte_data(APDS9960_REG_AILTH, (threshold & 0xFF00) >> 8)
|
||||||
|
|
||||||
|
|
||||||
def getLightIntHighThreshold(self):
|
def getLightIntHighThreshold(self):
|
||||||
"""Gets the high threshold for ambient light interrupts.
|
"""Gets the high threshold for ambient light interrupts.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
int: threshold current low threshold stored on the APDS9960
|
int: threshold current low threshold stored on the APDS9960
|
||||||
"""
|
"""
|
||||||
return self._read_byte_data(APDS9960_REG_AIHTL) | (self._read_byte_data(APDS9960_REG_AIHTH) << 8)
|
return self._read_byte_data(APDS9960_REG_AIHTL) | (
|
||||||
|
self._read_byte_data(APDS9960_REG_AIHTH) << 8
|
||||||
|
)
|
||||||
|
|
||||||
def setLightIntHighThreshold(self, threshold):
|
def setLightIntHighThreshold(self, threshold):
|
||||||
"""Sets the high threshold for ambient light interrupts.
|
"""Sets the high threshold for ambient light interrupts.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
threshold (int): high threshold value for interrupt to trigger
|
threshold (int): high threshold value for interrupt to trigger
|
||||||
"""
|
"""
|
||||||
# break 16-bit threshold into 2 8-bit values
|
# break 16-bit threshold into 2 8-bit values
|
||||||
self._write_byte_data(APDS9960_REG_AIHTL, threshold & 0x00ff)
|
self._write_byte_data(APDS9960_REG_AIHTL, threshold & 0x00FF)
|
||||||
self._write_byte_data(APDS9960_REG_AIHTH, (threshold & 0xff00) >> 8)
|
self._write_byte_data(APDS9960_REG_AIHTH, (threshold & 0xFF00) >> 8)
|
||||||
|
|
||||||
|
|
||||||
def getProximityIntLowThreshold(self):
|
def getProximityIntLowThreshold(self):
|
||||||
"""Gets the low threshold for proximity interrupts.
|
"""Gets the low threshold for proximity interrupts.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
int: threshold current low threshold stored on the APDS9960
|
int: threshold current low threshold stored on the APDS9960
|
||||||
"""
|
"""
|
||||||
return self._read_byte_data(APDS9960_REG_PILT)
|
return self._read_byte_data(APDS9960_REG_PILT)
|
||||||
|
|
||||||
def setProximityIntLowThreshold(self, threshold):
|
def setProximityIntLowThreshold(self, threshold):
|
||||||
"""Sets the low threshold for proximity interrupts.
|
"""Sets the low threshold for proximity interrupts.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
threshold (int): low threshold value for interrupt to trigger
|
threshold (int): low threshold value for interrupt to trigger
|
||||||
"""
|
"""
|
||||||
self._write_byte_data(APDS9960_REG_PILT, threshold)
|
self._write_byte_data(APDS9960_REG_PILT, threshold)
|
||||||
|
|
||||||
|
|
||||||
def getProximityIntHighThreshold(self):
|
def getProximityIntHighThreshold(self):
|
||||||
"""Gets the high threshold for proximity interrupts.
|
"""Gets the high threshold for proximity interrupts.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
int: threshold current high threshold stored on the APDS9960
|
int: threshold current high threshold stored on the APDS9960
|
||||||
"""
|
"""
|
||||||
return self._read_byte_data(APDS9960_REG_PIHT)
|
return self._read_byte_data(APDS9960_REG_PIHT)
|
||||||
|
|
||||||
def setProximityIntHighThreshold(self, threshold):
|
def setProximityIntHighThreshold(self, threshold):
|
||||||
"""Sets the high threshold for proximity interrupts.
|
"""Sets the high threshold for proximity interrupts.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
threshold (int): high threshold value for interrupt to trigger
|
threshold (int): high threshold value for interrupt to trigger
|
||||||
"""
|
"""
|
||||||
self._write_byte_data(APDS9960_REG_PIHT, threshold)
|
self._write_byte_data(APDS9960_REG_PIHT, threshold)
|
||||||
|
|
||||||
|
|
||||||
def getAmbientLightIntEnable(self):
|
def getAmbientLightIntEnable(self):
|
||||||
"""Gets if ambient light interrupts are enabled or not.
|
"""Gets if ambient light interrupts are enabled or not.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if interrupts are enabled, False if not
|
bool: True if interrupts are enabled, False if not
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_ENABLE)
|
val = self._read_byte_data(APDS9960_REG_ENABLE)
|
||||||
return (val >> 4) & 0b00000001 == 1
|
return (val >> 4) & 0b00000001 == 1
|
||||||
@ -964,24 +937,23 @@ class APDS9960:
|
|||||||
def setAmbientLightIntEnable(self, enable):
|
def setAmbientLightIntEnable(self, enable):
|
||||||
"""Turns ambient light interrupts on or off.
|
"""Turns ambient light interrupts on or off.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
enable (bool): True to enable interrupts, False to turn them off
|
enable (bool): True to enable interrupts, False to turn them off
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_ENABLE)
|
val = self._read_byte_data(APDS9960_REG_ENABLE)
|
||||||
|
|
||||||
# set bits in register to given value
|
# set bits in register to given value
|
||||||
val &= 0b11101111;
|
val &= 0b11101111
|
||||||
if enable:
|
if enable:
|
||||||
val |= 0b00010000
|
val |= 0b00010000
|
||||||
|
|
||||||
self._write_byte_data(APDS9960_REG_ENABLE, val)
|
self._write_byte_data(APDS9960_REG_ENABLE, val)
|
||||||
|
|
||||||
|
|
||||||
def getProximityIntEnable(self):
|
def getProximityIntEnable(self):
|
||||||
"""Gets if proximity interrupts are enabled or not.
|
"""Gets if proximity interrupts are enabled or not.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if interrupts are enabled, False if not
|
bool: True if interrupts are enabled, False if not
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_ENABLE)
|
val = self._read_byte_data(APDS9960_REG_ENABLE)
|
||||||
return (val >> 5) & 0b00000001 == 1
|
return (val >> 5) & 0b00000001 == 1
|
||||||
@ -989,24 +961,23 @@ class APDS9960:
|
|||||||
def setProximityIntEnable(self, enable):
|
def setProximityIntEnable(self, enable):
|
||||||
"""Turns proximity interrupts on or off.
|
"""Turns proximity interrupts on or off.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
enable (bool): True to enable interrupts, False to turn them off
|
enable (bool): True to enable interrupts, False to turn them off
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_ENABLE)
|
val = self._read_byte_data(APDS9960_REG_ENABLE)
|
||||||
|
|
||||||
# set bits in register to given value
|
# set bits in register to given value
|
||||||
val &= 0b11011111;
|
val &= 0b11011111
|
||||||
if enable:
|
if enable:
|
||||||
val |= 0b00100000
|
val |= 0b00100000
|
||||||
|
|
||||||
self._write_byte_data(APDS9960_REG_ENABLE, val)
|
self._write_byte_data(APDS9960_REG_ENABLE, val)
|
||||||
|
|
||||||
|
|
||||||
def getGestureIntEnable(self):
|
def getGestureIntEnable(self):
|
||||||
"""Gets if gesture interrupts are enabled or not.
|
"""Gets if gesture interrupts are enabled or not.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if interrupts are enabled, False if not
|
bool: True if interrupts are enabled, False if not
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_GCONF4)
|
val = self._read_byte_data(APDS9960_REG_GCONF4)
|
||||||
return (val >> 1) & 0b00000001 == 1
|
return (val >> 1) & 0b00000001 == 1
|
||||||
@ -1014,8 +985,8 @@ class APDS9960:
|
|||||||
def setGestureIntEnable(self, enable):
|
def setGestureIntEnable(self, enable):
|
||||||
"""Turns gesture-related interrupts on or off.
|
"""Turns gesture-related interrupts on or off.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
enable (bool): True to enable interrupts, False to turn them off
|
enable (bool): True to enable interrupts, False to turn them off
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_GCONF4)
|
val = self._read_byte_data(APDS9960_REG_GCONF4)
|
||||||
|
|
||||||
@ -1026,24 +997,19 @@ class APDS9960:
|
|||||||
|
|
||||||
self._write_byte_data(APDS9960_REG_GCONF4, val)
|
self._write_byte_data(APDS9960_REG_GCONF4, val)
|
||||||
|
|
||||||
|
|
||||||
def clearAmbientLightInt(self):
|
def clearAmbientLightInt(self):
|
||||||
"""Clears the ambient light interrupt.
|
"""Clears the ambient light interrupt."""
|
||||||
"""
|
|
||||||
self._read_byte_data(APDS9960_REG_AICLEAR)
|
self._read_byte_data(APDS9960_REG_AICLEAR)
|
||||||
|
|
||||||
|
|
||||||
def clearProximityInt(self):
|
def clearProximityInt(self):
|
||||||
"""Clears the proximity interrupt.
|
"""Clears the proximity interrupt."""
|
||||||
"""
|
|
||||||
self._read_byte_data(APDS9960_REG_PICLEAR)
|
self._read_byte_data(APDS9960_REG_PICLEAR)
|
||||||
|
|
||||||
|
|
||||||
def getGestureMode(self):
|
def getGestureMode(self):
|
||||||
"""Tells if the gesture state machine is currently running.
|
"""Tells if the gesture state machine is currently running.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if gesture state machine is running, False if not
|
bool: True if gesture state machine is running, False if not
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_GCONF4)
|
val = self._read_byte_data(APDS9960_REG_GCONF4)
|
||||||
return val & 0b00000001 == 1
|
return val & 0b00000001 == 1
|
||||||
@ -1051,8 +1017,8 @@ class APDS9960:
|
|||||||
def setGestureMode(self, enable):
|
def setGestureMode(self, enable):
|
||||||
"""Turns gesture-related interrupts on or off.
|
"""Turns gesture-related interrupts on or off.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
enable (bool): True to enter gesture state machine, False to turn them off
|
enable (bool): True to enter gesture state machine, False to turn them off
|
||||||
"""
|
"""
|
||||||
val = self._read_byte_data(APDS9960_REG_GCONF4)
|
val = self._read_byte_data(APDS9960_REG_GCONF4)
|
||||||
|
|
||||||
@ -1061,8 +1027,7 @@ class APDS9960:
|
|||||||
if enable:
|
if enable:
|
||||||
val |= 0b00000001
|
val |= 0b00000001
|
||||||
|
|
||||||
self._write_byte_data(APDS9960_REG_GCONF4, val)
|
self._write_byte_data(APDS9960_REG_GCONF4, val)
|
||||||
|
|
||||||
|
|
||||||
# *******************************************************************************
|
# *******************************************************************************
|
||||||
# Raw I2C Reads and Writes
|
# Raw I2C Reads and Writes
|
||||||
@ -1074,12 +1039,10 @@ class APDS9960:
|
|||||||
def _write_byte_data(self, cmd, val):
|
def _write_byte_data(self, cmd, val):
|
||||||
return self.bus.write_byte_data(self.address, cmd, val)
|
return self.bus.write_byte_data(self.address, cmd, val)
|
||||||
|
|
||||||
|
|
||||||
def _read_i2c_block_data(self, cmd, num):
|
def _read_i2c_block_data(self, cmd, num):
|
||||||
return self.bus.read_i2c_block_data(self.address, cmd, num)
|
return self.bus.read_i2c_block_data(self.address, cmd, num)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class uAPDS9960(APDS9960):
|
class uAPDS9960(APDS9960):
|
||||||
"""
|
"""
|
||||||
APDS9960 for MicroPython
|
APDS9960 for MicroPython
|
||||||
@ -1087,6 +1050,7 @@ class uAPDS9960(APDS9960):
|
|||||||
sensor = uAPDS9960(bus=I2C_instance,
|
sensor = uAPDS9960(bus=I2C_instance,
|
||||||
address=APDS9960_I2C_ADDR, valid_id=APDS9960_DEV_ID)
|
address=APDS9960_I2C_ADDR, valid_id=APDS9960_DEV_ID)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _read_byte_data(self, cmd):
|
def _read_byte_data(self, cmd):
|
||||||
return self.bus.readfrom_mem(self.address, cmd, 1)[0]
|
return self.bus.readfrom_mem(self.address, cmd, 1)[0]
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,12 @@
|
|||||||
class ADPS9960InvalidDevId(ValueError):
|
class ADPS9960InvalidDevId(ValueError):
|
||||||
def __init__(self, id, valid_ids):
|
def __init__(self, id, valid_ids):
|
||||||
Exception.__init__(self, "Device id 0x{} is not a valied one (valid: {})!".format(format(id, '02x'), ', '.join(["0x{}".format(format(i, '02x')) for i in valid_ids])))
|
Exception.__init__(
|
||||||
|
self,
|
||||||
|
"Device id 0x{} is not a valied one (valid: {})!".format(
|
||||||
|
format(id, "02x"), ", ".join(["0x{}".format(format(i, "02x")) for i in valid_ids])
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ADPS9960InvalidMode(ValueError):
|
class ADPS9960InvalidMode(ValueError):
|
||||||
def __init__(self, mode):
|
def __init__(self, mode):
|
||||||
|
|||||||
@ -1,17 +1,17 @@
|
|||||||
# The MIT License (MIT)
|
# The MIT License (MIT)
|
||||||
#
|
#
|
||||||
# Copyright (c) 2013-2021 Damien P. George
|
# Copyright (c) 2013-2021 Damien P. George
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
# in the Software without restriction, including without limitation the rights
|
# in the Software without restriction, including without limitation the rights
|
||||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
# copies of the Software, and to permit persons to whom the Software is
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
# furnished to do so, subject to the following conditions:
|
# furnished to do so, subject to the following conditions:
|
||||||
#
|
#
|
||||||
# The above copyright notice and this permission notice shall be included in
|
# The above copyright notice and this permission notice shall be included in
|
||||||
# all copies or substantial portions of the Software.
|
# all copies or substantial portions of the Software.
|
||||||
#
|
#
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
|||||||
@ -11,9 +11,9 @@ MAGGYRO_MODE = 0x06
|
|||||||
AMG_MODE = 0x07
|
AMG_MODE = 0x07
|
||||||
IMUPLUS_MODE = 0x08
|
IMUPLUS_MODE = 0x08
|
||||||
COMPASS_MODE = 0x09
|
COMPASS_MODE = 0x09
|
||||||
M4G_MODE = 0x0a
|
M4G_MODE = 0x0A
|
||||||
NDOF_FMC_OFF_MODE = 0x0b
|
NDOF_FMC_OFF_MODE = 0x0B
|
||||||
NDOF_MODE = 0x0c
|
NDOF_MODE = 0x0C
|
||||||
|
|
||||||
AXIS_P0 = bytes([0x21, 0x04])
|
AXIS_P0 = bytes([0x21, 0x04])
|
||||||
AXIS_P1 = bytes([0x24, 0x00])
|
AXIS_P1 = bytes([0x24, 0x00])
|
||||||
@ -24,75 +24,91 @@ AXIS_P5 = bytes([0x21, 0x01])
|
|||||||
AXIS_P6 = bytes([0x21, 0x07])
|
AXIS_P6 = bytes([0x21, 0x07])
|
||||||
AXIS_P7 = bytes([0x24, 0x05])
|
AXIS_P7 = bytes([0x24, 0x05])
|
||||||
|
|
||||||
_MODE_REGISTER = 0x3d
|
_MODE_REGISTER = 0x3D
|
||||||
_POWER_REGISTER = 0x3e
|
_POWER_REGISTER = 0x3E
|
||||||
_AXIS_MAP_CONFIG = 0x41
|
_AXIS_MAP_CONFIG = 0x41
|
||||||
|
|
||||||
|
|
||||||
class BNO055:
|
class BNO055:
|
||||||
def __init__(self, i2c, address=0x28, mode = NDOF_MODE, axis = AXIS_P4):
|
def __init__(self, i2c, address=0x28, mode=NDOF_MODE, axis=AXIS_P4):
|
||||||
self.i2c = i2c
|
self.i2c = i2c
|
||||||
self.address = address
|
self.address = address
|
||||||
if self.read_id() != bytes([0xA0, 0xFB, 0x32, 0x0F]):
|
if self.read_id() != bytes([0xA0, 0xFB, 0x32, 0x0F]):
|
||||||
raise RuntimeError('Failed to find expected ID register values. Check wiring!')
|
raise RuntimeError("Failed to find expected ID register values. Check wiring!")
|
||||||
self.operation_mode(CONFIG_MODE)
|
self.operation_mode(CONFIG_MODE)
|
||||||
self.system_trigger(0x20)# reset
|
self.system_trigger(0x20) # reset
|
||||||
pyb.delay(700)
|
pyb.delay(700)
|
||||||
self.power_mode(0x00)#POWER_NORMAL
|
self.power_mode(0x00) # POWER_NORMAL
|
||||||
self.axis(axis)
|
self.axis(axis)
|
||||||
self.page(0)
|
self.page(0)
|
||||||
pyb.delay(10)
|
pyb.delay(10)
|
||||||
self.operation_mode(mode)
|
self.operation_mode(mode)
|
||||||
self.system_trigger(0x80) # external oscillator
|
self.system_trigger(0x80) # external oscillator
|
||||||
pyb.delay(200)
|
pyb.delay(200)
|
||||||
|
|
||||||
def read_registers(self, register, size=1):
|
def read_registers(self, register, size=1):
|
||||||
return(self.i2c.readfrom_mem(self.address, register, size))
|
return self.i2c.readfrom_mem(self.address, register, size)
|
||||||
|
|
||||||
def write_registers(self, register, data):
|
def write_registers(self, register, data):
|
||||||
self.i2c.writeto_mem(self.address, register, data)
|
self.i2c.writeto_mem(self.address, register, data)
|
||||||
|
|
||||||
def operation_mode(self, mode=None):
|
def operation_mode(self, mode=None):
|
||||||
if mode:
|
if mode:
|
||||||
self.write_registers(_MODE_REGISTER, bytes([mode]))
|
self.write_registers(_MODE_REGISTER, bytes([mode]))
|
||||||
else:
|
else:
|
||||||
return(self.read_registers(_MODE_REGISTER, 1)[0])
|
return self.read_registers(_MODE_REGISTER, 1)[0]
|
||||||
|
|
||||||
def system_trigger(self, data):
|
def system_trigger(self, data):
|
||||||
self.write_registers(0x3f, bytes([data]))
|
self.write_registers(0x3F, bytes([data]))
|
||||||
|
|
||||||
def power_mode(self, mode=None):
|
def power_mode(self, mode=None):
|
||||||
if mode:
|
if mode:
|
||||||
self.write_registers(_POWER_REGISTER, bytes([mode]))
|
self.write_registers(_POWER_REGISTER, bytes([mode]))
|
||||||
else:
|
else:
|
||||||
return(self.read_registers(_POWER_REGISTER, 1))
|
return self.read_registers(_POWER_REGISTER, 1)
|
||||||
|
|
||||||
def page(self, num=None):
|
def page(self, num=None):
|
||||||
if num:
|
if num:
|
||||||
self.write_registers(0x3f, bytes([num]))
|
self.write_registers(0x3F, bytes([num]))
|
||||||
else:
|
else:
|
||||||
self.read_registers(0x3f)
|
self.read_registers(0x3F)
|
||||||
|
|
||||||
def temperature(self):
|
def temperature(self):
|
||||||
return(self.read_registers(0x34, 1)[0])
|
return self.read_registers(0x34, 1)[0]
|
||||||
|
|
||||||
def read_id(self):
|
def read_id(self):
|
||||||
return(self.read_registers(0x00, 4))
|
return self.read_registers(0x00, 4)
|
||||||
|
|
||||||
def axis(self, placement=None):
|
def axis(self, placement=None):
|
||||||
if placement:
|
if placement:
|
||||||
self.write_registers(_AXIS_MAP_CONFIG, placement)
|
self.write_registers(_AXIS_MAP_CONFIG, placement)
|
||||||
else:
|
else:
|
||||||
return(self.read_registers(_AXIS_MAP_CONFIG, 2))
|
return self.read_registers(_AXIS_MAP_CONFIG, 2)
|
||||||
|
|
||||||
def quaternion(self):
|
def quaternion(self):
|
||||||
data = struct.unpack("<hhhh", self.read_registers(0x20, 8))
|
data = struct.unpack("<hhhh", self.read_registers(0x20, 8))
|
||||||
return [d/(1<<14) for d in data] #[w, x, y, z]
|
return [d / (1 << 14) for d in data] # [w, x, y, z]
|
||||||
|
|
||||||
def euler(self):
|
def euler(self):
|
||||||
data = struct.unpack("<hhh", self.read_registers(0x1A, 6))
|
data = struct.unpack("<hhh", self.read_registers(0x1A, 6))
|
||||||
return [d/16 for d in data] # [yaw, roll, pitch]
|
return [d / 16 for d in data] # [yaw, roll, pitch]
|
||||||
|
|
||||||
def accelerometer(self):
|
def accelerometer(self):
|
||||||
data = struct.unpack("<hhh", self.read_registers(0x08, 6))
|
data = struct.unpack("<hhh", self.read_registers(0x08, 6))
|
||||||
return [d/100 for d in data] #[x, y, z]
|
return [d / 100 for d in data] # [x, y, z]
|
||||||
|
|
||||||
def magnetometer(self):
|
def magnetometer(self):
|
||||||
data = struct.unpack("<hhh", self.read_registers(0x0E, 6))
|
data = struct.unpack("<hhh", self.read_registers(0x0E, 6))
|
||||||
return [d/16 for d in data] # [x, y, z]
|
return [d / 16 for d in data] # [x, y, z]
|
||||||
|
|
||||||
def gyroscope(self):
|
def gyroscope(self):
|
||||||
data = struct.unpack("<hhh", self.read_registers(0x14, 6))
|
data = struct.unpack("<hhh", self.read_registers(0x14, 6))
|
||||||
return [d/900 for d in data] #[x, y, z]
|
return [d / 900 for d in data] # [x, y, z]
|
||||||
|
|
||||||
def linear_acceleration(self):
|
def linear_acceleration(self):
|
||||||
data = struct.unpack("<hhh", self.read_registers(0x28, 6))
|
data = struct.unpack("<hhh", self.read_registers(0x28, 6))
|
||||||
return [d/100 for d in data] #[x, y, z]
|
return [d / 100 for d in data] # [x, y, z]
|
||||||
|
|
||||||
def gravity(self):
|
def gravity(self):
|
||||||
data = struct.unpack("<hhh", self.read_registers(0x2e, 6))
|
data = struct.unpack("<hhh", self.read_registers(0x2E, 6))
|
||||||
return [d/100 for d in data] #[x, y, z]
|
return [d / 100 for d in data] # [x, y, z]
|
||||||
|
|||||||
@ -4,13 +4,14 @@
|
|||||||
# Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
# Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||||
#
|
#
|
||||||
# This work is licensed under the MIT license, see the file LICENSE for details.
|
# This work is licensed under the MIT license, see the file LICENSE for details.
|
||||||
#
|
#
|
||||||
# HTS221 driver based on public domain driver.
|
# HTS221 driver based on public domain driver.
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
class HTS221():
|
|
||||||
|
class HTS221:
|
||||||
def __init__(self, i2c, data_rate=1, dev_addr=0x5F):
|
def __init__(self, i2c, data_rate=1, dev_addr=0x5F):
|
||||||
self.bus = i2c
|
self.bus = i2c
|
||||||
self.odr = data_rate
|
self.odr = data_rate
|
||||||
@ -18,7 +19,7 @@ class HTS221():
|
|||||||
|
|
||||||
# Set configuration register
|
# Set configuration register
|
||||||
# Humidity and temperature average configuration
|
# Humidity and temperature average configuration
|
||||||
self.bus.writeto_mem(self.slv_addr, 0x10, b'\x1B')
|
self.bus.writeto_mem(self.slv_addr, 0x10, b"\x1B")
|
||||||
|
|
||||||
# Set control register
|
# Set control register
|
||||||
# PD | BDU | ODR
|
# PD | BDU | ODR
|
||||||
@ -38,13 +39,13 @@ class HTS221():
|
|||||||
# Temperature Calibration values
|
# Temperature Calibration values
|
||||||
raw = self.read_reg(0x35, 1)
|
raw = self.read_reg(0x35, 1)
|
||||||
self.T0 = ((raw & 0x03) * 256) + self.read_reg(0x32, 1)
|
self.T0 = ((raw & 0x03) * 256) + self.read_reg(0x32, 1)
|
||||||
self.T1 = ((raw & 0x0C) * 64) + self.read_reg(0x33, 1)
|
self.T1 = ((raw & 0x0C) * 64) + self.read_reg(0x33, 1)
|
||||||
self.T2 = self.read_reg(0x3C, 2)
|
self.T2 = self.read_reg(0x3C, 2)
|
||||||
self.T3 = self.read_reg(0x3E, 2)
|
self.T3 = self.read_reg(0x3E, 2)
|
||||||
|
|
||||||
def read_reg(self, reg_addr, size):
|
def read_reg(self, reg_addr, size):
|
||||||
fmt = 'B' if size == 1 else 'H'
|
fmt = "B" if size == 1 else "H"
|
||||||
reg_addr = reg_addr if size == 1 else reg_addr|0x80
|
reg_addr = reg_addr if size == 1 else reg_addr | 0x80
|
||||||
return struct.unpack(fmt, self.bus.readfrom_mem(self.slv_addr, reg_addr, size))[0]
|
return struct.unpack(fmt, self.bus.readfrom_mem(self.slv_addr, reg_addr, size))[0]
|
||||||
|
|
||||||
def humidity(self):
|
def humidity(self):
|
||||||
@ -55,4 +56,6 @@ class HTS221():
|
|||||||
temp = self.read_reg(0x2A, 2)
|
temp = self.read_reg(0x2A, 2)
|
||||||
if temp > 32767:
|
if temp > 32767:
|
||||||
temp -= 65536
|
temp -= 65536
|
||||||
return ((self.T1 - self.T0) / 8.0) * (temp - self.T2) / (self.T3 - self.T2) + (self.T0 / 8.0)
|
return ((self.T1 - self.T0) / 8.0) * (temp - self.T2) / (self.T3 - self.T2) + (
|
||||||
|
self.T0 / 8.0
|
||||||
|
)
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
# Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
# Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||||
# Copyright (c) 2021 Arduino SA
|
# Copyright (c) 2021 Arduino SA
|
||||||
#
|
#
|
||||||
# Authors:
|
# Authors:
|
||||||
# Ibrahim Abdelkader <iabdalkader@openmv.io>
|
# Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||||
# Sebastian Romero <s.romero@arduino.cc>
|
# Sebastian Romero <s.romero@arduino.cc>
|
||||||
#
|
#
|
||||||
@ -15,46 +15,72 @@
|
|||||||
from utime import sleep_ms, ticks_ms
|
from utime import sleep_ms, ticks_ms
|
||||||
from pyb import UART, Pin
|
from pyb import UART, Pin
|
||||||
|
|
||||||
MODE_ABP = 0
|
MODE_ABP = 0
|
||||||
MODE_OTAA = 1
|
MODE_OTAA = 1
|
||||||
|
|
||||||
RF_MODE_RFO = 0
|
RF_MODE_RFO = 0
|
||||||
RF_MODE_PABOOST = 1
|
RF_MODE_PABOOST = 1
|
||||||
|
|
||||||
BAND_AS923 = 0
|
BAND_AS923 = 0
|
||||||
BAND_AU915 = 1
|
BAND_AU915 = 1
|
||||||
BAND_EU868 = 5
|
BAND_EU868 = 5
|
||||||
BAND_KR920 = 6
|
BAND_KR920 = 6
|
||||||
BAND_IN865 = 7
|
BAND_IN865 = 7
|
||||||
BAND_US915 = 8
|
BAND_US915 = 8
|
||||||
BAND_US915_HYBRID = 9
|
BAND_US915_HYBRID = 9
|
||||||
|
|
||||||
CLASS_A = 'A'
|
CLASS_A = "A"
|
||||||
CLASS_B = 'B'
|
CLASS_B = "B"
|
||||||
CLASS_C = 'C'
|
CLASS_C = "C"
|
||||||
|
|
||||||
class LoraError(Exception): pass
|
|
||||||
class LoraErrorTimeout(LoraError): pass
|
|
||||||
class LoraErrorParam(LoraError): pass
|
|
||||||
class LoraErrorBusy(LoraError): pass
|
|
||||||
class LoraErrorOverflow(LoraError): pass
|
|
||||||
class LoraErrorNoNetwork(LoraError): pass
|
|
||||||
class LoraErrorRX(LoraError): pass
|
|
||||||
class LoraErrorUnknown(LoraError): pass
|
|
||||||
|
|
||||||
class Lora():
|
class LoraError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LoraErrorTimeout(LoraError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LoraErrorParam(LoraError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LoraErrorBusy(LoraError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LoraErrorOverflow(LoraError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LoraErrorNoNetwork(LoraError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LoraErrorRX(LoraError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class LoraErrorUnknown(LoraError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Lora:
|
||||||
LoraErrors = {
|
LoraErrors = {
|
||||||
"": LoraErrorTimeout, # empty buffer
|
"": LoraErrorTimeout, # empty buffer
|
||||||
"+ERR": LoraError,
|
"+ERR": LoraError,
|
||||||
"+ERR_PARAM": LoraErrorParam,
|
"+ERR_PARAM": LoraErrorParam,
|
||||||
"+ERR_BUSY": LoraErrorBusy,
|
"+ERR_BUSY": LoraErrorBusy,
|
||||||
"+ERR_PARAM_OVERFLOW": LoraErrorOverflow,
|
"+ERR_PARAM_OVERFLOW": LoraErrorOverflow,
|
||||||
"+ERR_NO_NETWORK": LoraErrorNoNetwork,
|
"+ERR_NO_NETWORK": LoraErrorNoNetwork,
|
||||||
"+ERR_RX": LoraErrorRX,
|
"+ERR_RX": LoraErrorRX,
|
||||||
"+ERR_UNKNOWN": LoraErrorUnknown
|
"+ERR_UNKNOWN": LoraErrorUnknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, uart=None, rst_pin=None, boot_pin=None, band=BAND_EU868, poll_ms=300000, debug=False):
|
def __init__(
|
||||||
|
self, uart=None, rst_pin=None, boot_pin=None, band=BAND_EU868, poll_ms=300000, debug=False
|
||||||
|
):
|
||||||
self.debug = debug
|
self.debug = debug
|
||||||
self.uart = uart
|
self.uart = uart
|
||||||
self.rst_pin = rst_pin
|
self.rst_pin = rst_pin
|
||||||
@ -75,44 +101,43 @@ class Lora():
|
|||||||
|
|
||||||
# Restart module
|
# Restart module
|
||||||
self.restart()
|
self.restart()
|
||||||
|
|
||||||
def init_modem(self):
|
def init_modem(self):
|
||||||
# Portenta vision shield configuration
|
# Portenta vision shield configuration
|
||||||
if not self.rst_pin:
|
if not self.rst_pin:
|
||||||
self.rst_pin = Pin('PC6', Pin.OUT_PP, Pin.PULL_UP, value=1)
|
self.rst_pin = Pin("PC6", Pin.OUT_PP, Pin.PULL_UP, value=1)
|
||||||
if not self.boot_pin:
|
if not self.boot_pin:
|
||||||
self.boot_pin = Pin('PG7', Pin.OUT_PP, Pin.PULL_DOWN, value=0)
|
self.boot_pin = Pin("PG7", Pin.OUT_PP, Pin.PULL_DOWN, value=0)
|
||||||
if not self.uart:
|
if not self.uart:
|
||||||
self.uart = UART(8, 19200)
|
self.uart = UART(8, 19200)
|
||||||
#self.uart = UART(1, 19200) # Use external module
|
# self.uart = UART(1, 19200) # Use external module
|
||||||
self.uart.init(19200, bits=8, parity=None, stop=2, timeout=250, timeout_char=100)
|
self.uart.init(19200, bits=8, parity=None, stop=2, timeout=250, timeout_char=100)
|
||||||
|
|
||||||
|
|
||||||
def debug_print(self, data):
|
def debug_print(self, data):
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print(data)
|
print(data)
|
||||||
|
|
||||||
def is_arduino_firmware(self):
|
def is_arduino_firmware(self):
|
||||||
return 'ARD-078' in self.fw_version
|
return "ARD-078" in self.fw_version
|
||||||
|
|
||||||
def configure_class(self, _class):
|
def configure_class(self, _class):
|
||||||
self.send_command("+CLASS=", _class)
|
self.send_command("+CLASS=", _class)
|
||||||
|
|
||||||
def configure_band(self, band):
|
def configure_band(self, band):
|
||||||
self.send_command("+BAND=", band)
|
self.send_command("+BAND=", band)
|
||||||
if (band == BAND_EU868 and self.is_arduino_firmware()):
|
if band == BAND_EU868 and self.is_arduino_firmware():
|
||||||
self.send_command("+DUTYCYCLE=", 1)
|
self.send_command("+DUTYCYCLE=", 1)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def set_baudrate(self, baudrate):
|
def set_baudrate(self, baudrate):
|
||||||
self.send_command("+UART=", baudrate)
|
self.send_command("+UART=", baudrate)
|
||||||
|
|
||||||
def set_autobaud(self, timeout=10000):
|
def set_autobaud(self, timeout=10000):
|
||||||
start = ticks_ms()
|
start = ticks_ms()
|
||||||
while ((ticks_ms() - start) < timeout):
|
while (ticks_ms() - start) < timeout:
|
||||||
if (self.send_command('', timeout=200, raise_error=False) == '+OK'):
|
if self.send_command("", timeout=200, raise_error=False) == "+OK":
|
||||||
sleep_ms(200)
|
sleep_ms(200)
|
||||||
while (self.uart.any()):
|
while self.uart.any():
|
||||||
self.uart.readchar()
|
self.uart.readchar()
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
@ -123,18 +148,18 @@ class Lora():
|
|||||||
return dev + " " + fw_ver
|
return dev + " " + fw_ver
|
||||||
|
|
||||||
def get_device_eui(self):
|
def get_device_eui(self):
|
||||||
return self.send_command("+DEVEUI?")
|
return self.send_command("+DEVEUI?")
|
||||||
|
|
||||||
def factory_default(self):
|
def factory_default(self):
|
||||||
self.send_command("+FACNEW")
|
self.send_command("+FACNEW")
|
||||||
|
|
||||||
def restart(self):
|
def restart(self):
|
||||||
if (self.set_autobaud() == False):
|
if self.set_autobaud() is False:
|
||||||
raise(LoraError("Failed to set autobaud"))
|
raise (LoraError("Failed to set autobaud"))
|
||||||
|
|
||||||
# Different delimiter as REBOOT response EVENT doesn't end with '\r'.
|
# Different delimiter as REBOOT response EVENT doesn't end with '\r'.
|
||||||
if (self.send_command("+REBOOT", delimiter="+EVENT=0,0", timeout=10000) != "+EVENT=0,0"):
|
if self.send_command("+REBOOT", delimiter="+EVENT=0,0", timeout=10000) != "+EVENT=0,0":
|
||||||
raise(LoraError("Failed to reboot module"))
|
raise (LoraError("Failed to reboot module"))
|
||||||
sleep_ms(1000)
|
sleep_ms(1000)
|
||||||
self.fw_version = self.get_fw_version()
|
self.fw_version = self.get_fw_version()
|
||||||
self.configure_band(self.band)
|
self.configure_band(self.band)
|
||||||
@ -205,72 +230,74 @@ class Lora():
|
|||||||
def join(self, timeout_ms):
|
def join(self, timeout_ms):
|
||||||
if self.send_command("+JOIN", timeout=timeout_ms) != "+ACK":
|
if self.send_command("+JOIN", timeout=timeout_ms) != "+ACK":
|
||||||
return False
|
return False
|
||||||
response = self.receive('\r', timeout=timeout_ms)
|
response = self.receive("\r", timeout=timeout_ms)
|
||||||
return response == "+EVENT=1,1"
|
return response == "+EVENT=1,1"
|
||||||
|
|
||||||
def get_join_status(self):
|
def get_join_status(self):
|
||||||
return int(self.send_command("+NJS?")) == 1
|
return int(self.send_command("+NJS?")) == 1
|
||||||
|
|
||||||
def get_max_size(self):
|
def get_max_size(self):
|
||||||
if (self.is_arduino_firmware()):
|
if self.is_arduino_firmware():
|
||||||
return 64
|
return 64
|
||||||
return int(self.send_command("+MSIZE?", timeout=2000))
|
return int(self.send_command("+MSIZE?", timeout=2000))
|
||||||
|
|
||||||
def poll(self):
|
def poll(self):
|
||||||
if ((ticks_ms() - self.last_poll_ms) > self.poll_ms):
|
if (ticks_ms() - self.last_poll_ms) > self.poll_ms:
|
||||||
self.last_poll_ms = ticks_ms()
|
self.last_poll_ms = ticks_ms()
|
||||||
# Triggers a fake write
|
# Triggers a fake write
|
||||||
self.send_data('\0', True)
|
self.send_data("\0", True)
|
||||||
|
|
||||||
def send_data(self, buff, confirmed=True):
|
def send_data(self, buff, confirmed=True):
|
||||||
max_len = self.get_max_size()
|
max_len = self.get_max_size()
|
||||||
if (len(buff) > max_len):
|
if len(buff) > max_len:
|
||||||
raise(LoraError("Packet exceeds max length"))
|
raise (LoraError("Packet exceeds max length"))
|
||||||
if self.send_command("+CTX " if confirmed else "+UTX ", len(buff), data=buff) != "+OK":
|
if self.send_command("+CTX " if confirmed else "+UTX ", len(buff), data=buff) != "+OK":
|
||||||
return False
|
return False
|
||||||
if confirmed:
|
if confirmed:
|
||||||
response = self.receive('\r', timeout=10000)
|
response = self.receive("\r", timeout=10000)
|
||||||
return response == "+ACK"
|
return response == "+ACK"
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def receive_data(self, timeout=1000):
|
def receive_data(self, timeout=1000):
|
||||||
response = self.receive('\r', timeout=timeout)
|
response = self.receive("\r", timeout=timeout)
|
||||||
if response.startswith("+RECV"):
|
if response.startswith("+RECV"):
|
||||||
params = response.split("=")[1].split(",")
|
params = response.split("=")[1].split(",")
|
||||||
port = params[0]
|
port = params[0]
|
||||||
length = int(params[1])
|
length = int(params[1])
|
||||||
dummy_data_length = 2 # Data starts with \n\n sequence
|
dummy_data_length = 2 # Data starts with \n\n sequence
|
||||||
data = self.receive(max_bytes=length+dummy_data_length, timeout=timeout)[dummy_data_length:]
|
data = self.receive(max_bytes=length + dummy_data_length, timeout=timeout)[
|
||||||
return {'port' : port, 'data' : data}
|
dummy_data_length:
|
||||||
|
]
|
||||||
|
return {"port": port, "data": data}
|
||||||
|
|
||||||
def receive(self, delimiter=None, max_bytes=None, timeout=1000):
|
def receive(self, delimiter=None, max_bytes=None, timeout=1000):
|
||||||
buf = []
|
buf = []
|
||||||
start = ticks_ms()
|
start = ticks_ms()
|
||||||
while ((ticks_ms() - start) < timeout):
|
while (ticks_ms() - start) < timeout:
|
||||||
while (self.uart.any()):
|
while self.uart.any():
|
||||||
buf += chr(self.uart.readchar())
|
buf += chr(self.uart.readchar())
|
||||||
|
|
||||||
if max_bytes and len(buf) == max_bytes:
|
if max_bytes and len(buf) == max_bytes:
|
||||||
data = ''.join(buf)
|
data = "".join(buf)
|
||||||
self.debug_print(data)
|
self.debug_print(data)
|
||||||
return data
|
return data
|
||||||
if (len(buf) and delimiter != None):
|
if len(buf) and delimiter is not None:
|
||||||
data = ''.join(buf)
|
data = "".join(buf)
|
||||||
trimmed = data[0:-1] if data[-1] == '\r' else data
|
trimmed = data[0:-1] if data[-1] == "\r" else data
|
||||||
|
|
||||||
if (isinstance(delimiter, str) and len(delimiter) == 1 and buf[-1] == delimiter):
|
if isinstance(delimiter, str) and len(delimiter) == 1 and buf[-1] == delimiter:
|
||||||
self.debug_print(trimmed)
|
self.debug_print(trimmed)
|
||||||
return trimmed
|
return trimmed
|
||||||
if (isinstance(delimiter, str) and trimmed == delimiter):
|
if isinstance(delimiter, str) and trimmed == delimiter:
|
||||||
self.debug_print(trimmed)
|
self.debug_print(trimmed)
|
||||||
return trimmed
|
return trimmed
|
||||||
if (isinstance(delimiter, list) and trimmed in delimiter):
|
if isinstance(delimiter, list) and trimmed in delimiter:
|
||||||
self.debug_print(trimmed)
|
self.debug_print(trimmed)
|
||||||
return trimmed
|
return trimmed
|
||||||
|
|
||||||
data = ''.join(buf)
|
data = "".join(buf)
|
||||||
self.debug_print(data)
|
self.debug_print(data)
|
||||||
return data[0:-1] if len(data) != 0 and data[-1] == '\r' else data
|
return data[0:-1] if len(data) != 0 and data[-1] == "\r" else data
|
||||||
|
|
||||||
def available(self):
|
def available(self):
|
||||||
return self.uart.any()
|
return self.uart.any()
|
||||||
@ -279,17 +306,17 @@ class Lora():
|
|||||||
self.change_mode(MODE_OTAA)
|
self.change_mode(MODE_OTAA)
|
||||||
self.send_command("+APPEUI=", appEui)
|
self.send_command("+APPEUI=", appEui)
|
||||||
self.send_command("+APPKEY=", appKey)
|
self.send_command("+APPKEY=", appKey)
|
||||||
if (devEui):
|
if devEui:
|
||||||
self.send_command("+DEVEUI=", devEui)
|
self.send_command("+DEVEUI=", devEui)
|
||||||
network_joined = self.join(timeout)
|
network_joined = self.join(timeout)
|
||||||
# This delay was in MKRWAN.h
|
# This delay was in MKRWAN.h
|
||||||
#delay(1000);
|
# delay(1000);
|
||||||
return network_joined
|
return network_joined
|
||||||
|
|
||||||
def join_ABP(self, nwkId, devAddr, nwkSKey, appSKey, timeout=60000):
|
def join_ABP(self, nwkId, devAddr, nwkSKey, appSKey, timeout=60000):
|
||||||
self.change_mode(MODE_ABP)
|
self.change_mode(MODE_ABP)
|
||||||
# Commented in MKRWAN.h
|
# Commented in MKRWAN.h
|
||||||
#self.send_command("+IDNWK=", nwkId)
|
# self.send_command("+IDNWK=", nwkId)
|
||||||
self.send_command("+DEVADDR=", devAddr)
|
self.send_command("+DEVADDR=", devAddr)
|
||||||
self.send_command("+NWKSKEY=", nwkSKey)
|
self.send_command("+NWKSKEY=", nwkSKey)
|
||||||
self.send_command("+APPSKEY=", appSKey)
|
self.send_command("+APPSKEY=", appSKey)
|
||||||
@ -299,13 +326,13 @@ class Lora():
|
|||||||
def handle_error(self, command, data):
|
def handle_error(self, command, data):
|
||||||
if not data.startswith("+ERR") and data != "":
|
if not data.startswith("+ERR") and data != "":
|
||||||
return
|
return
|
||||||
if (data in self.LoraErrors):
|
if data in self.LoraErrors:
|
||||||
raise(self.LoraErrors[data]('Command "%s" has failed!'%command))
|
raise (self.LoraErrors[data]('Command "%s" has failed!' % command))
|
||||||
raise(LoraError('Command: "%s" failed with unknown status: "%s"'%(command, data)))
|
raise (LoraError('Command: "%s" failed with unknown status: "%s"' % (command, data)))
|
||||||
|
|
||||||
def send_command(self, cmd, *args, delimiter='\r', data=None, timeout=1000, raise_error=True):
|
def send_command(self, cmd, *args, delimiter="\r", data=None, timeout=1000, raise_error=True):
|
||||||
# Write command and args
|
# Write command and args
|
||||||
uart_cmd = 'AT'+cmd+''.join([str(x) for x in args])+'\r'
|
uart_cmd = "AT" + cmd + "".join([str(x) for x in args]) + "\r"
|
||||||
self.debug_print(uart_cmd)
|
self.debug_print(uart_cmd)
|
||||||
self.uart.write(uart_cmd)
|
self.uart.write(uart_cmd)
|
||||||
|
|
||||||
@ -321,6 +348,6 @@ class Lora():
|
|||||||
if raise_error:
|
if raise_error:
|
||||||
self.handle_error(cmd, response)
|
self.handle_error(cmd, response)
|
||||||
|
|
||||||
if cmd.endswith('?'):
|
if cmd.endswith("?"):
|
||||||
return response.split('=')[1]
|
return response.split("=")[1]
|
||||||
return response
|
return response
|
||||||
|
|||||||
@ -5,15 +5,16 @@
|
|||||||
# v1.0 2016.4
|
# v1.0 2016.4
|
||||||
# v2.0 2019.7
|
# v2.0 2019.7
|
||||||
|
|
||||||
class LPS22H():
|
|
||||||
LPS22_CTRL_REG1 = const(0x10)
|
|
||||||
LPS22_CTRL_REG2 = const(0x11)
|
|
||||||
LPS22_STATUS = const(0x27)
|
|
||||||
LPS22_TEMP_OUT_L = const(0x2B)
|
|
||||||
LPS22_PRESS_OUT_XL = const(0x28)
|
|
||||||
LPS22_PRESS_OUT_L = const(0x29)
|
|
||||||
|
|
||||||
def __init__(self, i2c, addr = 0x5C):
|
class LPS22H:
|
||||||
|
LPS22_CTRL_REG1 = const(0x10)
|
||||||
|
LPS22_CTRL_REG2 = const(0x11)
|
||||||
|
LPS22_STATUS = const(0x27)
|
||||||
|
LPS22_TEMP_OUT_L = const(0x2B)
|
||||||
|
LPS22_PRESS_OUT_XL = const(0x28)
|
||||||
|
LPS22_PRESS_OUT_L = const(0x29)
|
||||||
|
|
||||||
|
def __init__(self, i2c, addr=0x5C):
|
||||||
self.i2c = i2c
|
self.i2c = i2c
|
||||||
self.addr = addr
|
self.addr = addr
|
||||||
self.tb = bytearray(1)
|
self.tb = bytearray(1)
|
||||||
@ -30,8 +31,10 @@ class LPS22H():
|
|||||||
else:
|
else:
|
||||||
self.getreg(LPS22_CTRL_REG1)
|
self.getreg(LPS22_CTRL_REG1)
|
||||||
self.oneshot = oneshot
|
self.oneshot = oneshot
|
||||||
if oneshot: self.rb[0] &= 0x0F
|
if oneshot:
|
||||||
else: self.rb[0] |= 0x10
|
self.rb[0] &= 0x0F
|
||||||
|
else:
|
||||||
|
self.rb[0] |= 0x10
|
||||||
self.setreg(LPS22_CTRL_REG1, self.rb[0])
|
self.setreg(LPS22_CTRL_REG1, self.rb[0])
|
||||||
|
|
||||||
def int16(self, d):
|
def int16(self, d):
|
||||||
@ -46,12 +49,12 @@ class LPS22H():
|
|||||||
return self.rb[0]
|
return self.rb[0]
|
||||||
|
|
||||||
def get2reg(self, reg):
|
def get2reg(self, reg):
|
||||||
return self.getreg(reg) + self.getreg(reg+1) * 256
|
return self.getreg(reg) + self.getreg(reg + 1) * 256
|
||||||
|
|
||||||
def ONE_SHOT(self, b):
|
def ONE_SHOT(self, b):
|
||||||
if self.oneshot:
|
if self.oneshot:
|
||||||
self.setreg(LPS22_CTRL_REG2, self.getreg(LPS22_CTRL_REG2) | 0x01)
|
self.setreg(LPS22_CTRL_REG2, self.getreg(LPS22_CTRL_REG2) | 0x01)
|
||||||
self.getreg(0x28 + b*2)
|
self.getreg(0x28 + b * 2)
|
||||||
while 1:
|
while 1:
|
||||||
if self.getreg(LPS22_STATUS) & b:
|
if self.getreg(LPS22_STATUS) & b:
|
||||||
return
|
return
|
||||||
@ -59,23 +62,27 @@ class LPS22H():
|
|||||||
def temperature(self):
|
def temperature(self):
|
||||||
self.ONE_SHOT(2)
|
self.ONE_SHOT(2)
|
||||||
try:
|
try:
|
||||||
return self.int16(self.get2reg(LPS22_TEMP_OUT_L))/100
|
return self.int16(self.get2reg(LPS22_TEMP_OUT_L)) / 100
|
||||||
except MemoryError:
|
except MemoryError:
|
||||||
return self.temperature_irq()
|
return self.temperature_irq()
|
||||||
|
|
||||||
def pressure(self):
|
def pressure(self):
|
||||||
self.ONE_SHOT(1)
|
self.ONE_SHOT(1)
|
||||||
try:
|
try:
|
||||||
return (self.getreg(LPS22_PRESS_OUT_XL) + self.get2reg(LPS22_PRESS_OUT_L) * 256)/4096
|
return (self.getreg(LPS22_PRESS_OUT_XL) + self.get2reg(LPS22_PRESS_OUT_L) * 256) / 4096
|
||||||
except MemoryError:
|
except MemoryError:
|
||||||
return self.pressure_irq()
|
return self.pressure_irq()
|
||||||
|
|
||||||
def altitude(self):
|
def altitude(self):
|
||||||
return (((1013.25 / self.pressure())**(1/5.257)) - 1.0) * (self.temperature() + 273.15) / 0.0065
|
return (
|
||||||
|
(((1013.25 / self.pressure()) ** (1 / 5.257)) - 1.0)
|
||||||
|
* (self.temperature() + 273.15)
|
||||||
|
/ 0.0065
|
||||||
|
)
|
||||||
|
|
||||||
def temperature_irq(self):
|
def temperature_irq(self):
|
||||||
self.ONE_SHOT(2)
|
self.ONE_SHOT(2)
|
||||||
return self.int16(self.get2reg(LPS22_TEMP_OUT_L))//100
|
return self.int16(self.get2reg(LPS22_TEMP_OUT_L)) // 100
|
||||||
|
|
||||||
def pressure_irq(self):
|
def pressure_irq(self):
|
||||||
self.ONE_SHOT(1)
|
self.ONE_SHOT(1)
|
||||||
|
|||||||
@ -143,7 +143,7 @@ class LSM6DSOX:
|
|||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
# Load and configure MLC if UCF file is provided
|
# Load and configure MLC if UCF file is provided
|
||||||
if ucf != None:
|
if ucf is not None:
|
||||||
self.load_mlc(ucf)
|
self.load_mlc(ucf)
|
||||||
|
|
||||||
# Set Gyroscope datarate and scale.
|
# Set Gyroscope datarate and scale.
|
||||||
|
|||||||
@ -45,39 +45,41 @@ while (True):
|
|||||||
"""
|
"""
|
||||||
import array
|
import array
|
||||||
|
|
||||||
|
|
||||||
class LSM9DS1:
|
class LSM9DS1:
|
||||||
WHO_AM_I = const(0xf)
|
WHO_AM_I = const(0xF)
|
||||||
CTRL_REG1_G = const(0x10)
|
CTRL_REG1_G = const(0x10)
|
||||||
INT_GEN_SRC_G = const(0x14)
|
INT_GEN_SRC_G = const(0x14)
|
||||||
OUT_TEMP = const(0x15)
|
OUT_TEMP = const(0x15)
|
||||||
OUT_G = const(0x18)
|
OUT_G = const(0x18)
|
||||||
CTRL_REG4_G = const(0x1e)
|
CTRL_REG4_G = const(0x1E)
|
||||||
STATUS_REG = const(0x27)
|
STATUS_REG = const(0x27)
|
||||||
OUT_XL = const(0x28)
|
OUT_XL = const(0x28)
|
||||||
FIFO_CTRL_REG = const(0x2e)
|
FIFO_CTRL_REG = const(0x2E)
|
||||||
FIFO_SRC = const(0x2f)
|
FIFO_SRC = const(0x2F)
|
||||||
OFFSET_REG_X_M = const(0x05)
|
OFFSET_REG_X_M = const(0x05)
|
||||||
CTRL_REG1_M = const(0x20)
|
CTRL_REG1_M = const(0x20)
|
||||||
OUT_M = const(0x28)
|
OUT_M = const(0x28)
|
||||||
SCALE_GYRO = [(245,0),(500,1),(2000,3)]
|
SCALE_GYRO = [(245, 0), (500, 1), (2000, 3)]
|
||||||
SCALE_ACCEL = [(2,0),(4,2),(8,3),(16,1)]
|
SCALE_ACCEL = [(2, 0), (4, 2), (8, 3), (16, 1)]
|
||||||
|
|
||||||
def __init__(self, i2c, address_gyro=0x6B, address_magnet=0x1E):
|
def __init__(self, i2c, address_gyro=0x6B, address_magnet=0x1E):
|
||||||
self.i2c = i2c
|
self.i2c = i2c
|
||||||
self.address_gyro = address_gyro
|
self.address_gyro = address_gyro
|
||||||
self.address_magnet = address_magnet
|
self.address_magnet = address_magnet
|
||||||
# check id's of accelerometer/gyro and magnetometer
|
# check id's of accelerometer/gyro and magnetometer
|
||||||
if (self.read_id_magnet() != b'=') or (self.read_id_gyro() != b'h'):
|
if (self.read_id_magnet() != b"=") or (self.read_id_gyro() != b"h"):
|
||||||
raise OSError("Invalid LSM9DS1 device, using address {}/{}".format(
|
raise OSError(
|
||||||
address_gyro,address_magnet))
|
"Invalid LSM9DS1 device, using address {}/{}".format(address_gyro, address_magnet)
|
||||||
|
)
|
||||||
# allocate scratch buffer for efficient conversions and memread op's
|
# allocate scratch buffer for efficient conversions and memread op's
|
||||||
self.scratch = array.array('B',[0,0,0,0,0,0])
|
self.scratch = array.array("B", [0, 0, 0, 0, 0, 0])
|
||||||
self.scratch_int = array.array('h',[0,0,0])
|
self.scratch_int = array.array("h", [0, 0, 0])
|
||||||
self.init_gyro_accel()
|
self.init_gyro_accel()
|
||||||
self.init_magnetometer()
|
self.init_magnetometer()
|
||||||
|
|
||||||
def init_gyro_accel(self, sample_rate=6, scale_gyro=0, scale_accel=0):
|
def init_gyro_accel(self, sample_rate=6, scale_gyro=0, scale_accel=0):
|
||||||
""" Initalizes Gyro and Accelerator.
|
"""Initalizes Gyro and Accelerator.
|
||||||
sample rate: 0-6 (off, 14.9Hz, 59.5Hz, 119Hz, 238Hz, 476Hz, 952Hz)
|
sample rate: 0-6 (off, 14.9Hz, 59.5Hz, 119Hz, 238Hz, 476Hz, 952Hz)
|
||||||
scale_gyro: 0-2 (245dps, 500dps, 2000dps )
|
scale_gyro: 0-2 (245dps, 500dps, 2000dps )
|
||||||
scale_accel: 0-3 (+/-2g, +/-4g, +/-8g, +-16g)
|
scale_accel: 0-3 (+/-2g, +/-4g, +/-8g, +-16g)
|
||||||
@ -91,7 +93,7 @@ class LSM9DS1:
|
|||||||
mv = memoryview(self.scratch)
|
mv = memoryview(self.scratch)
|
||||||
# angular control registers 1-3 / Orientation
|
# angular control registers 1-3 / Orientation
|
||||||
mv[0] = ((sample_rate & 0x07) << 5) | ((self.SCALE_GYRO[scale_gyro][1] & 0x3) << 3)
|
mv[0] = ((sample_rate & 0x07) << 5) | ((self.SCALE_GYRO[scale_gyro][1] & 0x3) << 3)
|
||||||
mv[1:4] = b'\x00\x00\x00'
|
mv[1:4] = b"\x00\x00\x00"
|
||||||
i2c.writeto_mem(addr, CTRL_REG1_G, mv[:5])
|
i2c.writeto_mem(addr, CTRL_REG1_G, mv[:5])
|
||||||
# ctrl4 - enable x,y,z, outputs, no irq latching, no 4D
|
# ctrl4 - enable x,y,z, outputs, no irq latching, no 4D
|
||||||
# ctrl5 - enable all axes, no decimation
|
# ctrl5 - enable all axes, no decimation
|
||||||
@ -106,8 +108,8 @@ class LSM9DS1:
|
|||||||
i2c.writeto_mem(addr, CTRL_REG4_G, mv[:6])
|
i2c.writeto_mem(addr, CTRL_REG4_G, mv[:6])
|
||||||
|
|
||||||
# fifo: use continous mode (overwrite old data if overflow)
|
# fifo: use continous mode (overwrite old data if overflow)
|
||||||
i2c.writeto_mem(addr, FIFO_CTRL_REG, b'\x00')
|
i2c.writeto_mem(addr, FIFO_CTRL_REG, b"\x00")
|
||||||
i2c.writeto_mem(addr, FIFO_CTRL_REG, b'\xc0')
|
i2c.writeto_mem(addr, FIFO_CTRL_REG, b"\xc0")
|
||||||
|
|
||||||
self.scale_gyro = 32768 / self.SCALE_GYRO[scale_gyro][0]
|
self.scale_gyro = 32768 / self.SCALE_GYRO[scale_gyro][0]
|
||||||
self.scale_accel = 32768 / self.SCALE_ACCEL[scale_accel][0]
|
self.scale_accel = 32768 / self.SCALE_ACCEL[scale_accel][0]
|
||||||
@ -122,26 +124,26 @@ class LSM9DS1:
|
|||||||
i2c = self.i2c
|
i2c = self.i2c
|
||||||
addr = self.address_magnet
|
addr = self.address_magnet
|
||||||
mv = memoryview(self.scratch)
|
mv = memoryview(self.scratch)
|
||||||
mv[0] = 0x40 | (sample_rate << 2) # ctrl1: high performance mode
|
mv[0] = 0x40 | (sample_rate << 2) # ctrl1: high performance mode
|
||||||
mv[1] = scale_magnet << 5 # ctrl2: scale, normal mode, no reset
|
mv[1] = scale_magnet << 5 # ctrl2: scale, normal mode, no reset
|
||||||
mv[2] = 0x00 # ctrl3: continous conversion, no low power, I2C
|
mv[2] = 0x00 # ctrl3: continous conversion, no low power, I2C
|
||||||
mv[3] = 0x08 # ctrl4: high performance z-axis
|
mv[3] = 0x08 # ctrl4: high performance z-axis
|
||||||
mv[4] = 0x00 # ctr5: no fast read, no block update
|
mv[4] = 0x00 # ctr5: no fast read, no block update
|
||||||
i2c.writeto_mem(addr, CTRL_REG1_M, mv[:5])
|
i2c.writeto_mem(addr, CTRL_REG1_M, mv[:5])
|
||||||
self.scale_factor_magnet = 32768 / ((scale_magnet+1) * 4 )
|
self.scale_factor_magnet = 32768 / ((scale_magnet + 1) * 4)
|
||||||
|
|
||||||
def calibrate_magnet(self, offset):
|
def calibrate_magnet(self, offset):
|
||||||
"""
|
"""
|
||||||
offset is a magnet vecor that will be substracted by the magnetometer
|
offset is a magnet vecor that will be substracted by the magnetometer
|
||||||
for each measurement. It is written to the magnetometer's offset register
|
for each measurement. It is written to the magnetometer's offset register
|
||||||
"""
|
"""
|
||||||
offset = [int(i*self.scale_factor_magnet) for i in offset]
|
offset = [int(i * self.scale_factor_magnet) for i in offset]
|
||||||
mv = memoryview(self.scratch)
|
mv = memoryview(self.scratch)
|
||||||
mv[0] = offset[0] & 0xff
|
mv[0] = offset[0] & 0xFF
|
||||||
mv[1] = offset[0] >> 8
|
mv[1] = offset[0] >> 8
|
||||||
mv[2] = offset[1] & 0xff
|
mv[2] = offset[1] & 0xFF
|
||||||
mv[3] = offset[1] >> 8
|
mv[3] = offset[1] >> 8
|
||||||
mv[4] = offset[2] & 0xff
|
mv[4] = offset[2] & 0xFF
|
||||||
mv[5] = offset[2] >> 8
|
mv[5] = offset[2] >> 8
|
||||||
self.i2c.writeto_mem(self.address_magnet, OFFSET_REG_X_M, mv[:6])
|
self.i2c.writeto_mem(self.address_magnet, OFFSET_REG_X_M, mv[:6])
|
||||||
|
|
||||||
@ -158,28 +160,30 @@ class LSM9DS1:
|
|||||||
mv = memoryview(self.scratch_int)
|
mv = memoryview(self.scratch_int)
|
||||||
f = self.scale_factor_magnet
|
f = self.scale_factor_magnet
|
||||||
self.i2c.readfrom_mem_into(self.address_magnet, OUT_M | 0x80, mv)
|
self.i2c.readfrom_mem_into(self.address_magnet, OUT_M | 0x80, mv)
|
||||||
return (mv[0]/f, mv[1]/f, mv[2]/f)
|
return (mv[0] / f, mv[1] / f, mv[2] / f)
|
||||||
|
|
||||||
def read_gyro(self):
|
def read_gyro(self):
|
||||||
"""Returns gyroscope vector in degrees/sec."""
|
"""Returns gyroscope vector in degrees/sec."""
|
||||||
mv = memoryview(self.scratch_int)
|
mv = memoryview(self.scratch_int)
|
||||||
f = self.scale_gyro
|
f = self.scale_gyro
|
||||||
self.i2c.readfrom_mem_into(self.address_gyro, OUT_G | 0x80, mv)
|
self.i2c.readfrom_mem_into(self.address_gyro, OUT_G | 0x80, mv)
|
||||||
return (mv[0]/f, mv[1]/f, mv[2]/f)
|
return (mv[0] / f, mv[1] / f, mv[2] / f)
|
||||||
|
|
||||||
def read_accel(self):
|
def read_accel(self):
|
||||||
"""Returns acceleration vector in gravity units (9.81m/s^2)."""
|
"""Returns acceleration vector in gravity units (9.81m/s^2)."""
|
||||||
mv = memoryview(self.scratch_int)
|
mv = memoryview(self.scratch_int)
|
||||||
f = self.scale_accel
|
f = self.scale_accel
|
||||||
self.i2c.readfrom_mem_into(self.address_gyro, OUT_XL | 0x80, mv)
|
self.i2c.readfrom_mem_into(self.address_gyro, OUT_XL | 0x80, mv)
|
||||||
return (mv[0]/f, mv[1]/f, mv[2]/f)
|
return (mv[0] / f, mv[1] / f, mv[2] / f)
|
||||||
|
|
||||||
def iter_accel_gyro(self):
|
def iter_accel_gyro(self):
|
||||||
"""A generator that returns tuples of (gyro,accelerometer) data from the fifo."""
|
"""A generator that returns tuples of (gyro,accelerometer) data from the fifo."""
|
||||||
while True:
|
while True:
|
||||||
fifo_state = int.from_bytes(self.i2c.readfrom_mem(self.address_gyro, FIFO_SRC, 1),'big')
|
fifo_state = int.from_bytes(
|
||||||
if fifo_state & 0x3f:
|
self.i2c.readfrom_mem(self.address_gyro, FIFO_SRC, 1), "big"
|
||||||
|
)
|
||||||
|
if fifo_state & 0x3F:
|
||||||
# print("Available samples=%d" % (fifo_state & 0x1f))
|
# print("Available samples=%d" % (fifo_state & 0x1f))
|
||||||
yield self.read_gyro(),self.read_accel()
|
yield self.read_gyro(), self.read_accel()
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|||||||
@ -1,51 +1,284 @@
|
|||||||
import struct
|
import struct
|
||||||
|
|
||||||
class ModbusRTU():
|
|
||||||
|
class ModbusRTU:
|
||||||
def __init__(self, uart, slave_id=0x01, register_num=30):
|
def __init__(self, uart, slave_id=0x01, register_num=30):
|
||||||
self.SLAVE_ID = slave_id
|
self.SLAVE_ID = slave_id
|
||||||
self.uart = uart
|
self.uart = uart
|
||||||
self.register_num = register_num
|
self.register_num = register_num
|
||||||
self.REGISTER = [0]*self.register_num
|
self.REGISTER = [0] * self.register_num
|
||||||
self.CRC16_TABLE = [
|
self.CRC16_TABLE = [
|
||||||
0x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241,0xC601,
|
0x0000,
|
||||||
0x06C0,0x0780,0xC741,0x0500,0xC5C1,0xC481,0x0440,0xCC01,0x0CC0,
|
0xC0C1,
|
||||||
0x0D80,0xCD41,0x0F00,0xCFC1,0xCE81,0x0E40,0x0A00,0xCAC1,0xCB81,
|
0xC181,
|
||||||
0x0B40,0xC901,0x09C0,0x0880,0xC841,0xD801,0x18C0,0x1980,0xD941,
|
0x0140,
|
||||||
0x1B00,0xDBC1,0xDA81,0x1A40,0x1E00,0xDEC1,0xDF81,0x1F40,0xDD01,
|
0xC301,
|
||||||
0x1DC0,0x1C80,0xDC41,0x1400,0xD4C1,0xD581,0x1540,0xD701,0x17C0,
|
0x03C0,
|
||||||
0x1680,0xD641,0xD201,0x12C0,0x1380,0xD341,0x1100,0xD1C1,0xD081,
|
0x0280,
|
||||||
0x1040,0xF001,0x30C0,0x3180,0xF141,0x3300,0xF3C1,0xF281,0x3240,
|
0xC241,
|
||||||
0x3600,0xF6C1,0xF781,0x3740,0xF501,0x35C0,0x3480,0xF441,0x3C00,
|
0xC601,
|
||||||
0xFCC1,0xFD81,0x3D40,0xFF01,0x3FC0,0x3E80,0xFE41,0xFA01,0x3AC0,
|
0x06C0,
|
||||||
0x3B80,0xFB41,0x3900,0xF9C1,0xF881,0x3840,0x2800,0xE8C1,0xE981,
|
0x0780,
|
||||||
0x2940,0xEB01,0x2BC0,0x2A80,0xEA41,0xEE01,0x2EC0,0x2F80,0xEF41,
|
0xC741,
|
||||||
0x2D00,0xEDC1,0xEC81,0x2C40,0xE401,0x24C0,0x2580,0xE541,0x2700,
|
0x0500,
|
||||||
0xE7C1,0xE681,0x2640,0x2200,0xE2C1,0xE381,0x2340,0xE101,0x21C0,
|
0xC5C1,
|
||||||
0x2080,0xE041,0xA001,0x60C0,0x6180,0xA141,0x6300,0xA3C1,0xA281,
|
0xC481,
|
||||||
0x6240,0x6600,0xA6C1,0xA781,0x6740,0xA501,0x65C0,0x6480,0xA441,
|
0x0440,
|
||||||
0x6C00,0xACC1,0xAD81,0x6D40,0xAF01,0x6FC0,0x6E80,0xAE41,0xAA01,
|
0xCC01,
|
||||||
0x6AC0,0x6B80,0xAB41,0x6900,0xA9C1,0xA881,0x6840,0x7800,0xB8C1,
|
0x0CC0,
|
||||||
0xB981,0x7940,0xBB01,0x7BC0,0x7A80,0xBA41,0xBE01,0x7EC0,0x7F80,
|
0x0D80,
|
||||||
0xBF41,0x7D00,0xBDC1,0xBC81,0x7C40,0xB401,0x74C0,0x7580,0xB541,
|
0xCD41,
|
||||||
0x7700,0xB7C1,0xB681,0x7640,0x7200,0xB2C1,0xB381,0x7340,0xB101,
|
0x0F00,
|
||||||
0x71C0,0x7080,0xB041,0x5000,0x90C1,0x9181,0x5140,0x9301,0x53C0,
|
0xCFC1,
|
||||||
0x5280,0x9241,0x9601,0x56C0,0x5780,0x9741,0x5500,0x95C1,0x9481,
|
0xCE81,
|
||||||
0x5440,0x9C01,0x5CC0,0x5D80,0x9D41,0x5F00,0x9FC1,0x9E81,0x5E40,
|
0x0E40,
|
||||||
0x5A00,0x9AC1,0x9B81,0x5B40,0x9901,0x59C0,0x5880,0x9841,0x8801,
|
0x0A00,
|
||||||
0x48C0,0x4980,0x8941,0x4B00,0x8BC1,0x8A81,0x4A40,0x4E00,0x8EC1,
|
0xCAC1,
|
||||||
0x8F81,0x4F40,0x8D01,0x4DC0,0x4C80,0x8C41,0x4400,0x84C1,0x8581,
|
0xCB81,
|
||||||
0x4540,0x8701,0x47C0,0x4680,0x8641,0x8201,0x42C0,0x4380,0x8341,
|
0x0B40,
|
||||||
0x4100,0x81C1,0x8081,0x4040]
|
0xC901,
|
||||||
|
0x09C0,
|
||||||
|
0x0880,
|
||||||
|
0xC841,
|
||||||
|
0xD801,
|
||||||
|
0x18C0,
|
||||||
|
0x1980,
|
||||||
|
0xD941,
|
||||||
|
0x1B00,
|
||||||
|
0xDBC1,
|
||||||
|
0xDA81,
|
||||||
|
0x1A40,
|
||||||
|
0x1E00,
|
||||||
|
0xDEC1,
|
||||||
|
0xDF81,
|
||||||
|
0x1F40,
|
||||||
|
0xDD01,
|
||||||
|
0x1DC0,
|
||||||
|
0x1C80,
|
||||||
|
0xDC41,
|
||||||
|
0x1400,
|
||||||
|
0xD4C1,
|
||||||
|
0xD581,
|
||||||
|
0x1540,
|
||||||
|
0xD701,
|
||||||
|
0x17C0,
|
||||||
|
0x1680,
|
||||||
|
0xD641,
|
||||||
|
0xD201,
|
||||||
|
0x12C0,
|
||||||
|
0x1380,
|
||||||
|
0xD341,
|
||||||
|
0x1100,
|
||||||
|
0xD1C1,
|
||||||
|
0xD081,
|
||||||
|
0x1040,
|
||||||
|
0xF001,
|
||||||
|
0x30C0,
|
||||||
|
0x3180,
|
||||||
|
0xF141,
|
||||||
|
0x3300,
|
||||||
|
0xF3C1,
|
||||||
|
0xF281,
|
||||||
|
0x3240,
|
||||||
|
0x3600,
|
||||||
|
0xF6C1,
|
||||||
|
0xF781,
|
||||||
|
0x3740,
|
||||||
|
0xF501,
|
||||||
|
0x35C0,
|
||||||
|
0x3480,
|
||||||
|
0xF441,
|
||||||
|
0x3C00,
|
||||||
|
0xFCC1,
|
||||||
|
0xFD81,
|
||||||
|
0x3D40,
|
||||||
|
0xFF01,
|
||||||
|
0x3FC0,
|
||||||
|
0x3E80,
|
||||||
|
0xFE41,
|
||||||
|
0xFA01,
|
||||||
|
0x3AC0,
|
||||||
|
0x3B80,
|
||||||
|
0xFB41,
|
||||||
|
0x3900,
|
||||||
|
0xF9C1,
|
||||||
|
0xF881,
|
||||||
|
0x3840,
|
||||||
|
0x2800,
|
||||||
|
0xE8C1,
|
||||||
|
0xE981,
|
||||||
|
0x2940,
|
||||||
|
0xEB01,
|
||||||
|
0x2BC0,
|
||||||
|
0x2A80,
|
||||||
|
0xEA41,
|
||||||
|
0xEE01,
|
||||||
|
0x2EC0,
|
||||||
|
0x2F80,
|
||||||
|
0xEF41,
|
||||||
|
0x2D00,
|
||||||
|
0xEDC1,
|
||||||
|
0xEC81,
|
||||||
|
0x2C40,
|
||||||
|
0xE401,
|
||||||
|
0x24C0,
|
||||||
|
0x2580,
|
||||||
|
0xE541,
|
||||||
|
0x2700,
|
||||||
|
0xE7C1,
|
||||||
|
0xE681,
|
||||||
|
0x2640,
|
||||||
|
0x2200,
|
||||||
|
0xE2C1,
|
||||||
|
0xE381,
|
||||||
|
0x2340,
|
||||||
|
0xE101,
|
||||||
|
0x21C0,
|
||||||
|
0x2080,
|
||||||
|
0xE041,
|
||||||
|
0xA001,
|
||||||
|
0x60C0,
|
||||||
|
0x6180,
|
||||||
|
0xA141,
|
||||||
|
0x6300,
|
||||||
|
0xA3C1,
|
||||||
|
0xA281,
|
||||||
|
0x6240,
|
||||||
|
0x6600,
|
||||||
|
0xA6C1,
|
||||||
|
0xA781,
|
||||||
|
0x6740,
|
||||||
|
0xA501,
|
||||||
|
0x65C0,
|
||||||
|
0x6480,
|
||||||
|
0xA441,
|
||||||
|
0x6C00,
|
||||||
|
0xACC1,
|
||||||
|
0xAD81,
|
||||||
|
0x6D40,
|
||||||
|
0xAF01,
|
||||||
|
0x6FC0,
|
||||||
|
0x6E80,
|
||||||
|
0xAE41,
|
||||||
|
0xAA01,
|
||||||
|
0x6AC0,
|
||||||
|
0x6B80,
|
||||||
|
0xAB41,
|
||||||
|
0x6900,
|
||||||
|
0xA9C1,
|
||||||
|
0xA881,
|
||||||
|
0x6840,
|
||||||
|
0x7800,
|
||||||
|
0xB8C1,
|
||||||
|
0xB981,
|
||||||
|
0x7940,
|
||||||
|
0xBB01,
|
||||||
|
0x7BC0,
|
||||||
|
0x7A80,
|
||||||
|
0xBA41,
|
||||||
|
0xBE01,
|
||||||
|
0x7EC0,
|
||||||
|
0x7F80,
|
||||||
|
0xBF41,
|
||||||
|
0x7D00,
|
||||||
|
0xBDC1,
|
||||||
|
0xBC81,
|
||||||
|
0x7C40,
|
||||||
|
0xB401,
|
||||||
|
0x74C0,
|
||||||
|
0x7580,
|
||||||
|
0xB541,
|
||||||
|
0x7700,
|
||||||
|
0xB7C1,
|
||||||
|
0xB681,
|
||||||
|
0x7640,
|
||||||
|
0x7200,
|
||||||
|
0xB2C1,
|
||||||
|
0xB381,
|
||||||
|
0x7340,
|
||||||
|
0xB101,
|
||||||
|
0x71C0,
|
||||||
|
0x7080,
|
||||||
|
0xB041,
|
||||||
|
0x5000,
|
||||||
|
0x90C1,
|
||||||
|
0x9181,
|
||||||
|
0x5140,
|
||||||
|
0x9301,
|
||||||
|
0x53C0,
|
||||||
|
0x5280,
|
||||||
|
0x9241,
|
||||||
|
0x9601,
|
||||||
|
0x56C0,
|
||||||
|
0x5780,
|
||||||
|
0x9741,
|
||||||
|
0x5500,
|
||||||
|
0x95C1,
|
||||||
|
0x9481,
|
||||||
|
0x5440,
|
||||||
|
0x9C01,
|
||||||
|
0x5CC0,
|
||||||
|
0x5D80,
|
||||||
|
0x9D41,
|
||||||
|
0x5F00,
|
||||||
|
0x9FC1,
|
||||||
|
0x9E81,
|
||||||
|
0x5E40,
|
||||||
|
0x5A00,
|
||||||
|
0x9AC1,
|
||||||
|
0x9B81,
|
||||||
|
0x5B40,
|
||||||
|
0x9901,
|
||||||
|
0x59C0,
|
||||||
|
0x5880,
|
||||||
|
0x9841,
|
||||||
|
0x8801,
|
||||||
|
0x48C0,
|
||||||
|
0x4980,
|
||||||
|
0x8941,
|
||||||
|
0x4B00,
|
||||||
|
0x8BC1,
|
||||||
|
0x8A81,
|
||||||
|
0x4A40,
|
||||||
|
0x4E00,
|
||||||
|
0x8EC1,
|
||||||
|
0x8F81,
|
||||||
|
0x4F40,
|
||||||
|
0x8D01,
|
||||||
|
0x4DC0,
|
||||||
|
0x4C80,
|
||||||
|
0x8C41,
|
||||||
|
0x4400,
|
||||||
|
0x84C1,
|
||||||
|
0x8581,
|
||||||
|
0x4540,
|
||||||
|
0x8701,
|
||||||
|
0x47C0,
|
||||||
|
0x4680,
|
||||||
|
0x8641,
|
||||||
|
0x8201,
|
||||||
|
0x42C0,
|
||||||
|
0x4380,
|
||||||
|
0x8341,
|
||||||
|
0x4100,
|
||||||
|
0x81C1,
|
||||||
|
0x8081,
|
||||||
|
0x4040,
|
||||||
|
]
|
||||||
|
|
||||||
def any(self):
|
def any(self):
|
||||||
return self.uart.any()
|
return self.uart.any()
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
self.REGISTER = [0]*self.register_num
|
self.REGISTER = [0] * self.register_num
|
||||||
|
|
||||||
def crc16(self, data):
|
def crc16(self, data):
|
||||||
crc = 0xFFFF
|
crc = 0xFFFF
|
||||||
for char in data:
|
for char in data:
|
||||||
crc = (crc >> 8) ^ self.CRC16_TABLE[((crc) ^ char) & 0xFF]
|
crc = (crc >> 8) ^ self.CRC16_TABLE[((crc) ^ char) & 0xFF]
|
||||||
return struct.pack('<H',crc)
|
return struct.pack("<H", crc)
|
||||||
def handle(self, debug = False):
|
|
||||||
|
def handle(self, debug=False):
|
||||||
REQUEST = self.uart.read()
|
REQUEST = self.uart.read()
|
||||||
if debug:
|
if debug:
|
||||||
print("GOT REQUEST: ", REQUEST)
|
print("GOT REQUEST: ", REQUEST)
|
||||||
@ -53,79 +286,79 @@ class ModbusRTU():
|
|||||||
error_check = REQUEST[-2:]
|
error_check = REQUEST[-2:]
|
||||||
function_code = REQUEST[1]
|
function_code = REQUEST[1]
|
||||||
data = REQUEST[2:]
|
data = REQUEST[2:]
|
||||||
RESPONSE = struct.pack('b', self.SLAVE_ID)
|
RESPONSE = struct.pack("b", self.SLAVE_ID)
|
||||||
if self.crc16(REQUEST[:-2]) != error_check:
|
if self.crc16(REQUEST[:-2]) != error_check:
|
||||||
if debug:
|
if debug:
|
||||||
print("crc not match")
|
print("crc not match")
|
||||||
return 0 # do nothing
|
return 0 # do nothing
|
||||||
if self.SLAVE_ID != additional_address:
|
if self.SLAVE_ID != additional_address:
|
||||||
if debug:
|
if debug:
|
||||||
print("OpenMV slave id: ", self.SLAVE_ID)
|
print("OpenMV slave id: ", self.SLAVE_ID)
|
||||||
print("got cmd id: ", additional_address)
|
print("got cmd id: ", additional_address)
|
||||||
return 0 # do nothing
|
return 0 # do nothing
|
||||||
if function_code == 0x03:
|
if function_code == 0x03:
|
||||||
starting_address = struct.unpack('>h', data[:2])[0]
|
starting_address = struct.unpack(">h", data[:2])[0]
|
||||||
quantity_of_registers = struct.unpack('>h', data[2:4])[0]
|
quantity_of_registers = struct.unpack(">h", data[2:4])[0]
|
||||||
response_registers = []
|
response_registers = []
|
||||||
try:
|
try:
|
||||||
for i in range(starting_address, starting_address+quantity_of_registers):
|
for i in range(starting_address, starting_address + quantity_of_registers):
|
||||||
response_registers.append(self.REGISTER[i])
|
response_registers.append(self.REGISTER[i])
|
||||||
except IndexError as err:
|
except IndexError as err:
|
||||||
RESPONSE += struct.pack('b', function_code|0x80)
|
RESPONSE += struct.pack("b", function_code | 0x80)
|
||||||
RESPONSE += struct.pack('b', 0x02) # Illegal Data Address
|
RESPONSE += struct.pack("b", 0x02) # Illegal Data Address
|
||||||
if debug:
|
if debug:
|
||||||
print("Illegal Data Address: ")
|
print("Illegal Data Address: ")
|
||||||
print(err)
|
print(err)
|
||||||
else:
|
else:
|
||||||
RESPONSE += struct.pack('b', function_code)
|
RESPONSE += struct.pack("b", function_code)
|
||||||
RESPONSE += struct.pack('b', 2*quantity_of_registers)
|
RESPONSE += struct.pack("b", 2 * quantity_of_registers)
|
||||||
for b in response_registers:
|
for b in response_registers:
|
||||||
RESPONSE += struct.pack('>h', b)
|
RESPONSE += struct.pack(">h", b)
|
||||||
elif function_code == 0x06:
|
elif function_code == 0x06:
|
||||||
register_address = struct.unpack('>h', data[:2])[0]
|
register_address = struct.unpack(">h", data[:2])[0]
|
||||||
register_value = struct.unpack('>h', data[2:4])[0]
|
register_value = struct.unpack(">h", data[2:4])[0]
|
||||||
try:
|
try:
|
||||||
self.REGISTER[register_address] = register_value
|
self.REGISTER[register_address] = register_value
|
||||||
except IndexError as err:
|
except IndexError as err:
|
||||||
RESPONSE += struct.pack('b', function_code|0x80)
|
RESPONSE += struct.pack("b", function_code | 0x80)
|
||||||
RESPONSE += struct.pack('b', 0x02) # Illegal Data Address
|
RESPONSE += struct.pack("b", 0x02) # Illegal Data Address
|
||||||
if debug:
|
if debug:
|
||||||
print("Illegal Data Address: ")
|
print("Illegal Data Address: ")
|
||||||
print(err)
|
print(err)
|
||||||
else:
|
else:
|
||||||
RESPONSE += struct.pack('b', function_code)
|
RESPONSE += struct.pack("b", function_code)
|
||||||
RESPONSE += struct.pack('>h', register_address)
|
RESPONSE += struct.pack(">h", register_address)
|
||||||
RESPONSE += struct.pack('>h', self.REGISTER[register_address])
|
RESPONSE += struct.pack(">h", self.REGISTER[register_address])
|
||||||
elif function_code == 0x10:
|
elif function_code == 0x10:
|
||||||
starting_address = struct.unpack('>h', data[:2])[0]
|
starting_address = struct.unpack(">h", data[:2])[0]
|
||||||
quantity_of_registers = struct.unpack('>h', data[2:4])[0]
|
quantity_of_registers = struct.unpack(">h", data[2:4])[0]
|
||||||
byte_of_registers = struct.unpack('b', data[4:5])[0]
|
byte_of_registers = struct.unpack("b", data[4:5])[0]
|
||||||
try:
|
try:
|
||||||
if byte_of_registers != 2*quantity_of_registers:
|
if byte_of_registers != 2 * quantity_of_registers:
|
||||||
raise struct.error
|
raise struct.error
|
||||||
values = struct.unpack('>%dh'%quantity_of_registers, data[5:])
|
values = struct.unpack(">%dh" % quantity_of_registers, data[5:])
|
||||||
except struct.error as err:
|
except struct.error as err:
|
||||||
RESPONSE += struct.pack('b', function_code|0x80)
|
RESPONSE += struct.pack("b", function_code | 0x80)
|
||||||
RESPONSE += struct.pack('b', 0x03) # Illegal Data Value
|
RESPONSE += struct.pack("b", 0x03) # Illegal Data Value
|
||||||
if debug:
|
if debug:
|
||||||
print("Illegal Data Value, data length error")
|
print("Illegal Data Value, data length error")
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
for i in range(quantity_of_registers):
|
for i in range(quantity_of_registers):
|
||||||
self.REGISTER[starting_address+i] = values[i]
|
self.REGISTER[starting_address + i] = values[i]
|
||||||
except IndexError as err:
|
except IndexError as err:
|
||||||
RESPONSE += struct.pack('b', function_code|0x80)
|
RESPONSE += struct.pack("b", function_code | 0x80)
|
||||||
RESPONSE += struct.pack('b', 0x02) # Illegal Data Address
|
RESPONSE += struct.pack("b", 0x02) # Illegal Data Address
|
||||||
if debug:
|
if debug:
|
||||||
print("Illegal Data Address: ")
|
print("Illegal Data Address: ")
|
||||||
print(err)
|
print(err)
|
||||||
else:
|
else:
|
||||||
RESPONSE += struct.pack('b', function_code)
|
RESPONSE += struct.pack("b", function_code)
|
||||||
RESPONSE += struct.pack('>h', starting_address)
|
RESPONSE += struct.pack(">h", starting_address)
|
||||||
RESPONSE += struct.pack('>h', quantity_of_registers)
|
RESPONSE += struct.pack(">h", quantity_of_registers)
|
||||||
else:
|
else:
|
||||||
RESPONSE += struct.pack('b', function_code|0x80)
|
RESPONSE += struct.pack("b", function_code | 0x80)
|
||||||
RESPONSE += struct.pack('b', 0x01) # Illegal Function
|
RESPONSE += struct.pack("b", 0x01) # Illegal Function
|
||||||
RESPONSE += self.crc16(RESPONSE)
|
RESPONSE += self.crc16(RESPONSE)
|
||||||
if debug:
|
if debug:
|
||||||
print("FUNCTION CODE: ", function_code)
|
print("FUNCTION CODE: ", function_code)
|
||||||
|
|||||||
@ -24,15 +24,24 @@
|
|||||||
|
|
||||||
import usocket as socket
|
import usocket as socket
|
||||||
import ustruct as struct
|
import ustruct as struct
|
||||||
from ubinascii import hexlify
|
|
||||||
|
|
||||||
class MQTTException(Exception):
|
class MQTTException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class MQTTClient:
|
|
||||||
|
|
||||||
def __init__(self, client_id, server, port=0, user=None, password=None, keepalive=0,
|
class MQTTClient:
|
||||||
ssl=False, ssl_params={}):
|
def __init__(
|
||||||
|
self,
|
||||||
|
client_id,
|
||||||
|
server,
|
||||||
|
port=0,
|
||||||
|
user=None,
|
||||||
|
password=None,
|
||||||
|
keepalive=0,
|
||||||
|
ssl=False,
|
||||||
|
ssl_params={},
|
||||||
|
):
|
||||||
if port == 0:
|
if port == 0:
|
||||||
port = 8883 if ssl else 1883
|
port = 8883 if ssl else 1883
|
||||||
self.client_id = client_id
|
self.client_id = client_id
|
||||||
@ -60,7 +69,7 @@ class MQTTClient:
|
|||||||
sh = 0
|
sh = 0
|
||||||
while 1:
|
while 1:
|
||||||
b = self.sock.read(1)[0]
|
b = self.sock.read(1)[0]
|
||||||
n |= (b & 0x7f) << sh
|
n |= (b & 0x7F) << sh
|
||||||
if not b & 0x80:
|
if not b & 0x80:
|
||||||
return n
|
return n
|
||||||
sh += 7
|
sh += 7
|
||||||
@ -83,6 +92,7 @@ class MQTTClient:
|
|||||||
self.sock.connect(addr)
|
self.sock.connect(addr)
|
||||||
if self.ssl:
|
if self.ssl:
|
||||||
import ussl
|
import ussl
|
||||||
|
|
||||||
self.sock = ussl.wrap_socket(self.sock, **self.ssl_params)
|
self.sock = ussl.wrap_socket(self.sock, **self.ssl_params)
|
||||||
premsg = bytearray(b"\x10\0\0\0\0\0")
|
premsg = bytearray(b"\x10\0\0\0\0\0")
|
||||||
msg = bytearray(b"\x04MQTT\x04\x02\0\0")
|
msg = bytearray(b"\x04MQTT\x04\x02\0\0")
|
||||||
@ -102,15 +112,15 @@ class MQTTClient:
|
|||||||
msg[6] |= self.lw_retain << 5
|
msg[6] |= self.lw_retain << 5
|
||||||
|
|
||||||
i = 1
|
i = 1
|
||||||
while sz > 0x7f:
|
while sz > 0x7F:
|
||||||
premsg[i] = (sz & 0x7f) | 0x80
|
premsg[i] = (sz & 0x7F) | 0x80
|
||||||
sz >>= 7
|
sz >>= 7
|
||||||
i += 1
|
i += 1
|
||||||
premsg[i] = sz
|
premsg[i] = sz
|
||||||
|
|
||||||
self.sock.write(premsg[0:i + 2])
|
self.sock.write(premsg[0 : i + 2])
|
||||||
self.sock.write(msg)
|
self.sock.write(msg)
|
||||||
#print(hex(len(msg)), hexlify(msg, ":"))
|
# print(hex(len(msg)), hexlify(msg, ":"))
|
||||||
self._send_str(self.client_id)
|
self._send_str(self.client_id)
|
||||||
if self.lw_topic:
|
if self.lw_topic:
|
||||||
self._send_str(self.lw_topic)
|
self._send_str(self.lw_topic)
|
||||||
@ -139,13 +149,13 @@ class MQTTClient:
|
|||||||
sz += 2
|
sz += 2
|
||||||
assert sz < 2097152
|
assert sz < 2097152
|
||||||
i = 1
|
i = 1
|
||||||
while sz > 0x7f:
|
while sz > 0x7F:
|
||||||
pkt[i] = (sz & 0x7f) | 0x80
|
pkt[i] = (sz & 0x7F) | 0x80
|
||||||
sz >>= 7
|
sz >>= 7
|
||||||
i += 1
|
i += 1
|
||||||
pkt[i] = sz
|
pkt[i] = sz
|
||||||
#print(hex(len(pkt)), hexlify(pkt, ":"))
|
# print(hex(len(pkt)), hexlify(pkt, ":"))
|
||||||
self.sock.write(pkt[0:i + 1])
|
self.sock.write(pkt[0 : i + 1])
|
||||||
self._send_str(topic)
|
self._send_str(topic)
|
||||||
if qos > 0:
|
if qos > 0:
|
||||||
self.pid += 1
|
self.pid += 1
|
||||||
@ -171,7 +181,7 @@ class MQTTClient:
|
|||||||
pkt = bytearray(b"\x82\0\0\0")
|
pkt = bytearray(b"\x82\0\0\0")
|
||||||
self.pid += 1
|
self.pid += 1
|
||||||
struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid)
|
struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid)
|
||||||
#print(hex(len(pkt)), hexlify(pkt, ":"))
|
# print(hex(len(pkt)), hexlify(pkt, ":"))
|
||||||
self.sock.write(pkt)
|
self.sock.write(pkt)
|
||||||
self._send_str(topic)
|
self._send_str(topic)
|
||||||
self.sock.write(qos.to_bytes(1, "little"))
|
self.sock.write(qos.to_bytes(1, "little"))
|
||||||
@ -179,7 +189,7 @@ class MQTTClient:
|
|||||||
op = self.wait_msg()
|
op = self.wait_msg()
|
||||||
if op == 0x90:
|
if op == 0x90:
|
||||||
resp = self.sock.read(4)
|
resp = self.sock.read(4)
|
||||||
#print(resp)
|
# print(resp)
|
||||||
assert resp[1] == pkt[2] and resp[2] == pkt[3]
|
assert resp[1] == pkt[2] and resp[2] == pkt[3]
|
||||||
if resp[3] == 0x80:
|
if resp[3] == 0x80:
|
||||||
raise MQTTException(resp[3])
|
raise MQTTException(resp[3])
|
||||||
@ -191,7 +201,7 @@ class MQTTClient:
|
|||||||
# messages processed internally.
|
# messages processed internally.
|
||||||
def wait_msg(self):
|
def wait_msg(self):
|
||||||
res = self.sock.read(1)
|
res = self.sock.read(1)
|
||||||
if res == b"" or res == None:
|
if res == b"" or res is None:
|
||||||
return None
|
return None
|
||||||
self.sock.setblocking(True)
|
self.sock.setblocking(True)
|
||||||
if res == b"\xd0": # PINGRESP
|
if res == b"\xd0": # PINGRESP
|
||||||
@ -199,7 +209,7 @@ class MQTTClient:
|
|||||||
assert sz == 0
|
assert sz == 0
|
||||||
return None
|
return None
|
||||||
op = res[0]
|
op = res[0]
|
||||||
if op & 0xf0 != 0x30:
|
if op & 0xF0 != 0x30:
|
||||||
return op
|
return op
|
||||||
sz = self._recv_len()
|
sz = self._recv_len()
|
||||||
topic_len = self.sock.read(2)
|
topic_len = self.sock.read(2)
|
||||||
|
|||||||
@ -1,41 +1,46 @@
|
|||||||
import pyb, micropython, array, uctypes
|
import micropython
|
||||||
|
import array
|
||||||
|
import uctypes
|
||||||
|
|
||||||
micropython.alloc_emergency_exception_buf(100)
|
micropython.alloc_emergency_exception_buf(100)
|
||||||
|
|
||||||
|
|
||||||
class MutexException(OSError):
|
class MutexException(OSError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Mutex:
|
class Mutex:
|
||||||
@micropython.asm_thumb
|
@micropython.asm_thumb
|
||||||
def _acquire(r0, r1): # Spinlock: wait on the semaphore. Return on success.
|
def _acquire(r0, r1): # Spinlock: wait on the semaphore. Return on success.
|
||||||
label(LOOP)
|
label(LOOP)
|
||||||
ldr(r0, [r1, 0]) # Wait for lock to be zero
|
ldr(r0, [r1, 0]) # Wait for lock to be zero
|
||||||
cmp(r0, 0)
|
cmp(r0, 0)
|
||||||
bne(LOOP) # Another process has the lock: spin on it
|
bne(LOOP) # Another process has the lock: spin on it
|
||||||
cpsid(0) # OK, we have lock at this instant disable interrupts
|
cpsid(0) # OK, we have lock at this instant disable interrupts
|
||||||
ldr(r0, [r1, 0]) # and re-check in case an interrupt occurred
|
ldr(r0, [r1, 0]) # and re-check in case an interrupt occurred
|
||||||
cmp(r0, 0)
|
cmp(r0, 0)
|
||||||
itt(ne) # if someone got in first re-enable ints
|
itt(ne) # if someone got in first re-enable ints
|
||||||
cpsie(0) # and start polling again
|
cpsie(0) # and start polling again
|
||||||
b(LOOP)
|
b(LOOP)
|
||||||
mov(r0, 1) # We have an exclusive access
|
mov(r0, 1) # We have an exclusive access
|
||||||
str(r0, [r1, 0]) # set the lock
|
str(r0, [r1, 0]) # set the lock
|
||||||
cpsie(0)
|
cpsie(0)
|
||||||
|
|
||||||
@micropython.asm_thumb
|
@micropython.asm_thumb
|
||||||
def _attempt(r0, r1): # Nonblocking. Try to lock. Return 0 on success, 1 on fail
|
def _attempt(r0, r1): # Nonblocking. Try to lock. Return 0 on success, 1 on fail
|
||||||
cpsid(0) # disable interrupts
|
cpsid(0) # disable interrupts
|
||||||
ldr(r0, [r1, 0])
|
ldr(r0, [r1, 0])
|
||||||
cmp(r0, 0)
|
cmp(r0, 0)
|
||||||
bne(FAIL) # Another process has the lock: fail
|
bne(FAIL) # Another process has the lock: fail
|
||||||
mov(r2, 1) # No lock
|
mov(r2, 1) # No lock
|
||||||
str(r2, [r1, 0]) # set the lock
|
str(r2, [r1, 0]) # set the lock
|
||||||
label(FAIL)
|
label(FAIL)
|
||||||
cpsie(0) # enable interrupts
|
cpsie(0) # enable interrupts
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.lock = array.array('i', (0,)) # 1 if a process has the lock else 0
|
self.lock = array.array("i", (0,)) # 1 if a process has the lock else 0
|
||||||
|
|
||||||
# POSIX API pthread_mutex_lock() blocks the thread till resource is available.
|
# POSIX API pthread_mutex_lock() blocks the thread till resource is available.
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
self._acquire(uctypes.addressof(self.lock))
|
self._acquire(uctypes.addressof(self.lock))
|
||||||
return self
|
return self
|
||||||
@ -43,13 +48,12 @@ class Mutex:
|
|||||||
def __exit__(self, *_):
|
def __exit__(self, *_):
|
||||||
self.lock[0] = 0
|
self.lock[0] = 0
|
||||||
|
|
||||||
# POSIX pthread_mutex_unlock()
|
# POSIX pthread_mutex_unlock()
|
||||||
def release(self):
|
def release(self):
|
||||||
if self.lock[0] == 0:
|
if self.lock[0] == 0:
|
||||||
raise MutexException('Semaphore already released')
|
raise MutexException("Semaphore already released")
|
||||||
self.lock[0] = 0
|
self.lock[0] = 0
|
||||||
|
|
||||||
# POSIX pthread_mutex_trylock() API. When mutex is not available the function returns immediately
|
# POSIX pthread_mutex_trylock() API. When mutex is not available the function returns immediately
|
||||||
def test(self): # Nonblocking: try to acquire, return True if success.
|
def test(self): # Nonblocking: try to acquire, return True if success.
|
||||||
return self._attempt(uctypes.addressof(self.lock)) == 0
|
return self._attempt(uctypes.addressof(self.lock)) == 0
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
'''
|
"""
|
||||||
Example:
|
Example:
|
||||||
from pid import PID
|
from pid import PID
|
||||||
pid1 = PID(p=0.07, i=0, imax=90)
|
pid1 = PID(p=0.07, i=0, imax=90)
|
||||||
@ -6,22 +6,24 @@ while(True):
|
|||||||
error = 50 #error should be caculated, target - mesure
|
error = 50 #error should be caculated, target - mesure
|
||||||
output=pid1.get_pid(error,1)
|
output=pid1.get_pid(error,1)
|
||||||
#control value with output
|
#control value with output
|
||||||
'''
|
"""
|
||||||
|
|
||||||
from pyb import millis
|
from pyb import millis
|
||||||
from math import pi, isnan
|
from math import pi, isnan
|
||||||
|
|
||||||
|
|
||||||
class PID:
|
class PID:
|
||||||
_kp = _ki = _kd = _integrator = _imax = 0
|
_kp = _ki = _kd = _integrator = _imax = 0
|
||||||
_last_error = _last_derivative = _last_t = 0
|
_last_error = _last_derivative = _last_t = 0
|
||||||
_RC = 1/(2 * pi * 20)
|
_RC = 1 / (2 * pi * 20)
|
||||||
|
|
||||||
def __init__(self, p=0, i=0, d=0, imax=0):
|
def __init__(self, p=0, i=0, d=0, imax=0):
|
||||||
self._kp = float(p)
|
self._kp = float(p)
|
||||||
self._ki = float(i)
|
self._ki = float(i)
|
||||||
self._kd = float(d)
|
self._kd = float(d)
|
||||||
self._imax = abs(imax)
|
self._imax = abs(imax)
|
||||||
self._last_derivative = float('nan')
|
self._last_derivative = float("nan")
|
||||||
|
|
||||||
def get_pid(self, error, scaler):
|
def get_pid(self, error, scaler):
|
||||||
tnow = millis()
|
tnow = millis()
|
||||||
dt = tnow - self._last_t
|
dt = tnow - self._last_t
|
||||||
@ -38,19 +40,22 @@ class PID:
|
|||||||
self._last_derivative = 0
|
self._last_derivative = 0
|
||||||
else:
|
else:
|
||||||
derivative = (error - self._last_error) / delta_time
|
derivative = (error - self._last_error) / delta_time
|
||||||
derivative = self._last_derivative + \
|
derivative = self._last_derivative + (
|
||||||
((delta_time / (self._RC + delta_time)) * \
|
(delta_time / (self._RC + delta_time)) * (derivative - self._last_derivative)
|
||||||
(derivative - self._last_derivative))
|
)
|
||||||
self._last_error = error
|
self._last_error = error
|
||||||
self._last_derivative = derivative
|
self._last_derivative = derivative
|
||||||
output += self._kd * derivative
|
output += self._kd * derivative
|
||||||
output *= scaler
|
output *= scaler
|
||||||
if abs(self._ki) > 0 and dt > 0:
|
if abs(self._ki) > 0 and dt > 0:
|
||||||
self._integrator += (error * self._ki) * scaler * delta_time
|
self._integrator += (error * self._ki) * scaler * delta_time
|
||||||
if self._integrator < -self._imax: self._integrator = -self._imax
|
if self._integrator < -self._imax:
|
||||||
elif self._integrator > self._imax: self._integrator = self._imax
|
self._integrator = -self._imax
|
||||||
|
elif self._integrator > self._imax:
|
||||||
|
self._integrator = self._imax
|
||||||
output += self._integrator
|
output += self._integrator
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def reset_I(self):
|
def reset_I(self):
|
||||||
self._integrator = 0
|
self._integrator = 0
|
||||||
self._last_derivative = float('nan')
|
self._last_derivative = float("nan")
|
||||||
|
|||||||
@ -5,7 +5,13 @@
|
|||||||
#
|
#
|
||||||
# This work is licensed under the MIT license, see the file LICENSE for details.
|
# This work is licensed under the MIT license, see the file LICENSE for details.
|
||||||
|
|
||||||
import gc, network, omv, pyb, select, socket, stm, struct
|
import gc
|
||||||
|
import omv
|
||||||
|
import pyb
|
||||||
|
import select
|
||||||
|
import socket
|
||||||
|
import stm
|
||||||
|
import struct
|
||||||
|
|
||||||
|
|
||||||
class rpc:
|
class rpc:
|
||||||
|
|||||||
@ -5,7 +5,10 @@
|
|||||||
#
|
#
|
||||||
# This work is licensed under the MIT license, see the file LICENSE for details.
|
# This work is licensed under the MIT license, see the file LICENSE for details.
|
||||||
|
|
||||||
import network, pyb, re, socket, struct
|
import pyb
|
||||||
|
import re
|
||||||
|
import socket
|
||||||
|
import struct
|
||||||
|
|
||||||
|
|
||||||
class rtsp_server:
|
class rtsp_server:
|
||||||
|
|||||||
@ -3,23 +3,24 @@ import framebuf
|
|||||||
from pyb import SPI
|
from pyb import SPI
|
||||||
|
|
||||||
# register definitions
|
# register definitions
|
||||||
SET_CONTRAST = const(0x81)
|
SET_CONTRAST = const(0x81)
|
||||||
SET_ENTIRE_ON = const(0xa4)
|
SET_ENTIRE_ON = const(0xA4)
|
||||||
SET_NORM_INV = const(0xa6)
|
SET_NORM_INV = const(0xA6)
|
||||||
SET_DISP = const(0xae)
|
SET_DISP = const(0xAE)
|
||||||
SET_MEM_ADDR = const(0x20)
|
SET_MEM_ADDR = const(0x20)
|
||||||
SET_COL_ADDR = const(0x21)
|
SET_COL_ADDR = const(0x21)
|
||||||
SET_PAGE_ADDR = const(0x22)
|
SET_PAGE_ADDR = const(0x22)
|
||||||
SET_DISP_START_LINE = const(0x40)
|
SET_DISP_START_LINE = const(0x40)
|
||||||
SET_SEG_REMAP = const(0xa0)
|
SET_SEG_REMAP = const(0xA0)
|
||||||
SET_MUX_RATIO = const(0xa8)
|
SET_MUX_RATIO = const(0xA8)
|
||||||
SET_COM_OUT_DIR = const(0xc0)
|
SET_COM_OUT_DIR = const(0xC0)
|
||||||
SET_DISP_OFFSET = const(0xd3)
|
SET_DISP_OFFSET = const(0xD3)
|
||||||
SET_COM_PIN_CFG = const(0xda)
|
SET_COM_PIN_CFG = const(0xDA)
|
||||||
SET_DISP_CLK_DIV = const(0xd5)
|
SET_DISP_CLK_DIV = const(0xD5)
|
||||||
SET_PRECHARGE = const(0xd9)
|
SET_PRECHARGE = const(0xD9)
|
||||||
SET_VCOM_DESEL = const(0xdb)
|
SET_VCOM_DESEL = const(0xDB)
|
||||||
SET_CHARGE_PUMP = const(0x8d)
|
SET_CHARGE_PUMP = const(0x8D)
|
||||||
|
|
||||||
|
|
||||||
class SSD1306:
|
class SSD1306:
|
||||||
def __init__(self, width, height, external_vcc):
|
def __init__(self, width, height, external_vcc):
|
||||||
@ -35,27 +36,37 @@ class SSD1306:
|
|||||||
|
|
||||||
def init_display(self):
|
def init_display(self):
|
||||||
for cmd in (
|
for cmd in (
|
||||||
SET_DISP | 0x00, # off
|
SET_DISP | 0x00, # off
|
||||||
# address setting
|
# address setting
|
||||||
SET_MEM_ADDR, 0x00, # horizontal
|
SET_MEM_ADDR,
|
||||||
|
0x00, # horizontal
|
||||||
# resolution and layout
|
# resolution and layout
|
||||||
SET_DISP_START_LINE | 0x00,
|
SET_DISP_START_LINE | 0x00,
|
||||||
SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
|
SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
|
||||||
SET_MUX_RATIO, self.height - 1,
|
SET_MUX_RATIO,
|
||||||
SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
|
self.height - 1,
|
||||||
SET_DISP_OFFSET, 0x00,
|
SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
|
||||||
SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12,
|
SET_DISP_OFFSET,
|
||||||
|
0x00,
|
||||||
|
SET_COM_PIN_CFG,
|
||||||
|
0x02 if self.height == 32 else 0x12,
|
||||||
# timing and driving scheme
|
# timing and driving scheme
|
||||||
SET_DISP_CLK_DIV, 0x80,
|
SET_DISP_CLK_DIV,
|
||||||
SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1,
|
0x80,
|
||||||
SET_VCOM_DESEL, 0x30, # 0.83*Vcc
|
SET_PRECHARGE,
|
||||||
|
0x22 if self.external_vcc else 0xF1,
|
||||||
|
SET_VCOM_DESEL,
|
||||||
|
0x30, # 0.83*Vcc
|
||||||
# display
|
# display
|
||||||
SET_CONTRAST, 0xff, # maximum
|
SET_CONTRAST,
|
||||||
SET_ENTIRE_ON, # output follows RAM contents
|
0xFF, # maximum
|
||||||
SET_NORM_INV, # not inverted
|
SET_ENTIRE_ON, # output follows RAM contents
|
||||||
|
SET_NORM_INV, # not inverted
|
||||||
# charge pump
|
# charge pump
|
||||||
SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14,
|
SET_CHARGE_PUMP,
|
||||||
SET_DISP | 0x01): # on
|
0x10 if self.external_vcc else 0x14,
|
||||||
|
SET_DISP | 0x01,
|
||||||
|
): # on
|
||||||
self.write_cmd(cmd)
|
self.write_cmd(cmd)
|
||||||
self.fill(0)
|
self.fill(0)
|
||||||
self.show()
|
self.show()
|
||||||
@ -97,27 +108,27 @@ class SSD1306:
|
|||||||
def text(self, string, x, y, col=1):
|
def text(self, string, x, y, col=1):
|
||||||
self.framebuf.text(string, x, y, col)
|
self.framebuf.text(string, x, y, col)
|
||||||
|
|
||||||
|
|
||||||
class SSD1306_I2C(SSD1306):
|
class SSD1306_I2C(SSD1306):
|
||||||
def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False):
|
def __init__(self, width, height, i2c, addr=0x3C, external_vcc=False):
|
||||||
self.i2c = i2c
|
self.i2c = i2c
|
||||||
self.addr = addr
|
self.addr = addr
|
||||||
self.temp = bytearray(2)
|
self.temp = bytearray(2)
|
||||||
super().__init__(width, height, external_vcc)
|
super().__init__(width, height, external_vcc)
|
||||||
|
|
||||||
def write_cmd(self, cmd):
|
def write_cmd(self, cmd):
|
||||||
self.temp[0] = 0x80 # Co=1, D/C#=0
|
self.temp[0] = 0x80 # Co=1, D/C#=0
|
||||||
self.temp[1] = cmd
|
self.temp[1] = cmd
|
||||||
self.i2c.writeto(self.addr, self.temp)
|
self.i2c.writeto(self.addr, self.temp)
|
||||||
|
|
||||||
def write_data(self, buf):
|
def write_data(self, buf):
|
||||||
self.temp[0] = self.addr << 1
|
self.temp[0] = self.addr << 1
|
||||||
self.temp[1] = 0x40 # Co=0, D/C#=1
|
self.temp[1] = 0x40 # Co=0, D/C#=1
|
||||||
self.i2c.start()
|
self.i2c.start()
|
||||||
self.i2c.write(self.temp)
|
self.i2c.write(self.temp)
|
||||||
self.i2c.write(buf)
|
self.i2c.write(buf)
|
||||||
self.i2c.stop()
|
self.i2c.stop()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SSD1306_SPI(SSD1306):
|
class SSD1306_SPI(SSD1306):
|
||||||
def __init__(self, width, height, spi, dc, res, cs, external_vcc=False):
|
def __init__(self, width, height, spi, dc, res, cs, external_vcc=False):
|
||||||
@ -142,7 +153,7 @@ class SSD1306_SPI(SSD1306):
|
|||||||
self.cs.high()
|
self.cs.high()
|
||||||
|
|
||||||
def write_framebuf(self):
|
def write_framebuf(self):
|
||||||
self.spi.init(SPI.MASTER,baudrate=self.rate, polarity=0, phase=0)
|
self.spi.init(SPI.MASTER, baudrate=self.rate, polarity=0, phase=0)
|
||||||
self.cs.high()
|
self.cs.high()
|
||||||
self.dc.high()
|
self.dc.high()
|
||||||
self.cs.low()
|
self.cs.low()
|
||||||
|
|||||||
@ -1,17 +1,19 @@
|
|||||||
import pyb
|
import pyb
|
||||||
|
|
||||||
class Motor():
|
|
||||||
|
class Motor:
|
||||||
def __init__(self, channel):
|
def __init__(self, channel):
|
||||||
if channel == 1:
|
if channel == 1:
|
||||||
self.pin1 = pyb.Pin('P3', pyb.Pin.OUT_PP, pyb.Pin.PULL_NONE)
|
self.pin1 = pyb.Pin("P3", pyb.Pin.OUT_PP, pyb.Pin.PULL_NONE)
|
||||||
self.pin2 = pyb.Pin('P2', pyb.Pin.OUT_PP, pyb.Pin.PULL_NONE)
|
self.pin2 = pyb.Pin("P2", pyb.Pin.OUT_PP, pyb.Pin.PULL_NONE)
|
||||||
tim = pyb.Timer(4, freq=1000)
|
tim = pyb.Timer(4, freq=1000)
|
||||||
self.power = tim.channel(1, pyb.Timer.PWM, pin=pyb.Pin("P7"), pulse_width_percent=0)
|
self.power = tim.channel(1, pyb.Timer.PWM, pin=pyb.Pin("P7"), pulse_width_percent=0)
|
||||||
elif channel == 2:
|
elif channel == 2:
|
||||||
self.pin1 = pyb.Pin('P1', pyb.Pin.OUT_PP, pyb.Pin.PULL_NONE)
|
self.pin1 = pyb.Pin("P1", pyb.Pin.OUT_PP, pyb.Pin.PULL_NONE)
|
||||||
self.pin2 = pyb.Pin('P0', pyb.Pin.OUT_PP, pyb.Pin.PULL_NONE)
|
self.pin2 = pyb.Pin("P0", pyb.Pin.OUT_PP, pyb.Pin.PULL_NONE)
|
||||||
tim = pyb.Timer(4, freq=1000)
|
tim = pyb.Timer(4, freq=1000)
|
||||||
self.power = tim.channel(2, pyb.Timer.PWM, pin=pyb.Pin("P8"), pulse_width_percent=0)
|
self.power = tim.channel(2, pyb.Timer.PWM, pin=pyb.Pin("P8"), pulse_width_percent=0)
|
||||||
|
|
||||||
def set_speed(self, pwm):
|
def set_speed(self, pwm):
|
||||||
if pwm < 0:
|
if pwm < 0:
|
||||||
self.pin1.low()
|
self.pin1.low()
|
||||||
@ -21,13 +23,14 @@ class Motor():
|
|||||||
self.pin2.low()
|
self.pin2.low()
|
||||||
self.power.pulse_width_percent(abs(pwm))
|
self.power.pulse_width_percent(abs(pwm))
|
||||||
|
|
||||||
class Stepper():
|
|
||||||
|
class Stepper:
|
||||||
def __init__(self, stepnumber=200, rpms=2, power=50):
|
def __init__(self, stepnumber=200, rpms=2, power=50):
|
||||||
self.stepnumber = stepnumber
|
self.stepnumber = stepnumber
|
||||||
self.pin1 = pyb.Pin('P3', pyb.Pin.OUT_PP, pyb.Pin.PULL_NONE)
|
self.pin1 = pyb.Pin("P3", pyb.Pin.OUT_PP, pyb.Pin.PULL_NONE)
|
||||||
self.pin2 = pyb.Pin('P2', pyb.Pin.OUT_PP, pyb.Pin.PULL_NONE)
|
self.pin2 = pyb.Pin("P2", pyb.Pin.OUT_PP, pyb.Pin.PULL_NONE)
|
||||||
self.pin3 = pyb.Pin('P1', pyb.Pin.OUT_PP, pyb.Pin.PULL_NONE)
|
self.pin3 = pyb.Pin("P1", pyb.Pin.OUT_PP, pyb.Pin.PULL_NONE)
|
||||||
self.pin4 = pyb.Pin('P0', pyb.Pin.OUT_PP, pyb.Pin.PULL_NONE)
|
self.pin4 = pyb.Pin("P0", pyb.Pin.OUT_PP, pyb.Pin.PULL_NONE)
|
||||||
tim = pyb.Timer(4, freq=1000)
|
tim = pyb.Timer(4, freq=1000)
|
||||||
self.power1 = tim.channel(1, pyb.Timer.PWM, pin=pyb.Pin("P7"), pulse_width_percent=0)
|
self.power1 = tim.channel(1, pyb.Timer.PWM, pin=pyb.Pin("P7"), pulse_width_percent=0)
|
||||||
self.power2 = tim.channel(2, pyb.Timer.PWM, pin=pyb.Pin("P8"), pulse_width_percent=0)
|
self.power2 = tim.channel(2, pyb.Timer.PWM, pin=pyb.Pin("P8"), pulse_width_percent=0)
|
||||||
@ -36,13 +39,13 @@ class Stepper():
|
|||||||
self.phase = self.phase_list()
|
self.phase = self.phase_list()
|
||||||
|
|
||||||
def phase_list(self):
|
def phase_list(self):
|
||||||
phase_list = [(1,0,0,0), (0,0,1,0), (0,1,0,0), (0,0,0,1)]
|
phase_list = [(1, 0, 0, 0), (0, 0, 1, 0), (0, 1, 0, 0), (0, 0, 0, 1)]
|
||||||
while True:
|
while True:
|
||||||
for p in phase_list:
|
for p in phase_list:
|
||||||
yield p
|
yield p
|
||||||
|
|
||||||
def set_speed(self, rpms):
|
def set_speed(self, rpms):
|
||||||
self.delay_time = int(1000000/(rpms*self.stepnumber)/2)
|
self.delay_time = int(1000000 / (rpms * self.stepnumber) / 2)
|
||||||
|
|
||||||
def set_power(self, power):
|
def set_power(self, power):
|
||||||
self.power1.pulse_width_percent(power)
|
self.power1.pulse_width_percent(power)
|
||||||
@ -56,4 +59,3 @@ class Stepper():
|
|||||||
self.pin3.value(phase[2])
|
self.pin3.value(phase[2])
|
||||||
self.pin4.value(phase[3])
|
self.pin4.value(phase[3])
|
||||||
pyb.udelay(self.delay_time)
|
pyb.udelay(self.delay_time)
|
||||||
|
|
||||||
|
|||||||
@ -42,24 +42,36 @@ verbose_l = 0
|
|||||||
client_busy = False
|
client_busy = False
|
||||||
# Interfaces: (IP-Address (string), IP-Address (integer), Netmask (integer))
|
# Interfaces: (IP-Address (string), IP-Address (integer), Netmask (integer))
|
||||||
|
|
||||||
_month_name = ("", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
_month_name = (
|
||||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
|
"",
|
||||||
|
"Jan",
|
||||||
|
"Feb",
|
||||||
|
"Mar",
|
||||||
|
"Apr",
|
||||||
|
"May",
|
||||||
|
"Jun",
|
||||||
|
"Jul",
|
||||||
|
"Aug",
|
||||||
|
"Sep",
|
||||||
|
"Oct",
|
||||||
|
"Nov",
|
||||||
|
"Dec",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class FTP_client:
|
class FTP_client:
|
||||||
|
|
||||||
def __init__(self, ftpsocket, local_addr):
|
def __init__(self, ftpsocket, local_addr):
|
||||||
self.command_client, self.remote_addr = ftpsocket.accept()
|
self.command_client, self.remote_addr = ftpsocket.accept()
|
||||||
self.remote_addr = self.remote_addr[0]
|
self.remote_addr = self.remote_addr[0]
|
||||||
self.command_client.settimeout(_COMMAND_TIMEOUT)
|
self.command_client.settimeout(_COMMAND_TIMEOUT)
|
||||||
log_msg(1, "FTP Command connection from:", self.remote_addr)
|
log_msg(1, "FTP Command connection from:", self.remote_addr)
|
||||||
self.command_client.setsockopt(socket.SOL_SOCKET,
|
self.command_client.setsockopt(
|
||||||
_SO_REGISTER_HANDLER,
|
socket.SOL_SOCKET, _SO_REGISTER_HANDLER, self.exec_ftp_command
|
||||||
self.exec_ftp_command)
|
)
|
||||||
self.command_client.sendall("220 Hello, this is the {}.\r\n".format(sys.platform))
|
self.command_client.sendall("220 Hello, this is the {}.\r\n".format(sys.platform))
|
||||||
self.cwd = '/'
|
self.cwd = "/"
|
||||||
self.fromname = None
|
self.fromname = None
|
||||||
# self.logged_in = False
|
# self.logged_in = False
|
||||||
self.act_data_addr = self.remote_addr
|
self.act_data_addr = self.remote_addr
|
||||||
self.DATA_PORT = 20
|
self.DATA_PORT = 20
|
||||||
self.active = True
|
self.active = True
|
||||||
@ -69,13 +81,12 @@ class FTP_client:
|
|||||||
try:
|
try:
|
||||||
for fname in uos.listdir(path):
|
for fname in uos.listdir(path):
|
||||||
data_client.sendall(self.make_description(path, fname, full))
|
data_client.sendall(self.make_description(path, fname, full))
|
||||||
except Exception as e: # path may be a file name or pattern
|
except Exception: # path may be a file name or pattern
|
||||||
path, pattern = self.split_path(path)
|
path, pattern = self.split_path(path)
|
||||||
try:
|
try:
|
||||||
for fname in uos.listdir(path):
|
for fname in uos.listdir(path):
|
||||||
if self.fncmp(fname, pattern):
|
if self.fncmp(fname, pattern):
|
||||||
data_client.sendall(
|
data_client.sendall(self.make_description(path, fname, full))
|
||||||
self.make_description(path, fname, full))
|
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -83,20 +94,18 @@ class FTP_client:
|
|||||||
global _month_name
|
global _month_name
|
||||||
if full:
|
if full:
|
||||||
stat = uos.stat(self.get_absolute_path(path, fname))
|
stat = uos.stat(self.get_absolute_path(path, fname))
|
||||||
file_permissions = ("drwxr-xr-x"
|
file_permissions = "drwxr-xr-x" if (stat[0] & 0o170000 == 0o040000) else "-rw-r--r--"
|
||||||
if (stat[0] & 0o170000 == 0o040000)
|
|
||||||
else "-rw-r--r--")
|
|
||||||
file_size = stat[6]
|
file_size = stat[6]
|
||||||
tm = stat[7] & 0xffffffff
|
tm = stat[7] & 0xFFFFFFFF
|
||||||
tm = localtime(tm if tm < 0x80000000 else tm - 0x100000000)
|
tm = localtime(tm if tm < 0x80000000 else tm - 0x100000000)
|
||||||
if tm[0] != localtime()[0]:
|
if tm[0] != localtime()[0]:
|
||||||
description = "{} 1 owner group {:>10} {} {:2} {:>5} {}\r\n".\
|
description = "{} 1 owner group {:>10} {} {:2} {:>5} {}\r\n".format(
|
||||||
format(file_permissions, file_size,
|
file_permissions, file_size, _month_name[tm[1]], tm[2], tm[0], fname
|
||||||
_month_name[tm[1]], tm[2], tm[0], fname)
|
)
|
||||||
else:
|
else:
|
||||||
description = "{} 1 owner group {:>10} {} {:2} {:02}:{:02} {}\r\n".\
|
description = "{} 1 owner group {:>10} {} {:2} {:02}:{:02} {}\r\n".format(
|
||||||
format(file_permissions, file_size,
|
file_permissions, file_size, _month_name[tm[1]], tm[2], tm[3], tm[4], fname
|
||||||
_month_name[tm[1]], tm[2], tm[3], tm[4], fname)
|
)
|
||||||
else:
|
else:
|
||||||
description = fname + "\r\n"
|
description = fname + "\r\n"
|
||||||
return description
|
return description
|
||||||
@ -125,22 +134,22 @@ class FTP_client:
|
|||||||
# Just a few special cases "..", "." and ""
|
# Just a few special cases "..", "." and ""
|
||||||
# If payload start's with /, set cwd to /
|
# If payload start's with /, set cwd to /
|
||||||
# and consider the remainder a relative path
|
# and consider the remainder a relative path
|
||||||
if payload.startswith('/'):
|
if payload.startswith("/"):
|
||||||
cwd = "/"
|
cwd = "/"
|
||||||
for token in payload.split("/"):
|
for token in payload.split("/"):
|
||||||
if token == '..':
|
if token == "..":
|
||||||
cwd = self.split_path(cwd)[0]
|
cwd = self.split_path(cwd)[0]
|
||||||
elif token != '.' and token != '':
|
elif token != "." and token != "":
|
||||||
if cwd == '/':
|
if cwd == "/":
|
||||||
cwd += token
|
cwd += token
|
||||||
else:
|
else:
|
||||||
cwd = cwd + '/' + token
|
cwd = cwd + "/" + token
|
||||||
return cwd
|
return cwd
|
||||||
|
|
||||||
def split_path(self, path): # instead of path.rpartition('/')
|
def split_path(self, path): # instead of path.rpartition('/')
|
||||||
tail = path.split('/')[-1]
|
tail = path.split("/")[-1]
|
||||||
head = path[:-(len(tail) + 1)]
|
head = path[: -(len(tail) + 1)]
|
||||||
return ('/' if head == '' else head, tail)
|
return ("/" if head == "" else head, tail)
|
||||||
|
|
||||||
# compare fname against pattern. Pattern may contain
|
# compare fname against pattern. Pattern may contain
|
||||||
# the wildcards ? and *.
|
# the wildcards ? and *.
|
||||||
@ -148,15 +157,15 @@ class FTP_client:
|
|||||||
pi = 0
|
pi = 0
|
||||||
si = 0
|
si = 0
|
||||||
while pi < len(pattern) and si < len(fname):
|
while pi < len(pattern) and si < len(fname):
|
||||||
if (fname[si] == pattern[pi]) or (pattern[pi] == '?'):
|
if (fname[si] == pattern[pi]) or (pattern[pi] == "?"):
|
||||||
si += 1
|
si += 1
|
||||||
pi += 1
|
pi += 1
|
||||||
else:
|
else:
|
||||||
if pattern[pi] == '*': # recurse
|
if pattern[pi] == "*": # recurse
|
||||||
if pi == len(pattern.rstrip("*?")): # only wildcards left
|
if pi == len(pattern.rstrip("*?")): # only wildcards left
|
||||||
return True
|
return True
|
||||||
while si < len(fname):
|
while si < len(fname):
|
||||||
if self.fncmp(fname[si:], pattern[pi + 1:]):
|
if self.fncmp(fname[si:], pattern[pi + 1 :]):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
si += 1
|
si += 1
|
||||||
@ -210,7 +219,7 @@ class FTP_client:
|
|||||||
# return
|
# return
|
||||||
|
|
||||||
command = data.split()[0].upper()
|
command = data.split()[0].upper()
|
||||||
payload = data[len(command):].lstrip() # partition is missing
|
payload = data[len(command) :].lstrip() # partition is missing
|
||||||
path = self.get_absolute_path(self.cwd, payload)
|
path = self.get_absolute_path(self.cwd, payload)
|
||||||
log_msg(1, "Command={}, Payload={}".format(command, payload))
|
log_msg(1, "Command={}, Payload={}".format(command, payload))
|
||||||
|
|
||||||
@ -229,9 +238,9 @@ class FTP_client:
|
|||||||
elif command == "SYST":
|
elif command == "SYST":
|
||||||
cl.sendall("215 UNIX Type: L8\r\n")
|
cl.sendall("215 UNIX Type: L8\r\n")
|
||||||
elif command in ("TYPE", "NOOP", "ABOR"): # just accept & ignore
|
elif command in ("TYPE", "NOOP", "ABOR"): # just accept & ignore
|
||||||
cl.sendall('200 OK\r\n')
|
cl.sendall("200 OK\r\n")
|
||||||
elif command == "QUIT":
|
elif command == "QUIT":
|
||||||
cl.sendall('221 Bye.\r\n')
|
cl.sendall("221 Bye.\r\n")
|
||||||
close_client(cl)
|
close_client(cl)
|
||||||
elif command == "PWD" or command == "XPWD":
|
elif command == "PWD" or command == "XPWD":
|
||||||
cl.sendall('257 "{}"\r\n'.format(self.cwd))
|
cl.sendall('257 "{}"\r\n'.format(self.cwd))
|
||||||
@ -239,44 +248,44 @@ class FTP_client:
|
|||||||
try:
|
try:
|
||||||
if (uos.stat(path)[0] & 0o170000) == 0o040000:
|
if (uos.stat(path)[0] & 0o170000) == 0o040000:
|
||||||
self.cwd = path
|
self.cwd = path
|
||||||
cl.sendall('250 OK\r\n')
|
cl.sendall("250 OK\r\n")
|
||||||
else:
|
else:
|
||||||
cl.sendall('550 Fail\r\n')
|
cl.sendall("550 Fail\r\n")
|
||||||
except:
|
except:
|
||||||
cl.sendall('550 Fail\r\n')
|
cl.sendall("550 Fail\r\n")
|
||||||
elif command == "PASV":
|
elif command == "PASV":
|
||||||
cl.sendall('227 Entering Passive Mode ({},{},{}).\r\n'.format(
|
cl.sendall(
|
||||||
self.pasv_data_addr.replace('.', ','),
|
"227 Entering Passive Mode ({},{},{}).\r\n".format(
|
||||||
_DATA_PORT >> 8, _DATA_PORT % 256))
|
self.pasv_data_addr.replace(".", ","), _DATA_PORT >> 8, _DATA_PORT % 256
|
||||||
|
)
|
||||||
|
)
|
||||||
self.active = False
|
self.active = False
|
||||||
elif command == "PORT":
|
elif command == "PORT":
|
||||||
items = payload.split(",")
|
items = payload.split(",")
|
||||||
if len(items) >= 6:
|
if len(items) >= 6:
|
||||||
self.act_data_addr = '.'.join(items[:4])
|
self.act_data_addr = ".".join(items[:4])
|
||||||
if self.act_data_addr == "127.0.1.1":
|
if self.act_data_addr == "127.0.1.1":
|
||||||
# replace by command session addr
|
# replace by command session addr
|
||||||
self.act_data_addr = self.remote_addr
|
self.act_data_addr = self.remote_addr
|
||||||
self.DATA_PORT = int(items[4]) * 256 + int(items[5])
|
self.DATA_PORT = int(items[4]) * 256 + int(items[5])
|
||||||
cl.sendall('200 OK\r\n')
|
cl.sendall("200 OK\r\n")
|
||||||
self.active = True
|
self.active = True
|
||||||
else:
|
else:
|
||||||
cl.sendall('504 Fail\r\n')
|
cl.sendall("504 Fail\r\n")
|
||||||
elif command == "LIST" or command == "NLST":
|
elif command == "LIST" or command == "NLST":
|
||||||
if payload.startswith("-"):
|
if payload.startswith("-"):
|
||||||
option = payload.split()[0].lower()
|
option = payload.split()[0].lower()
|
||||||
path = self.get_absolute_path(
|
path = self.get_absolute_path(self.cwd, payload[len(option) :].lstrip())
|
||||||
self.cwd, payload[len(option):].lstrip())
|
|
||||||
else:
|
else:
|
||||||
option = ""
|
option = ""
|
||||||
try:
|
try:
|
||||||
data_client = self.open_dataclient()
|
data_client = self.open_dataclient()
|
||||||
cl.sendall("150 Directory listing:\r\n")
|
cl.sendall("150 Directory listing:\r\n")
|
||||||
self.send_list_data(path, data_client,
|
self.send_list_data(path, data_client, command == "LIST" or "l" in option)
|
||||||
command == "LIST" or 'l' in option)
|
|
||||||
cl.sendall("226 Done.\r\n")
|
cl.sendall("226 Done.\r\n")
|
||||||
data_client.close()
|
data_client.close()
|
||||||
except:
|
except:
|
||||||
cl.sendall('550 Fail\r\n')
|
cl.sendall("550 Fail\r\n")
|
||||||
if data_client is not None:
|
if data_client is not None:
|
||||||
data_client.close()
|
data_client.close()
|
||||||
elif command == "RETR":
|
elif command == "RETR":
|
||||||
@ -289,43 +298,47 @@ class FTP_client:
|
|||||||
data_client = None
|
data_client = None
|
||||||
cl.sendall("226 Done.\r\n")
|
cl.sendall("226 Done.\r\n")
|
||||||
except:
|
except:
|
||||||
cl.sendall('550 Fail\r\n')
|
cl.sendall("550 Fail\r\n")
|
||||||
if data_client is not None:
|
if data_client is not None:
|
||||||
data_client.close()
|
data_client.close()
|
||||||
elif command == "STOR" or command == "APPE":
|
elif command == "STOR" or command == "APPE":
|
||||||
try:
|
try:
|
||||||
data_client = self.open_dataclient()
|
data_client = self.open_dataclient()
|
||||||
cl.sendall("150 Opened data connection.\r\n")
|
cl.sendall("150 Opened data connection.\r\n")
|
||||||
self.save_file_data(path, data_client,
|
self.save_file_data(path, data_client, "wb" if command == "STOR" else "ab")
|
||||||
"wb" if command == "STOR" else "ab")
|
|
||||||
# if the next statement is reached,
|
# if the next statement is reached,
|
||||||
# the data_client was closed.
|
# the data_client was closed.
|
||||||
data_client = None
|
data_client = None
|
||||||
cl.sendall("226 Done.\r\n")
|
cl.sendall("226 Done.\r\n")
|
||||||
except:
|
except:
|
||||||
cl.sendall('550 Fail\r\n')
|
cl.sendall("550 Fail\r\n")
|
||||||
if data_client is not None:
|
if data_client is not None:
|
||||||
data_client.close()
|
data_client.close()
|
||||||
elif command == "SIZE":
|
elif command == "SIZE":
|
||||||
try:
|
try:
|
||||||
cl.sendall('213 {}\r\n'.format(uos.stat(path)[6]))
|
cl.sendall("213 {}\r\n".format(uos.stat(path)[6]))
|
||||||
except:
|
except:
|
||||||
cl.sendall('550 Fail\r\n')
|
cl.sendall("550 Fail\r\n")
|
||||||
elif command == "MDTM":
|
elif command == "MDTM":
|
||||||
try:
|
try:
|
||||||
tm=localtime(uos.stat(path)[8])
|
tm = localtime(uos.stat(path)[8])
|
||||||
cl.sendall('213 {:04d}{:02d}{:02d}{:02d}{:02d}{:02d}\r\n'.format(*tm[0:6]))
|
cl.sendall("213 {:04d}{:02d}{:02d}{:02d}{:02d}{:02d}\r\n".format(*tm[0:6]))
|
||||||
except:
|
except:
|
||||||
cl.sendall('550 Fail\r\n')
|
cl.sendall("550 Fail\r\n")
|
||||||
elif command == "STAT":
|
elif command == "STAT":
|
||||||
if payload == "":
|
if payload == "":
|
||||||
cl.sendall("211-Connected to ({})\r\n"
|
cl.sendall(
|
||||||
" Data address ({})\r\n"
|
"211-Connected to ({})\r\n"
|
||||||
" TYPE: Binary STRU: File MODE: Stream\r\n"
|
" Data address ({})\r\n"
|
||||||
" Session timeout {}\r\n"
|
" TYPE: Binary STRU: File MODE: Stream\r\n"
|
||||||
"211 Client count is {}\r\n".format(
|
" Session timeout {}\r\n"
|
||||||
self.remote_addr, self.pasv_data_addr,
|
"211 Client count is {}\r\n".format(
|
||||||
_COMMAND_TIMEOUT, len(client_list)))
|
self.remote_addr,
|
||||||
|
self.pasv_data_addr,
|
||||||
|
_COMMAND_TIMEOUT,
|
||||||
|
len(client_list),
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
cl.sendall("213-Directory listing:\r\n")
|
cl.sendall("213-Directory listing:\r\n")
|
||||||
self.send_list_data(path, cl, True)
|
self.send_list_data(path, cl, True)
|
||||||
@ -333,9 +346,9 @@ class FTP_client:
|
|||||||
elif command == "DELE":
|
elif command == "DELE":
|
||||||
try:
|
try:
|
||||||
uos.remove(path)
|
uos.remove(path)
|
||||||
cl.sendall('250 OK\r\n')
|
cl.sendall("250 OK\r\n")
|
||||||
except:
|
except:
|
||||||
cl.sendall('550 Fail\r\n')
|
cl.sendall("550 Fail\r\n")
|
||||||
elif command == "RNFR":
|
elif command == "RNFR":
|
||||||
try:
|
try:
|
||||||
# just test if the name exists, exception if not
|
# just test if the name exists, exception if not
|
||||||
@ -343,35 +356,35 @@ class FTP_client:
|
|||||||
self.fromname = path
|
self.fromname = path
|
||||||
cl.sendall("350 Rename from\r\n")
|
cl.sendall("350 Rename from\r\n")
|
||||||
except:
|
except:
|
||||||
cl.sendall('550 Fail\r\n')
|
cl.sendall("550 Fail\r\n")
|
||||||
elif command == "RNTO":
|
elif command == "RNTO":
|
||||||
try:
|
try:
|
||||||
uos.rename(self.fromname, path)
|
uos.rename(self.fromname, path)
|
||||||
cl.sendall('250 OK\r\n')
|
cl.sendall("250 OK\r\n")
|
||||||
except:
|
except:
|
||||||
cl.sendall('550 Fail\r\n')
|
cl.sendall("550 Fail\r\n")
|
||||||
self.fromname = None
|
self.fromname = None
|
||||||
elif command == "CDUP" or command == "XCUP":
|
elif command == "CDUP" or command == "XCUP":
|
||||||
self.cwd = self.get_absolute_path(self.cwd, "..")
|
self.cwd = self.get_absolute_path(self.cwd, "..")
|
||||||
cl.sendall('250 OK\r\n')
|
cl.sendall("250 OK\r\n")
|
||||||
elif command == "RMD" or command == "XRMD":
|
elif command == "RMD" or command == "XRMD":
|
||||||
try:
|
try:
|
||||||
uos.rmdir(path)
|
uos.rmdir(path)
|
||||||
cl.sendall('250 OK\r\n')
|
cl.sendall("250 OK\r\n")
|
||||||
except:
|
except:
|
||||||
cl.sendall('550 Fail\r\n')
|
cl.sendall("550 Fail\r\n")
|
||||||
elif command == "MKD" or command == "XMKD":
|
elif command == "MKD" or command == "XMKD":
|
||||||
try:
|
try:
|
||||||
uos.mkdir(path)
|
uos.mkdir(path)
|
||||||
cl.sendall('250 OK\r\n')
|
cl.sendall("250 OK\r\n")
|
||||||
except:
|
except:
|
||||||
cl.sendall('550 Fail\r\n')
|
cl.sendall("550 Fail\r\n")
|
||||||
elif command == "SITE":
|
elif command == "SITE":
|
||||||
try:
|
try:
|
||||||
exec(payload.replace('\0','\n'))
|
exec(payload.replace("\0", "\n"))
|
||||||
cl.sendall('250 OK\r\n')
|
cl.sendall("250 OK\r\n")
|
||||||
except:
|
except:
|
||||||
cl.sendall('550 Fail\r\n')
|
cl.sendall("550 Fail\r\n")
|
||||||
else:
|
else:
|
||||||
cl.sendall("502 Unsupported command.\r\n")
|
cl.sendall("502 Unsupported command.\r\n")
|
||||||
# log_msg(2,
|
# log_msg(2,
|
||||||
@ -422,8 +435,7 @@ def accept_ftp_connect(ftpsocket, local_addr):
|
|||||||
|
|
||||||
def num_ip(ip):
|
def num_ip(ip):
|
||||||
items = ip.split(".")
|
items = ip.split(".")
|
||||||
return (int(items[0]) << 24 | int(items[1]) << 16 |
|
return int(items[0]) << 24 | int(items[1]) << 16 | int(items[2]) << 8 | int(items[3])
|
||||||
int(items[2]) << 8 | int(items[3]))
|
|
||||||
|
|
||||||
|
|
||||||
def stop():
|
def stop():
|
||||||
@ -432,8 +444,7 @@ def stop():
|
|||||||
global client_busy
|
global client_busy
|
||||||
|
|
||||||
for client in client_list:
|
for client in client_list:
|
||||||
client.command_client.setsockopt(socket.SOL_SOCKET,
|
client.command_client.setsockopt(socket.SOL_SOCKET, _SO_REGISTER_HANDLER, None)
|
||||||
_SO_REGISTER_HANDLER, None)
|
|
||||||
client.command_client.close()
|
client.command_client.close()
|
||||||
del client_list
|
del client_list
|
||||||
client_list = []
|
client_list = []
|
||||||
@ -470,19 +481,20 @@ def start(port=21, verbose=0, splash=True):
|
|||||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
sock.bind(addr[0][4])
|
sock.bind(addr[0][4])
|
||||||
sock.listen(1)
|
sock.listen(1)
|
||||||
sock.setsockopt(socket.SOL_SOCKET,
|
sock.setsockopt(
|
||||||
_SO_REGISTER_HANDLER,
|
socket.SOL_SOCKET, _SO_REGISTER_HANDLER, lambda s: accept_ftp_connect(s, ifconfig[0])
|
||||||
lambda s : accept_ftp_connect(s, ifconfig[0]))
|
)
|
||||||
ftpsockets.append(sock)
|
ftpsockets.append(sock)
|
||||||
if splash:
|
if splash:
|
||||||
print("FTP server started on {}:{}".format(ifconfig[0], port))
|
print("FTP server started on {}:{}".format(ifconfig[0], port))
|
||||||
|
|
||||||
datasocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
datasocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
datasocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
datasocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
datasocket.bind(('0.0.0.0', _DATA_PORT))
|
datasocket.bind(("0.0.0.0", _DATA_PORT))
|
||||||
datasocket.listen(1)
|
datasocket.listen(1)
|
||||||
datasocket.settimeout(10)
|
datasocket.settimeout(10)
|
||||||
|
|
||||||
|
|
||||||
def restart(port=21, verbose=0, splash=True):
|
def restart(port=21, verbose=0, splash=True):
|
||||||
stop()
|
stop()
|
||||||
sleep_ms(200)
|
sleep_ms(200)
|
||||||
|
|||||||
@ -2,23 +2,25 @@
|
|||||||
# copyright (c) 2018 Shawwwn <shawwwn1@gmail.com>
|
# copyright (c) 2018 Shawwwn <shawwwn1@gmail.com>
|
||||||
# License: MIT
|
# License: MIT
|
||||||
|
|
||||||
|
|
||||||
# Internet Checksum Algorithm
|
# Internet Checksum Algorithm
|
||||||
# Author: Olav Morken
|
# Author: Olav Morken
|
||||||
# https://github.com/olavmrk/python-ping/blob/master/ping.py
|
# https://github.com/olavmrk/python-ping/blob/master/ping.py
|
||||||
# @data: bytes
|
# @data: bytes
|
||||||
def checksum(data):
|
def checksum(data):
|
||||||
if len(data) & 0x1: # Odd number of bytes
|
if len(data) & 0x1: # Odd number of bytes
|
||||||
data += b'\0'
|
data += b"\0"
|
||||||
cs = 0
|
cs = 0
|
||||||
for pos in range(0, len(data), 2):
|
for pos in range(0, len(data), 2):
|
||||||
b1 = data[pos]
|
b1 = data[pos]
|
||||||
b2 = data[pos + 1]
|
b2 = data[pos + 1]
|
||||||
cs += (b1 << 8) + b2
|
cs += (b1 << 8) + b2
|
||||||
while cs >= 0x10000:
|
while cs >= 0x10000:
|
||||||
cs = (cs & 0xffff) + (cs >> 16)
|
cs = (cs & 0xFFFF) + (cs >> 16)
|
||||||
cs = ~cs & 0xffff
|
cs = ~cs & 0xFFFF
|
||||||
return cs
|
return cs
|
||||||
|
|
||||||
|
|
||||||
def ping(host, count=4, timeout=5000, interval=10, quiet=False, size=64):
|
def ping(host, count=4, timeout=5000, interval=10, quiet=False, size=64):
|
||||||
import utime
|
import utime
|
||||||
import uselect
|
import uselect
|
||||||
@ -29,7 +31,7 @@ def ping(host, count=4, timeout=5000, interval=10, quiet=False, size=64):
|
|||||||
|
|
||||||
# prepare packet
|
# prepare packet
|
||||||
assert size >= 16, "pkt size too small"
|
assert size >= 16, "pkt size too small"
|
||||||
pkt = b'Q'*size
|
pkt = b"Q" * size
|
||||||
pkt_desc = {
|
pkt_desc = {
|
||||||
"type": uctypes.UINT8 | 0,
|
"type": uctypes.UINT8 | 0,
|
||||||
"code": uctypes.UINT8 | 1,
|
"code": uctypes.UINT8 | 1,
|
||||||
@ -37,9 +39,9 @@ def ping(host, count=4, timeout=5000, interval=10, quiet=False, size=64):
|
|||||||
"id": uctypes.UINT16 | 4,
|
"id": uctypes.UINT16 | 4,
|
||||||
"seq": uctypes.INT16 | 6,
|
"seq": uctypes.INT16 | 6,
|
||||||
"timestamp": uctypes.UINT64 | 8,
|
"timestamp": uctypes.UINT64 | 8,
|
||||||
} # packet header descriptor
|
} # packet header descriptor
|
||||||
h = uctypes.struct(uctypes.addressof(pkt), pkt_desc, uctypes.BIG_ENDIAN)
|
h = uctypes.struct(uctypes.addressof(pkt), pkt_desc, uctypes.BIG_ENDIAN)
|
||||||
h.type = 8 # ICMP_ECHO_REQUEST
|
h.type = 8 # ICMP_ECHO_REQUEST
|
||||||
h.code = 0
|
h.code = 0
|
||||||
h.checksum = 0
|
h.checksum = 0
|
||||||
h.id = urandom.randint(0, 65535)
|
h.id = urandom.randint(0, 65535)
|
||||||
@ -48,19 +50,19 @@ def ping(host, count=4, timeout=5000, interval=10, quiet=False, size=64):
|
|||||||
# init socket
|
# init socket
|
||||||
sock = usocket.socket(usocket.AF_INET, usocket.SOCK_RAW, 1)
|
sock = usocket.socket(usocket.AF_INET, usocket.SOCK_RAW, 1)
|
||||||
sock.setblocking(0)
|
sock.setblocking(0)
|
||||||
sock.settimeout(timeout/1000)
|
sock.settimeout(timeout / 1000)
|
||||||
addr = usocket.getaddrinfo(host, 1)[0][-1][0] # ip address
|
addr = usocket.getaddrinfo(host, 1)[0][-1][0] # ip address
|
||||||
sock.connect((addr, 1))
|
sock.connect((addr, 1))
|
||||||
not quiet and print("PING %s (%s): %u data bytes" % (host, addr, len(pkt)))
|
not quiet and print("PING %s (%s): %u data bytes" % (host, addr, len(pkt)))
|
||||||
|
|
||||||
seqs = list(range(1, count+1)) # [1,2,...,count]
|
seqs = list(range(1, count + 1)) # [1,2,...,count]
|
||||||
c = 1
|
c = 1
|
||||||
t = 0
|
t = 0
|
||||||
n_trans = 0
|
n_trans = 0
|
||||||
n_recv = 0
|
n_recv = 0
|
||||||
finish = False
|
finish = False
|
||||||
while t < timeout:
|
while t < timeout:
|
||||||
if t==interval and c<=count:
|
if t == interval and c <= count:
|
||||||
# send packet
|
# send packet
|
||||||
h.checksum = 0
|
h.checksum = 0
|
||||||
h.seq = c
|
h.seq = c
|
||||||
@ -68,7 +70,7 @@ def ping(host, count=4, timeout=5000, interval=10, quiet=False, size=64):
|
|||||||
h.checksum = checksum(pkt)
|
h.checksum = checksum(pkt)
|
||||||
if sock.send(pkt) == size:
|
if sock.send(pkt) == size:
|
||||||
n_trans += 1
|
n_trans += 1
|
||||||
t = 0 # reset timeout
|
t = 0 # reset timeout
|
||||||
else:
|
else:
|
||||||
seqs.remove(c)
|
seqs.remove(c)
|
||||||
c += 1
|
c += 1
|
||||||
@ -82,11 +84,14 @@ def ping(host, count=4, timeout=5000, interval=10, quiet=False, size=64):
|
|||||||
h2 = uctypes.struct(uctypes.addressof(resp_mv[20:]), pkt_desc, uctypes.BIG_ENDIAN)
|
h2 = uctypes.struct(uctypes.addressof(resp_mv[20:]), pkt_desc, uctypes.BIG_ENDIAN)
|
||||||
# TODO: validate checksum (optional)
|
# TODO: validate checksum (optional)
|
||||||
seq = h2.seq
|
seq = h2.seq
|
||||||
if h2.type==0 and h2.id==h.id and (seq in seqs): # 0: ICMP_ECHO_REPLY
|
if h2.type == 0 and h2.id == h.id and (seq in seqs): # 0: ICMP_ECHO_REPLY
|
||||||
t_elasped = (utime.ticks_us()-h2.timestamp) / 1000
|
t_elasped = (utime.ticks_us() - h2.timestamp) / 1000
|
||||||
ttl = ustruct.unpack('!B', resp_mv[8:9])[0] # time-to-live
|
ttl = ustruct.unpack("!B", resp_mv[8:9])[0] # time-to-live
|
||||||
n_recv += 1
|
n_recv += 1
|
||||||
not quiet and print("%u bytes from %s: icmp_seq=%u, ttl=%u, time=%f ms" % (len(resp), addr, seq, ttl, t_elasped))
|
not quiet and print(
|
||||||
|
"%u bytes from %s: icmp_seq=%u, ttl=%u, time=%f ms"
|
||||||
|
% (len(resp), addr, seq, ttl, t_elasped)
|
||||||
|
)
|
||||||
seqs.remove(seq)
|
seqs.remove(seq)
|
||||||
if len(seqs) == 0:
|
if len(seqs) == 0:
|
||||||
finish = True
|
finish = True
|
||||||
|
|||||||
@ -1,17 +1,17 @@
|
|||||||
# The MIT License (MIT)
|
# The MIT License (MIT)
|
||||||
#
|
#
|
||||||
# Copyright (c) 2013, 2014 micropython-lib contributors
|
# Copyright (c) 2013, 2014 micropython-lib contributors
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
# in the Software without restriction, including without limitation the rights
|
# in the Software without restriction, including without limitation the rights
|
||||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
# copies of the Software, and to permit persons to whom the Software is
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
# furnished to do so, subject to the following conditions:
|
# furnished to do so, subject to the following conditions:
|
||||||
#
|
#
|
||||||
# The above copyright notice and this permission notice shall be included in
|
# The above copyright notice and this permission notice shall be included in
|
||||||
# all copies or substantial portions of the Software.
|
# all copies or substantial portions of the Software.
|
||||||
#
|
#
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
@ -20,7 +20,8 @@
|
|||||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
# THE SOFTWARE.
|
# THE SOFTWARE.
|
||||||
|
|
||||||
# Source: improved version of https://github.com/micropython/micropython-lib/blob/master/python-ecosys/urequests/urequests.py
|
# Source: improved version of:
|
||||||
|
# https://github.com/micropython/micropython-lib/blob/master/python-ecosys/urequests/urequests.py
|
||||||
# Some useful links for future updates:
|
# Some useful links for future updates:
|
||||||
# https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4
|
# https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4
|
||||||
# https://docs.python-requests.org/en/master/
|
# https://docs.python-requests.org/en/master/
|
||||||
@ -28,6 +29,7 @@
|
|||||||
import usocket
|
import usocket
|
||||||
import ubinascii
|
import ubinascii
|
||||||
|
|
||||||
|
|
||||||
class Response:
|
class Response:
|
||||||
def __init__(self, code, reason, headers=None, content=None):
|
def __init__(self, code, reason, headers=None, content=None):
|
||||||
self.encoding = "utf-8"
|
self.encoding = "utf-8"
|
||||||
@ -46,23 +48,26 @@ class Response:
|
|||||||
|
|
||||||
def json(self):
|
def json(self):
|
||||||
import ujson
|
import ujson
|
||||||
|
|
||||||
return ujson.loads(self._content)
|
return ujson.loads(self._content)
|
||||||
|
|
||||||
|
|
||||||
def readline(s):
|
def readline(s):
|
||||||
l = bytearray()
|
l = bytearray()
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
l += s.read(1)
|
l += s.read(1)
|
||||||
if (l[-1] == b'\n'):
|
if l[-1] == b"\n":
|
||||||
break
|
break
|
||||||
except:
|
except:
|
||||||
break
|
break
|
||||||
return l
|
return l
|
||||||
|
|
||||||
|
|
||||||
def socket_readall(s):
|
def socket_readall(s):
|
||||||
buf = b''
|
buf = b""
|
||||||
while True:
|
while True:
|
||||||
recv = b''
|
recv = b""
|
||||||
try:
|
try:
|
||||||
recv = s.recv(1)
|
recv = s.recv(1)
|
||||||
except:
|
except:
|
||||||
@ -72,6 +77,7 @@ def socket_readall(s):
|
|||||||
buf += recv
|
buf += recv
|
||||||
return buf
|
return buf
|
||||||
|
|
||||||
|
|
||||||
def request(method, url, data=None, json=None, files=None, headers={}, auth=None, stream=None):
|
def request(method, url, data=None, json=None, files=None, headers={}, auth=None, stream=None):
|
||||||
try:
|
try:
|
||||||
proto, dummy, host, path = url.split("/", 3)
|
proto, dummy, host, path = url.split("/", 3)
|
||||||
@ -82,6 +88,7 @@ def request(method, url, data=None, json=None, files=None, headers={}, auth=None
|
|||||||
port = 80
|
port = 80
|
||||||
elif proto == "https:":
|
elif proto == "https:":
|
||||||
import ussl
|
import ussl
|
||||||
|
|
||||||
port = 443
|
port = 443
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unsupported protocol: " + proto)
|
raise ValueError("Unsupported protocol: " + proto)
|
||||||
@ -91,7 +98,9 @@ def request(method, url, data=None, json=None, files=None, headers={}, auth=None
|
|||||||
port = int(port)
|
port = int(port)
|
||||||
|
|
||||||
if auth:
|
if auth:
|
||||||
headers['Authorization'] = b'Basic %s'%(ubinascii.b2a_base64('%s:%s' %(auth[0], auth[1]))[0:-1])
|
headers["Authorization"] = b"Basic %s" % (
|
||||||
|
ubinascii.b2a_base64("%s:%s" % (auth[0], auth[1]))[0:-1]
|
||||||
|
)
|
||||||
|
|
||||||
resp_code = 0
|
resp_code = 0
|
||||||
resp_reason = None
|
resp_reason = None
|
||||||
@ -107,7 +116,7 @@ def request(method, url, data=None, json=None, files=None, headers={}, auth=None
|
|||||||
|
|
||||||
s.write(b"%s /%s HTTP/1.0\r\n" % (method, path))
|
s.write(b"%s /%s HTTP/1.0\r\n" % (method, path))
|
||||||
|
|
||||||
if not "Host" in headers:
|
if "Host" not in headers:
|
||||||
s.write(b"Host: %s\r\n" % host)
|
s.write(b"Host: %s\r\n" % host)
|
||||||
|
|
||||||
# Iterate over keys to avoid tuple alloc
|
# Iterate over keys to avoid tuple alloc
|
||||||
@ -119,19 +128,23 @@ def request(method, url, data=None, json=None, files=None, headers={}, auth=None
|
|||||||
|
|
||||||
if json is not None:
|
if json is not None:
|
||||||
import ujson
|
import ujson
|
||||||
|
|
||||||
data = ujson.dumps(json)
|
data = ujson.dumps(json)
|
||||||
s.write(b"Content-Type: application/json\r\n")
|
s.write(b"Content-Type: application/json\r\n")
|
||||||
|
|
||||||
if files is not None:
|
if files is not None:
|
||||||
data = bytearray()
|
data = bytearray()
|
||||||
boundary = b"37a4bcce91521f74142f1868e328a6b9"
|
boundary = b"37a4bcce91521f74142f1868e328a6b9"
|
||||||
s.write(b"Content-Type: multipart/form-data; boundary=%s\r\n"%(boundary))
|
s.write(b"Content-Type: multipart/form-data; boundary=%s\r\n" % (boundary))
|
||||||
for name, fileobj in files.items():
|
for name, fileobj in files.items():
|
||||||
data += b"--%s\r\n"%(boundary)
|
data += b"--%s\r\n" % (boundary)
|
||||||
data += b'Content-Disposition: form-data; name="%s"; filename="%s"\r\n\r\n' %(name, fileobj[0])
|
data += b'Content-Disposition: form-data; name="%s"; filename="%s"\r\n\r\n' % (
|
||||||
|
name,
|
||||||
|
fileobj[0],
|
||||||
|
)
|
||||||
data += fileobj[1].read()
|
data += fileobj[1].read()
|
||||||
data += b"\r\n"
|
data += b"\r\n"
|
||||||
data += b"\r\n--%s--\r\n"%(boundary)
|
data += b"\r\n--%s--\r\n" % (boundary)
|
||||||
|
|
||||||
if data:
|
if data:
|
||||||
s.write(b"Content-Length: %d\r\n\r\n" % len(data))
|
s.write(b"Content-Length: %d\r\n\r\n" % len(data))
|
||||||
@ -149,35 +162,40 @@ def request(method, url, data=None, json=None, files=None, headers={}, auth=None
|
|||||||
raise ValueError("Unsupported " + l)
|
raise ValueError("Unsupported " + l)
|
||||||
elif l.startswith(b"Location:") and not 200 <= status <= 299:
|
elif l.startswith(b"Location:") and not 200 <= status <= 299:
|
||||||
raise NotImplementedError("Redirects not yet supported")
|
raise NotImplementedError("Redirects not yet supported")
|
||||||
if 'HTTPS' in l or 'HTTP' in l:
|
if "HTTPS" in l or "HTTP" in l:
|
||||||
sline = l.split(None, 2)
|
sline = l.split(None, 2)
|
||||||
resp_code = int(sline[1])
|
resp_code = int(sline[1])
|
||||||
resp_reason = sline[2].decode().rstrip() if len(sline) > 2 else ""
|
resp_reason = sline[2].decode().rstrip() if len(sline) > 2 else ""
|
||||||
continue
|
continue
|
||||||
resp_headers.append(l)
|
resp_headers.append(l)
|
||||||
resp_headers = b'\r\n'.join(resp_headers)
|
resp_headers = b"\r\n".join(resp_headers)
|
||||||
content = b'\r\n'.join(response)
|
content = b"\r\n".join(response)
|
||||||
except OSError:
|
except OSError:
|
||||||
s.close()
|
s.close()
|
||||||
raise
|
raise
|
||||||
|
|
||||||
return Response(resp_code, resp_reason, resp_headers, content)
|
return Response(resp_code, resp_reason, resp_headers, content)
|
||||||
|
|
||||||
|
|
||||||
def head(url, **kw):
|
def head(url, **kw):
|
||||||
return request("HEAD", url, **kw)
|
return request("HEAD", url, **kw)
|
||||||
|
|
||||||
|
|
||||||
def get(url, **kw):
|
def get(url, **kw):
|
||||||
return request("GET", url, **kw)
|
return request("GET", url, **kw)
|
||||||
|
|
||||||
|
|
||||||
def post(url, **kw):
|
def post(url, **kw):
|
||||||
return request("POST", url, **kw)
|
return request("POST", url, **kw)
|
||||||
|
|
||||||
|
|
||||||
def put(url, **kw):
|
def put(url, **kw):
|
||||||
return request("PUT", url, **kw)
|
return request("PUT", url, **kw)
|
||||||
|
|
||||||
|
|
||||||
def patch(url, **kw):
|
def patch(url, **kw):
|
||||||
return request("PATCH", url, **kw)
|
return request("PATCH", url, **kw)
|
||||||
|
|
||||||
|
|
||||||
def delete(url, **kw):
|
def delete(url, **kw):
|
||||||
return request("DELETE", url, **kw)
|
return request("DELETE", url, **kw)
|
||||||
|
|
||||||
|
|||||||
@ -5,25 +5,26 @@ import socket
|
|||||||
import network
|
import network
|
||||||
import uos
|
import uos
|
||||||
import errno
|
import errno
|
||||||
from uio import IOBase
|
from uio import IOBase
|
||||||
|
|
||||||
last_client_socket = None
|
last_client_socket = None
|
||||||
server_socket = None
|
server_socket = None
|
||||||
|
|
||||||
|
|
||||||
# Provide necessary functions for dupterm and replace telnet control characters that come in.
|
# Provide necessary functions for dupterm and replace telnet control characters that come in.
|
||||||
class TelnetWrapper(IOBase):
|
class TelnetWrapper(IOBase):
|
||||||
def __init__(self, socket):
|
def __init__(self, socket):
|
||||||
self.socket = socket
|
self.socket = socket
|
||||||
self.discard_count = 0
|
self.discard_count = 0
|
||||||
|
|
||||||
def readinto(self, b):
|
def readinto(self, b):
|
||||||
readbytes = 0
|
readbytes = 0
|
||||||
for i in range(len(b)):
|
for i in range(len(b)):
|
||||||
try:
|
try:
|
||||||
byte = 0
|
byte = 0
|
||||||
# discard telnet control characters and
|
# discard telnet control characters and
|
||||||
# null bytes
|
# null bytes
|
||||||
while(byte == 0):
|
while byte == 0:
|
||||||
byte = self.socket.recv(1)[0]
|
byte = self.socket.recv(1)[0]
|
||||||
if byte == 0xFF:
|
if byte == 0xFF:
|
||||||
self.discard_count = 2
|
self.discard_count = 2
|
||||||
@ -31,9 +32,9 @@ class TelnetWrapper(IOBase):
|
|||||||
elif self.discard_count > 0:
|
elif self.discard_count > 0:
|
||||||
self.discard_count -= 1
|
self.discard_count -= 1
|
||||||
byte = 0
|
byte = 0
|
||||||
|
|
||||||
b[i] = byte
|
b[i] = byte
|
||||||
|
|
||||||
readbytes += 1
|
readbytes += 1
|
||||||
except (IndexError, OSError) as e:
|
except (IndexError, OSError) as e:
|
||||||
if type(e) == IndexError or len(e.args) > 0 and e.args[0] == errno.EAGAIN:
|
if type(e) == IndexError or len(e.args) > 0 and e.args[0] == errno.EAGAIN:
|
||||||
@ -44,7 +45,7 @@ class TelnetWrapper(IOBase):
|
|||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
return readbytes
|
return readbytes
|
||||||
|
|
||||||
def write(self, data):
|
def write(self, data):
|
||||||
# we need to write all the data but it's a non-blocking socket
|
# we need to write all the data but it's a non-blocking socket
|
||||||
# so loop until it's all written eating EAGAIN exceptions
|
# so loop until it's all written eating EAGAIN exceptions
|
||||||
@ -59,32 +60,34 @@ class TelnetWrapper(IOBase):
|
|||||||
else:
|
else:
|
||||||
# something else...propagate the exception
|
# something else...propagate the exception
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self.socket.close()
|
self.socket.close()
|
||||||
|
|
||||||
# Attach new clients to dupterm and
|
|
||||||
|
# Attach new clients to dupterm and
|
||||||
# send telnet control characters to disable line mode
|
# send telnet control characters to disable line mode
|
||||||
# and stop local echoing
|
# and stop local echoing
|
||||||
def accept_telnet_connect(telnet_server):
|
def accept_telnet_connect(telnet_server):
|
||||||
global last_client_socket
|
global last_client_socket
|
||||||
|
|
||||||
if last_client_socket:
|
if last_client_socket:
|
||||||
# close any previous clients
|
# close any previous clients
|
||||||
uos.dupterm(None)
|
uos.dupterm(None)
|
||||||
last_client_socket.close()
|
last_client_socket.close()
|
||||||
|
|
||||||
last_client_socket, remote_addr = telnet_server.accept()
|
last_client_socket, remote_addr = telnet_server.accept()
|
||||||
print("Telnet connection from:", remote_addr)
|
print("Telnet connection from:", remote_addr)
|
||||||
last_client_socket.setblocking(False)
|
last_client_socket.setblocking(False)
|
||||||
# dupterm_notify() not available under MicroPython v1.1
|
# dupterm_notify() not available under MicroPython v1.1
|
||||||
# last_client_socket.setsockopt(socket.SOL_SOCKET, 20, uos.dupterm_notify)
|
# last_client_socket.setsockopt(socket.SOL_SOCKET, 20, uos.dupterm_notify)
|
||||||
|
|
||||||
last_client_socket.sendall(bytes([255, 252, 34])) # dont allow line mode
|
last_client_socket.sendall(bytes([255, 252, 34])) # dont allow line mode
|
||||||
last_client_socket.sendall(bytes([255, 251, 1])) # turn off local echo
|
last_client_socket.sendall(bytes([255, 251, 1])) # turn off local echo
|
||||||
|
|
||||||
uos.dupterm(TelnetWrapper(last_client_socket))
|
uos.dupterm(TelnetWrapper(last_client_socket))
|
||||||
|
|
||||||
|
|
||||||
def stop():
|
def stop():
|
||||||
global server_socket, last_client_socket
|
global server_socket, last_client_socket
|
||||||
uos.dupterm(None)
|
uos.dupterm(None)
|
||||||
@ -93,20 +96,21 @@ def stop():
|
|||||||
if last_client_socket:
|
if last_client_socket:
|
||||||
last_client_socket.close()
|
last_client_socket.close()
|
||||||
|
|
||||||
|
|
||||||
# start listening for telnet connections on port 23
|
# start listening for telnet connections on port 23
|
||||||
def start(port=23):
|
def start(port=23):
|
||||||
stop()
|
stop()
|
||||||
global server_socket
|
global server_socket
|
||||||
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
|
||||||
ai = socket.getaddrinfo("0.0.0.0", port)
|
ai = socket.getaddrinfo("0.0.0.0", port)
|
||||||
addr = ai[0][4]
|
addr = ai[0][4]
|
||||||
|
|
||||||
server_socket.bind(addr)
|
server_socket.bind(addr)
|
||||||
server_socket.listen(1)
|
server_socket.listen(1)
|
||||||
server_socket.setsockopt(socket.SOL_SOCKET, 20, accept_telnet_connect)
|
server_socket.setsockopt(socket.SOL_SOCKET, 20, accept_telnet_connect)
|
||||||
|
|
||||||
for i in (network.AP_IF, network.STA_IF):
|
for i in (network.AP_IF, network.STA_IF):
|
||||||
wlan = network.WLAN(i)
|
wlan = network.WLAN(i)
|
||||||
if wlan.active():
|
if wlan.active():
|
||||||
|
|||||||
@ -1,109 +1,117 @@
|
|||||||
import pyb
|
import pyb
|
||||||
|
|
||||||
VL51L1X_DEFAULT_CONFIGURATION = bytes([
|
VL51L1X_DEFAULT_CONFIGURATION = bytes(
|
||||||
0x00, # 0x2d : set bit 2 and 5 to 1 for fast plus mode (1MHz I2C), else don't touch */
|
[
|
||||||
0x00, # 0x2e : bit 0 if I2C pulled up at 1.8V, else set bit 0 to 1 (pull up at AVDD) */
|
0x00, # 0x2d : set bit 2 and 5 to 1 for fast plus mode (1MHz I2C), else don't touch
|
||||||
0x00, # 0x2f : bit 0 if GPIO pulled up at 1.8V, else set bit 0 to 1 (pull up at AVDD) */
|
0x00, # 0x2e : bit 0 if I2C pulled up at 1.8V, else set bit 0 to 1 (pull up at AVDD)
|
||||||
0x01, # 0x30 : set bit 4 to 0 for active high interrupt and 1 for active low (bits 3:0 must be 0x1), use SetInterruptPolarity() */
|
0x00, # 0x2f : bit 0 if GPIO pulled up at 1.8V, else set bit 0 to 1 (pull up at AVDD)
|
||||||
0x02, # 0x31 : bit 1 = interrupt depending on the polarity, use CheckForDataReady() */
|
0x01, # 0x30 : set bit 4 to 0 for active high interrupt and 1 for active low
|
||||||
0x00, # 0x32 : not user-modifiable */
|
# (bits 3:0 must be 0x1), use SetInterruptPolarity()
|
||||||
0x02, # 0x33 : not user-modifiable */
|
0x02, # 0x31 : bit 1 = interrupt depending on the polarity, use CheckForDataReady()
|
||||||
0x08, # 0x34 : not user-modifiable */
|
0x00, # 0x32 : not user-modifiable
|
||||||
0x00, # 0x35 : not user-modifiable */
|
0x02, # 0x33 : not user-modifiable
|
||||||
0x08, # 0x36 : not user-modifiable */
|
0x08, # 0x34 : not user-modifiable
|
||||||
0x10, # 0x37 : not user-modifiable */
|
0x00, # 0x35 : not user-modifiable
|
||||||
0x01, # 0x38 : not user-modifiable */
|
0x08, # 0x36 : not user-modifiable
|
||||||
0x01, # 0x39 : not user-modifiable */
|
0x10, # 0x37 : not user-modifiable
|
||||||
0x00, # 0x3a : not user-modifiable */
|
0x01, # 0x38 : not user-modifiable
|
||||||
0x00, # 0x3b : not user-modifiable */
|
0x01, # 0x39 : not user-modifiable
|
||||||
0x00, # 0x3c : not user-modifiable */
|
0x00, # 0x3a : not user-modifiable
|
||||||
0x00, # 0x3d : not user-modifiable */
|
0x00, # 0x3b : not user-modifiable
|
||||||
0xff, # 0x3e : not user-modifiable */
|
0x00, # 0x3c : not user-modifiable
|
||||||
0x00, # 0x3f : not user-modifiable */
|
0x00, # 0x3d : not user-modifiable
|
||||||
0x0F, # 0x40 : not user-modifiable */
|
0xFF, # 0x3e : not user-modifiable
|
||||||
0x00, # 0x41 : not user-modifiable */
|
0x00, # 0x3f : not user-modifiable
|
||||||
0x00, # 0x42 : not user-modifiable */
|
0x0F, # 0x40 : not user-modifiable
|
||||||
0x00, # 0x43 : not user-modifiable */
|
0x00, # 0x41 : not user-modifiable
|
||||||
0x00, # 0x44 : not user-modifiable */
|
0x00, # 0x42 : not user-modifiable
|
||||||
0x00, # 0x45 : not user-modifiable */
|
0x00, # 0x43 : not user-modifiable
|
||||||
0x20, # 0x46 : interrupt configuration 0->level low detection, 1-> level high, 2-> Out of window, 3->In window, 0x20-> New sample ready , TBC */
|
0x00, # 0x44 : not user-modifiable
|
||||||
0x0b, # 0x47 : not user-modifiable */
|
0x00, # 0x45 : not user-modifiable
|
||||||
0x00, # 0x48 : not user-modifiable */
|
0x20, # 0x46 : interrupt configuration 0->level low detection,
|
||||||
0x00, # 0x49 : not user-modifiable */
|
# 1-> level high, 2-> Out of window, 3->In window, 0x20-> New sample ready , TBC
|
||||||
0x02, # 0x4a : not user-modifiable */
|
0x0B, # 0x47 : not user-modifiable
|
||||||
0x0a, # 0x4b : not user-modifiable */
|
0x00, # 0x48 : not user-modifiable
|
||||||
0x21, # 0x4c : not user-modifiable */
|
0x00, # 0x49 : not user-modifiable
|
||||||
0x00, # 0x4d : not user-modifiable */
|
0x02, # 0x4a : not user-modifiable
|
||||||
0x00, # 0x4e : not user-modifiable */
|
0x0A, # 0x4b : not user-modifiable
|
||||||
0x05, # 0x4f : not user-modifiable */
|
0x21, # 0x4c : not user-modifiable
|
||||||
0x00, # 0x50 : not user-modifiable */
|
0x00, # 0x4d : not user-modifiable
|
||||||
0x00, # 0x51 : not user-modifiable */
|
0x00, # 0x4e : not user-modifiable
|
||||||
0x00, # 0x52 : not user-modifiable */
|
0x05, # 0x4f : not user-modifiable
|
||||||
0x00, # 0x53 : not user-modifiable */
|
0x00, # 0x50 : not user-modifiable
|
||||||
0xc8, # 0x54 : not user-modifiable */
|
0x00, # 0x51 : not user-modifiable
|
||||||
0x00, # 0x55 : not user-modifiable */
|
0x00, # 0x52 : not user-modifiable
|
||||||
0x00, # 0x56 : not user-modifiable */
|
0x00, # 0x53 : not user-modifiable
|
||||||
0x38, # 0x57 : not user-modifiable */
|
0xC8, # 0x54 : not user-modifiable
|
||||||
0xff, # 0x58 : not user-modifiable */
|
0x00, # 0x55 : not user-modifiable
|
||||||
0x01, # 0x59 : not user-modifiable */
|
0x00, # 0x56 : not user-modifiable
|
||||||
0x00, # 0x5a : not user-modifiable */
|
0x38, # 0x57 : not user-modifiable
|
||||||
0x08, # 0x5b : not user-modifiable */
|
0xFF, # 0x58 : not user-modifiable
|
||||||
0x00, # 0x5c : not user-modifiable */
|
0x01, # 0x59 : not user-modifiable
|
||||||
0x00, # 0x5d : not user-modifiable */
|
0x00, # 0x5a : not user-modifiable
|
||||||
0x01, # 0x5e : not user-modifiable */
|
0x08, # 0x5b : not user-modifiable
|
||||||
0xdb, # 0x5f : not user-modifiable */
|
0x00, # 0x5c : not user-modifiable
|
||||||
0x0f, # 0x60 : not user-modifiable */
|
0x00, # 0x5d : not user-modifiable
|
||||||
0x01, # 0x61 : not user-modifiable */
|
0x01, # 0x5e : not user-modifiable
|
||||||
0xf1, # 0x62 : not user-modifiable */
|
0xDB, # 0x5f : not user-modifiable
|
||||||
0x0d, # 0x63 : not user-modifiable */
|
0x0F, # 0x60 : not user-modifiable
|
||||||
0x01, # 0x64 : Sigma threshold MSB (mm in 14.2 format for MSB+LSB), use SetSigmaThreshold(), default value 90 mm */
|
0x01, # 0x61 : not user-modifiable
|
||||||
0x68, # 0x65 : Sigma threshold LSB */
|
0xF1, # 0x62 : not user-modifiable
|
||||||
0x00, # 0x66 : Min count Rate MSB (MCPS in 9.7 format for MSB+LSB), use SetSignalThreshold() */
|
0x0D, # 0x63 : not user-modifiable
|
||||||
0x80, # 0x67 : Min count Rate LSB */
|
0x01, # 0x64 : Sigma threshold MSB (mm in 14.2 format for MSB+LSB),
|
||||||
0x08, # 0x68 : not user-modifiable */
|
# use SetSigmaThreshold(), default value 90 mm
|
||||||
0xb8, # 0x69 : not user-modifiable */
|
0x68, # 0x65 : Sigma threshold LSB
|
||||||
0x00, # 0x6a : not user-modifiable */
|
0x00, # 0x66 : Min count Rate MSB (MCPS in 9.7 format for MSB+LSB), use SetSignalThreshold()
|
||||||
0x00, # 0x6b : not user-modifiable */
|
0x80, # 0x67 : Min count Rate LSB
|
||||||
0x00, # 0x6c : Intermeasurement period MSB, 32 bits register, use SetIntermeasurementInMs() */
|
0x08, # 0x68 : not user-modifiable
|
||||||
0x00, # 0x6d : Intermeasurement period */
|
0xB8, # 0x69 : not user-modifiable
|
||||||
0x0f, # 0x6e : Intermeasurement period */
|
0x00, # 0x6a : not user-modifiable
|
||||||
0x89, # 0x6f : Intermeasurement period LSB */
|
0x00, # 0x6b : not user-modifiable
|
||||||
0x00, # 0x70 : not user-modifiable */
|
0x00, # 0x6c : Intermeasurement period MSB, 32 bits register, use SetIntermeasurementInMs()
|
||||||
0x00, # 0x71 : not user-modifiable */
|
0x00, # 0x6d : Intermeasurement period
|
||||||
0x00, # 0x72 : distance threshold high MSB (in mm, MSB+LSB), use SetD:tanceThreshold() */
|
0x0F, # 0x6e : Intermeasurement period
|
||||||
0x00, # 0x73 : distance threshold high LSB */
|
0x89, # 0x6f : Intermeasurement period LSB
|
||||||
0x00, # 0x74 : distance threshold low MSB ( in mm, MSB+LSB), use SetD:tanceThreshold() */
|
0x00, # 0x70 : not user-modifiable
|
||||||
0x00, # 0x75 : distance threshold low LSB */
|
0x00, # 0x71 : not user-modifiable
|
||||||
0x00, # 0x76 : not user-modifiable */
|
0x00, # 0x72 : distance threshold high MSB (in mm, MSB+LSB), use SetD:tanceThreshold()
|
||||||
0x01, # 0x77 : not user-modifiable */
|
0x00, # 0x73 : distance threshold high LSB
|
||||||
0x0f, # 0x78 : not user-modifiable */
|
0x00, # 0x74 : distance threshold low MSB ( in mm, MSB+LSB), use SetD:tanceThreshold()
|
||||||
0x0d, # 0x79 : not user-modifiable */
|
0x00, # 0x75 : distance threshold low LSB
|
||||||
0x0e, # 0x7a : not user-modifiable */
|
0x00, # 0x76 : not user-modifiable
|
||||||
0x0e, # 0x7b : not user-modifiable */
|
0x01, # 0x77 : not user-modifiable
|
||||||
0x00, # 0x7c : not user-modifiable */
|
0x0F, # 0x78 : not user-modifiable
|
||||||
0x00, # 0x7d : not user-modifiable */
|
0x0D, # 0x79 : not user-modifiable
|
||||||
0x02, # 0x7e : not user-modifiable */
|
0x0E, # 0x7a : not user-modifiable
|
||||||
0xc7, # 0x7f : ROI center, use SetROI() */
|
0x0E, # 0x7b : not user-modifiable
|
||||||
0xff, # 0x80 : XY ROI (X=Width, Y=Height), use SetROI() */
|
0x00, # 0x7c : not user-modifiable
|
||||||
0x9B, # 0x81 : not user-modifiable */
|
0x00, # 0x7d : not user-modifiable
|
||||||
0x00, # 0x82 : not user-modifiable */
|
0x02, # 0x7e : not user-modifiable
|
||||||
0x00, # 0x83 : not user-modifiable */
|
0xC7, # 0x7f : ROI center, use SetROI()
|
||||||
0x00, # 0x84 : not user-modifiable */
|
0xFF, # 0x80 : XY ROI (X=Width, Y=Height), use SetROI()
|
||||||
0x01, # 0x85 : not user-modifiable */
|
0x9B, # 0x81 : not user-modifiable
|
||||||
0x01, # 0x86 : clear interrupt, use ClearInterrupt() */
|
0x00, # 0x82 : not user-modifiable
|
||||||
0x40 # 0x87 : start ranging, use StartRanging() or StopRanging(), If you want an automatic start after VL53L1X_init() call, put 0x40 in location 0x87 */
|
0x00, # 0x83 : not user-modifiable
|
||||||
])
|
0x00, # 0x84 : not user-modifiable
|
||||||
|
0x01, # 0x85 : not user-modifiable
|
||||||
|
0x01, # 0x86 : clear interrupt, use ClearInterrupt()
|
||||||
|
0x40, # 0x87 : start ranging, use StartRanging() or StopRanging(), If you want
|
||||||
|
# an automatic start after VL53L1X_init() call, put 0x40 in location 0x87
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class VL53L1X:
|
class VL53L1X:
|
||||||
def __init__(self,i2c, address=0x29):
|
def __init__(self, i2c, address=0x29):
|
||||||
self.i2c = i2c
|
self.i2c = i2c
|
||||||
self.address = address
|
self.address = address
|
||||||
self.reset()
|
self.reset()
|
||||||
pyb.delay(1)
|
pyb.delay(1)
|
||||||
if self.read_model_id() != 0xEACC:
|
if self.read_model_id() != 0xEACC:
|
||||||
raise RuntimeError('Failed to find expected ID register values. Check wiring!')
|
raise RuntimeError("Failed to find expected ID register values. Check wiring!")
|
||||||
# write default configuration
|
# write default configuration
|
||||||
self.i2c.writeto_mem(self.address, 0x2D, VL51L1X_DEFAULT_CONFIGURATION, addrsize=16)
|
self.i2c.writeto_mem(self.address, 0x2D, VL51L1X_DEFAULT_CONFIGURATION, addrsize=16)
|
||||||
#pyb.delay(100)
|
# pyb.delay(100)
|
||||||
# the API triggers this change in VL53L1_init_and_start_range() once a
|
# the API triggers this change in VL53L1_init_and_start_range() once a
|
||||||
# measurement is started; assumes MM1 and MM2 are disabled
|
# measurement is started; assumes MM1 and MM2 are disabled
|
||||||
self.writeReg16Bit(0x001E, self.readReg16Bit(0x0022) * 4)
|
self.writeReg16Bit(0x001E, self.readReg16Bit(0x0022) * 4)
|
||||||
@ -111,53 +119,61 @@ class VL53L1X:
|
|||||||
|
|
||||||
def writeReg(self, reg, value):
|
def writeReg(self, reg, value):
|
||||||
return self.i2c.writeto_mem(self.address, reg, bytes([value]), addrsize=16)
|
return self.i2c.writeto_mem(self.address, reg, bytes([value]), addrsize=16)
|
||||||
|
|
||||||
def writeReg16Bit(self, reg, value):
|
def writeReg16Bit(self, reg, value):
|
||||||
return self.i2c.writeto_mem(self.address, reg, bytes([(value >> 8) & 0xFF, value & 0xFF]), addrsize=16)
|
return self.i2c.writeto_mem(
|
||||||
|
self.address, reg, bytes([(value >> 8) & 0xFF, value & 0xFF]), addrsize=16
|
||||||
|
)
|
||||||
|
|
||||||
def readReg(self, reg):
|
def readReg(self, reg):
|
||||||
return self.i2c.readfrom_mem(self.address, reg, 1, addrsize=16)[0]
|
return self.i2c.readfrom_mem(self.address, reg, 1, addrsize=16)[0]
|
||||||
|
|
||||||
def readReg16Bit(self, reg):
|
def readReg16Bit(self, reg):
|
||||||
data = self.i2c.readfrom_mem(self.address, reg, 2, addrsize=16)
|
data = self.i2c.readfrom_mem(self.address, reg, 2, addrsize=16)
|
||||||
return (data[0]<<8) + data[1]
|
return (data[0] << 8) + data[1]
|
||||||
|
|
||||||
def read_model_id(self):
|
def read_model_id(self):
|
||||||
return self.readReg16Bit(0x010F)
|
return self.readReg16Bit(0x010F)
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
self.writeReg(0x0000, 0x00)
|
self.writeReg(0x0000, 0x00)
|
||||||
pyb.delay(100)
|
pyb.delay(100)
|
||||||
self.writeReg(0x0000, 0x01)
|
self.writeReg(0x0000, 0x01)
|
||||||
|
|
||||||
def read(self):
|
def read(self):
|
||||||
data = self.i2c.readfrom_mem(self.address, 0x0089, 17, addrsize=16) # RESULT__RANGE_STATUS
|
data = self.i2c.readfrom_mem(self.address, 0x0089, 17, addrsize=16) # RESULT__RANGE_STATUS
|
||||||
range_status = data[0]
|
# range_status = data[0]
|
||||||
# report_status = data[1]
|
# report_status = data[1]
|
||||||
stream_count = data[2]
|
# stream_count = data[2]
|
||||||
dss_actual_effective_spads_sd0 = (data[3]<<8) + data[4]
|
# dss_actual_effective_spads_sd0 = (data[3] << 8) + data[4]
|
||||||
# peak_signal_count_rate_mcps_sd0 = (data[5]<<8) + data[6]
|
# peak_signal_count_rate_mcps_sd0 = (data[5]<<8) + data[6]
|
||||||
ambient_count_rate_mcps_sd0 = (data[7]<<8) + data[8]
|
# ambient_count_rate_mcps_sd0 = (data[7] << 8) + data[8]
|
||||||
# sigma_sd0 = (data[9]<<8) + data[10]
|
# sigma_sd0 = (data[9]<<8) + data[10]
|
||||||
# phase_sd0 = (data[11]<<8) + data[12]
|
# phase_sd0 = (data[11]<<8) + data[12]
|
||||||
final_crosstalk_corrected_range_mm_sd0 = (data[13]<<8) + data[14]
|
final_crosstalk_corrected_range_mm_sd0 = (data[13] << 8) + data[14]
|
||||||
peak_signal_count_rate_crosstalk_corrected_mcps_sd0 = (data[15]<<8) + data[16]
|
# peak_signal_count_rate_crosstalk_corrected_mcps_sd0 = (data[15] << 8) + data[16]
|
||||||
#status = None
|
# status = None
|
||||||
#if range_status in (17, 2, 1, 3):
|
# if range_status in (17, 2, 1, 3):
|
||||||
#status = "HardwareFail"
|
# status = "HardwareFail"
|
||||||
#elif range_status == 13:
|
# elif range_status == 13:
|
||||||
#status = "MinRangeFail"
|
# status = "MinRangeFail"
|
||||||
#elif range_status == 18:
|
# elif range_status == 18:
|
||||||
#status = "SynchronizationInt"
|
# status = "SynchronizationInt"
|
||||||
#elif range_status == 5:
|
# elif range_status == 5:
|
||||||
#status = "OutOfBoundsFail"
|
# status = "OutOfBoundsFail"
|
||||||
#elif range_status == 4:
|
# elif range_status == 4:
|
||||||
#status = "SignalFail"
|
# status = "SignalFail"
|
||||||
#elif range_status == 6:
|
# elif range_status == 6:
|
||||||
#status = "SignalFail"
|
# status = "SignalFail"
|
||||||
#elif range_status == 7:
|
# elif range_status == 7:
|
||||||
#status = "WrapTargetFail"
|
# status = "WrapTargetFail"
|
||||||
#elif range_status == 12:
|
# elif range_status == 12:
|
||||||
#status = "XtalkSignalFail"
|
# status = "XtalkSignalFail"
|
||||||
#elif range_status == 8:
|
# elif range_status == 8:
|
||||||
#status = "RangeValidMinRangeClipped"
|
# status = "RangeValidMinRangeClipped"
|
||||||
#elif range_status == 9:
|
# elif range_status == 9:
|
||||||
#if stream_count == 0:
|
# if stream_count == 0:
|
||||||
#status = "RangeValidNoWrapCheckFail"
|
# status = "RangeValidNoWrapCheckFail"
|
||||||
#else:
|
# else:
|
||||||
#status = "OK"
|
# status = "OK"
|
||||||
return final_crosstalk_corrected_range_mm_sd0
|
return final_crosstalk_corrected_range_mm_sd0
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user