Merge pull request #1785 from openmv/pylint

misc: Add Python linter workflow.
This commit is contained in:
Ibrahim Abdelkader 2023-02-19 22:17:34 +02:00 committed by GitHub
commit a9e5c41a71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 1416 additions and 943 deletions

51
.github/workflows/python-linter.yml vendored Normal file
View 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/

View 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")

View File

@ -1,3 +1,6 @@
from apds9960.device import APDS9960, uAPDS9960
__all__ = [ 'APDS9960', 'uAPDS9960', ]
__all__ = [
"APDS9960",
"uAPDS9960",
]

View File

@ -7,7 +7,7 @@ APDS9960_GESTURE_SENSITIVITY_1 = 50
APDS9960_GESTURE_SENSITIVITY_2 = 20
# APDS9960 device IDs
APDS9960_DEV_ID = [0xab, 0x9c, 0xa8, -0x55]
APDS9960_DEV_ID = [0xAB, 0x9C, 0xA8, -0x55]
# APDS9960 times
APDS9960_TIME_FIFO_PAUSE = 30
@ -21,11 +21,11 @@ APDS9960_REG_AILTH = 0x85
APDS9960_REG_AIHTL = 0x86
APDS9960_REG_AIHTH = 0x87
APDS9960_REG_PILT = 0x89
APDS9960_REG_PIHT = 0x8b
APDS9960_REG_PERS = 0x8c
APDS9960_REG_CONFIG1 = 0x8d
APDS9960_REG_PPULSE = 0x8e
APDS9960_REG_CONTROL = 0x8f
APDS9960_REG_PIHT = 0x8B
APDS9960_REG_PERS = 0x8C
APDS9960_REG_CONFIG1 = 0x8D
APDS9960_REG_PPULSE = 0x8E
APDS9960_REG_CONTROL = 0x8F
APDS9960_REG_CONFIG2 = 0x90
APDS9960_REG_ID = 0x92
APDS9960_REG_STATUS = 0x93
@ -35,40 +35,40 @@ APDS9960_REG_RDATAL = 0x96
APDS9960_REG_RDATAH = 0x97
APDS9960_REG_GDATAL = 0x98
APDS9960_REG_GDATAH = 0x99
APDS9960_REG_BDATAL = 0x9a
APDS9960_REG_BDATAH = 0x9b
APDS9960_REG_PDATA = 0x9c
APDS9960_REG_POFFSET_UR = 0x9d
APDS9960_REG_POFFSET_DL = 0x9e
APDS9960_REG_CONFIG3 = 0x9f
APDS9960_REG_GPENTH = 0xa0
APDS9960_REG_GEXTH = 0xa1
APDS9960_REG_GCONF1 = 0xa2
APDS9960_REG_GCONF2 = 0xa3
APDS9960_REG_GOFFSET_U = 0xa4
APDS9960_REG_GOFFSET_D = 0xa5
APDS9960_REG_GOFFSET_L = 0xa7
APDS9960_REG_GOFFSET_R = 0xa9
APDS9960_REG_GPULSE = 0xa6
APDS9960_REG_GCONF3 = 0xaA
APDS9960_REG_GCONF4 = 0xaB
APDS9960_REG_GFLVL = 0xae
APDS9960_REG_GSTATUS = 0xaf
APDS9960_REG_IFORCE = 0xe4
APDS9960_REG_PICLEAR = 0xe5
APDS9960_REG_CICLEAR = 0xe6
APDS9960_REG_AICLEAR = 0xe7
APDS9960_REG_GFIFO_U = 0xfc
APDS9960_REG_GFIFO_D = 0xfd
APDS9960_REG_GFIFO_L = 0xfe
APDS9960_REG_GFIFO_R = 0xff
APDS9960_REG_BDATAL = 0x9A
APDS9960_REG_BDATAH = 0x9B
APDS9960_REG_PDATA = 0x9C
APDS9960_REG_POFFSET_UR = 0x9D
APDS9960_REG_POFFSET_DL = 0x9E
APDS9960_REG_CONFIG3 = 0x9F
APDS9960_REG_GPENTH = 0xA0
APDS9960_REG_GEXTH = 0xA1
APDS9960_REG_GCONF1 = 0xA2
APDS9960_REG_GCONF2 = 0xA3
APDS9960_REG_GOFFSET_U = 0xA4
APDS9960_REG_GOFFSET_D = 0xA5
APDS9960_REG_GOFFSET_L = 0xA7
APDS9960_REG_GOFFSET_R = 0xA9
APDS9960_REG_GPULSE = 0xA6
APDS9960_REG_GCONF3 = 0xAA
APDS9960_REG_GCONF4 = 0xAB
APDS9960_REG_GFLVL = 0xAE
APDS9960_REG_GSTATUS = 0xAF
APDS9960_REG_IFORCE = 0xE4
APDS9960_REG_PICLEAR = 0xE5
APDS9960_REG_CICLEAR = 0xE6
APDS9960_REG_AICLEAR = 0xE7
APDS9960_REG_GFIFO_U = 0xFC
APDS9960_REG_GFIFO_D = 0xFD
APDS9960_REG_GFIFO_L = 0xFE
APDS9960_REG_GFIFO_R = 0xFF
# APDS9960 bit fields
APDS9960_BIT_PON = 0b00000001
APDS9960_BIT_AEN = 0b00000010
APDS9960_BIT_PEN = 0b00000100
APDS9960_BIT_WEN = 0b00001000
APSD9960_BIT_AIEN =0b00010000
APSD9960_BIT_AIEN = 0b00010000
APDS9960_BIT_PIEN = 0b00100000
APDS9960_BIT_GEN = 0b01000000
APDS9960_BIT_GVALID = 0b00000001
@ -124,33 +124,33 @@ APDS9960_GWTIME_30_8MS = 6
APDS9960_GWTIME_39_2MS = 7
# Default values
APDS9960_DEFAULT_ATIME = 219 # 103ms
APDS9960_DEFAULT_WTIME = 246 # 27ms
APDS9960_DEFAULT_PROX_PPULSE = 0x87 # 16us, 8 pulses
APDS9960_DEFAULT_GESTURE_PPULSE = 0x89 # 16us, 10 pulses
APDS9960_DEFAULT_POFFSET_UR = 0 # 0 offset
APDS9960_DEFAULT_POFFSET_DL = 0 # 0 offset
APDS9960_DEFAULT_CONFIG1 = 0x60 # No 12x wait (WTIME) factor
APDS9960_DEFAULT_ATIME = 219 # 103ms
APDS9960_DEFAULT_WTIME = 246 # 27ms
APDS9960_DEFAULT_PROX_PPULSE = 0x87 # 16us, 8 pulses
APDS9960_DEFAULT_GESTURE_PPULSE = 0x89 # 16us, 10 pulses
APDS9960_DEFAULT_POFFSET_UR = 0 # 0 offset
APDS9960_DEFAULT_POFFSET_DL = 0 # 0 offset
APDS9960_DEFAULT_CONFIG1 = 0x60 # No 12x wait (WTIME) factor
APDS9960_DEFAULT_LDRIVE = APDS9960_LED_DRIVE_100MA
APDS9960_DEFAULT_PGAIN = APDS9960_PGAIN_4X
APDS9960_DEFAULT_AGAIN = APDS9960_AGAIN_4X
APDS9960_DEFAULT_PILT = 0 # Low proximity threshold
APDS9960_DEFAULT_PIHT = 50 # High proximity threshold
APDS9960_DEFAULT_AILT = 0xffff # Force interrupt for calibration
APDS9960_DEFAULT_PILT = 0 # Low proximity threshold
APDS9960_DEFAULT_PIHT = 50 # High proximity threshold
APDS9960_DEFAULT_AILT = 0xFFFF # Force interrupt for calibration
APDS9960_DEFAULT_AIHT = 0
APDS9960_DEFAULT_PERS = 0x11 # 2 consecutive prox or ALS for int.
APDS9960_DEFAULT_CONFIG2 = 0x01 # No saturation interrupts or LED boost
APDS9960_DEFAULT_CONFIG3 = 0 # Enable all photodiodes, no SAI
APDS9960_DEFAULT_GPENTH = 40 # Threshold for entering 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_PERS = 0x11 # 2 consecutive prox or ALS for int.
APDS9960_DEFAULT_CONFIG2 = 0x01 # No saturation interrupts or LED boost
APDS9960_DEFAULT_CONFIG3 = 0 # Enable all photodiodes, no SAI
APDS9960_DEFAULT_GPENTH = 40 # Threshold for entering 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_GGAIN = APDS9960_GGAIN_4X
APDS9960_DEFAULT_GLDRIVE = APDS9960_LED_DRIVE_100MA
APDS9960_DEFAULT_GWTIME = APDS9960_GWTIME_2_8MS
APDS9960_DEFAULT_GOFFSET = 0 # No offset scaling for gesture mode
APDS9960_DEFAULT_GPULSE = 0xc9 # 32us, 10 pulses
APDS9960_DEFAULT_GCONF3 = 0 # All photodiodes active during gesture
APDS9960_DEFAULT_GIEN = 0 # Disable gesture interrupts
APDS9960_DEFAULT_GOFFSET = 0 # No offset scaling for gesture mode
APDS9960_DEFAULT_GPULSE = 0xC9 # 32us, 10 pulses
APDS9960_DEFAULT_GCONF3 = 0 # All photodiodes active during gesture
APDS9960_DEFAULT_GIEN = 0 # Disable gesture interrupts
# gesture directions
APDS9960_DIR_NONE = 0

View File

@ -3,6 +3,7 @@ from apds9960.exceptions import *
from time import sleep_ms
class APDS9960:
class GestureData:
def __init__(self):
@ -78,7 +79,6 @@ class APDS9960:
self._write_byte_data(APDS9960_REG_GCONF3, APDS9960_DEFAULT_GCONF3)
self.setGestureIntEnable(APDS9960_DEFAULT_GIEN)
def getMode(self):
return self._read_byte_data(APDS9960_REG_ENABLE)
@ -92,19 +92,18 @@ class APDS9960:
# change bit(s) in ENABLE register */
if mode == APDS9960_MODE_ALL:
if enable:
reg_val = 0x7f
reg_val = 0x7F
else:
reg_val = 0x00
else:
if enable:
reg_val |= (1 << mode);
reg_val |= 1 << mode
else:
reg_val &= ~(1 << mode);
reg_val &= ~(1 << mode)
# write value to ENABLE register
self._write_byte_data(APDS9960_REG_ENABLE, reg_val)
# start the light (R/G/B/Ambient) sensor
def enableLightSensor(self, interrupts=True):
self.setAmbientLightGain(APDS9960_DEFAULT_AGAIN)
@ -117,7 +116,6 @@ class APDS9960:
self.setAmbientLightIntEnable(False)
self.setMode(APDS9960_MODE_AMBIENT_LIGHT, False)
# start the proximity sensor
def enableProximitySensor(self, interrupts=True):
self.setProximityGain(APDS9960_DEFAULT_PGAIN)
@ -131,11 +129,10 @@ class APDS9960:
self.setProximityIntEnable(False)
self.setMode(APDS9960_MODE_PROXIMITY, False)
# start the gesture recognition engine
def enableGestureSensor(self, interrupts=True):
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.setLEDBoost(APDS9960_LED_BOOST_300)
self.setGestureIntEnable(interrupts)
@ -152,16 +149,14 @@ class APDS9960:
self.setGestureMode(False)
self.setMode(APDS9960_MODE_GESTURE, False)
# check if there is a gesture available
def isGestureAvailable(self):
val = self._read_byte_data(APDS9960_REG_GSTATUS)
# shift and mask out GVALID bit
val &= APDS9960_BIT_GVALID;
return (val == APDS9960_BIT_GVALID)
val &= APDS9960_BIT_GVALID
return val == APDS9960_BIT_GVALID
# processes a gesture event and returns best guessed gesture
def readGesture(self):
@ -174,7 +169,7 @@ class APDS9960:
return APDS9960_DIR_NONE
# keep looping as long as gesture data is valid
while(self.isGestureAvailable()):
while self.isGestureAvailable():
# read the current FIFO level
fifo_level = self._read_byte_data(APDS9960_REG_GFLVL)
@ -197,7 +192,7 @@ class APDS9960:
# filter and process gesture data, decode near/far state
if self.processGestureData():
if self.decodeGesture():
#***TODO: U-Turn Gestures
# ***TODO: U-Turn Gestures
pass
# reset data
@ -215,18 +210,14 @@ class APDS9960:
self.resetGestureParameters()
return motion
# turn the APDS-9960 on
def enablePower(self):
self.setMode(APDS9960_MODE_POWER, True)
def disablePower(self):
# turn the APDS-9960 off
self.setMode(APDS9960_MODE_POWER, False)
# *******************************************************************************
# ambient light and color sensor controls
# *******************************************************************************
@ -271,7 +262,6 @@ class APDS9960:
return l + (h << 8)
# *******************************************************************************
# Proximity sensor controls
# *******************************************************************************
@ -280,7 +270,6 @@ class APDS9960:
def readProximity(self):
return self._read_byte_data(APDS9960_REG_PDATA)
# *******************************************************************************
# High-level gesture controls
# *******************************************************************************
@ -302,12 +291,11 @@ class APDS9960:
self.gesture_state_ = 0
self.gesture_motion_ = APDS9960_DIR_NONE
def processGestureData(self):
"""Processes the raw gesture data to determine swipe direction
Returns:
bool: True if near or far state seen, False otherwise.
Returns:
bool: True if near or far state seen, False otherwise.
"""
u_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:
# find the first value in U/D/L/R above the threshold
for i in range(0, self.gesture_data_.total_gestures):
if self.gesture_data_.u_data[i] > APDS9960_GESTURE_THRESHOLD_OUT and \
self.gesture_data_.d_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:
if (
self.gesture_data_.u_data[i] > APDS9960_GESTURE_THRESHOLD_OUT
and self.gesture_data_.d_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]
d_first = self.gesture_data_.d_data[i]
l_first = self.gesture_data_.l_data[i]
@ -338,16 +327,17 @@ class APDS9960:
break
# 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
# find the last value in U/D/L/R above the threshold
for i in reversed(range(0, self.gesture_data_.total_gestures)):
if self.gesture_data_.u_data[i] > APDS9960_GESTURE_THRESHOLD_OUT and \
self.gesture_data_.d_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:
if (
self.gesture_data_.u_data[i] > APDS9960_GESTURE_THRESHOLD_OUT
and self.gesture_data_.d_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]
d_last = self.gesture_data_.d_data[i]
l_last = self.gesture_data_.l_data[i]
@ -386,9 +376,10 @@ class APDS9960:
# determine Near/Far gesture
if self.gesture_ud_count_ == 0 and self.gesture_lr_count_ == 0:
if abs(ud_delta) < APDS9960_GESTURE_SENSITIVITY_2 and \
abs(lr_delta) < APDS9960_GESTURE_SENSITIVITY_2:
if (
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
elif ud_delta != 0 or lr_delta != 0:
@ -401,23 +392,23 @@ class APDS9960:
self.gesture_state_ = APDS9960_STATE_FAR
return True
else:
if abs(ud_delta) < APDS9960_GESTURE_SENSITIVITY_2 and \
abs(lr_delta) < APDS9960_GESTURE_SENSITIVITY_2:
if (
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:
self.gesture_near_count_ += 1
if self.gesture_near_count_ >= 10:
self.gesture_ud_count_ = 0
self.gesture_lr_count_ = 0
self.gesture_ud_delta_ = 0
self.gesture_lr_delta_ = 0
if self.gesture_near_count_ >= 10:
self.gesture_ud_count_ = 0
self.gesture_lr_count_ = 0
self.gesture_ud_delta_ = 0
self.gesture_lr_delta_ = 0
return False
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
if self.gesture_state_ == APDS9960_STATE_NEAR:
@ -462,44 +453,37 @@ class APDS9960:
return True
# *******************************************************************************
# Getters and setters for register values
# *******************************************************************************
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)
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)
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)
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)
def getLEDDrive(self):
"""Returns LED drive strength for proximity and ALS.
Value LED Current
0 100 mA
1 50 mA
2 25 mA
3 12.5 mA
Value LED Current
0 100 mA
1 50 mA
2 25 mA
3 12.5 mA
Returns:
int: the value of the LED drive strength
Returns:
int: the value of the LED drive strength
"""
val = self._read_byte_data(APDS9960_REG_CONTROL)
@ -509,14 +493,14 @@ class APDS9960:
def setLEDDrive(self, drive):
"""Sets LED drive strength for proximity and ALS.
Value LED Current
0 100 mA
1 50 mA
2 25 mA
3 12.5 mA
Value LED Current
0 100 mA
1 50 mA
2 25 mA
3 12.5 mA
Args:
drive (int): value for the LED drive strength
Args:
drive (int): value for the LED drive strength
"""
val = self._read_byte_data(APDS9960_REG_CONTROL)
@ -528,18 +512,17 @@ class APDS9960:
self._write_byte_data(APDS9960_REG_CONTROL, val)
def getProximityGain(self):
"""Returns receiver gain for proximity detection.
Value Gain
0 1x
1 2x
2 4x
3 8x
Value Gain
0 1x
1 2x
2 4x
3 8x
Returns:
int: the value of the proximity gain
Returns:
int: the value of the proximity gain
"""
val = self._read_byte_data(APDS9960_REG_CONTROL)
@ -549,14 +532,14 @@ class APDS9960:
def setProximityGain(self, drive):
"""Returns receiver gain for proximity detection.
Value Gain
0 1x
1 2x
2 4x
3 8x
Value Gain
0 1x
1 2x
2 4x
3 8x
Args:
drive (int): value for the proximity gain
Args:
drive (int): value for the proximity gain
"""
val = self._read_byte_data(APDS9960_REG_CONTROL)
@ -568,35 +551,34 @@ class APDS9960:
self._write_byte_data(APDS9960_REG_CONTROL, val)
def getAmbientLightGain(self):
"""Returns receiver gain for the ambient light sensor (ALS).
Value Gain
0 1x
1 4x
2 16x
3 64x
Value Gain
0 1x
1 4x
2 16x
3 64x
Returns:
int: the value of the ALS gain
Returns:
int: the value of the ALS gain
"""
val = self._read_byte_data(APDS9960_REG_CONTROL)
# shift and mask out ADRIVE bits
return (val & 0b00000011)
return val & 0b00000011
def setAmbientLightGain(self, drive):
"""Sets the receiver gain for the ambient light sensor (ALS).
Value Gain
0 1x
1 4x
2 16x
3 64x
Value Gain
0 1x
1 4x
2 16x
3 64x
Args:
drive (int): value for the ALS gain
Args:
drive (int): value for the ALS gain
"""
val = self._read_byte_data(APDS9960_REG_CONTROL)
@ -607,18 +589,17 @@ class APDS9960:
self._write_byte_data(APDS9960_REG_CONTROL, val)
def getLEDBoost(self):
"""Get the current LED boost value.
Value Gain
0 100%
1 150%
2 200%
3 300%
Value Gain
0 100%
1 150%
2 200%
3 300%
Returns:
int: the LED boost value
Returns:
int: the LED boost value
"""
val = self._read_byte_data(APDS9960_REG_CONFIG2)
@ -628,14 +609,14 @@ class APDS9960:
def setLEDBoost(self, boost):
"""Sets the LED current boost value.
Value Gain
0 100%
1 150%
2 200%
3 300%
Value Gain
0 100%
1 150%
2 200%
3 300%
Args:
boost (int): value for the LED boost
Args:
boost (int): value for the LED boost
"""
val = self._read_byte_data(APDS9960_REG_CONFIG2)
@ -647,12 +628,11 @@ class APDS9960:
self._write_byte_data(APDS9960_REG_CONFIG2, val)
def getProxGainCompEnable(self):
"""Gets proximity gain compensation enable.
Returns:
bool: True if compensation is enabled, False if not
Returns:
bool: True if compensation is enabled, False if not
"""
val = self._read_byte_data(APDS9960_REG_CONFIG3)
@ -663,8 +643,8 @@ class APDS9960:
def setProxGainCompEnable(self, enable):
"""Sets the proximity gain compensation enable.
Args:
enable (bool): True to enable compensation, False to disable
Args:
enable (bool): True to enable compensation, False to disable
"""
val = self._read_byte_data(APDS9960_REG_CONFIG3)
@ -675,20 +655,19 @@ class APDS9960:
self._write_byte_data(APDS9960_REG_CONFIG3, val)
def getProxPhotoMask(self):
"""Gets the current mask for enabled/disabled proximity photodiodes.
Bit Photodiode
3 UP
2 DOWN
1 LEFT
0 RIGHT
Bit Photodiode
3 UP
2 DOWN
1 LEFT
0 RIGHT
1 = disabled, 0 = enabled
1 = disabled, 0 = enabled
Returns:
int: Current proximity mask for photodiodes.
Returns:
int: Current proximity mask for photodiodes.
"""
val = self._read_byte_data(APDS9960_REG_CONFIG3)
@ -698,16 +677,16 @@ class APDS9960:
def setProxPhotoMask(self, mask):
"""Sets the mask for enabling/disabling proximity photodiodes.
Bit Photodiode
3 UP
2 DOWN
1 LEFT
0 RIGHT
Bit Photodiode
3 UP
2 DOWN
1 LEFT
0 RIGHT
1 = disabled, 0 = enabled
1 = disabled, 0 = enabled
Args:
mask (int): 4-bit mask value
Args:
mask (int): 4-bit mask value
"""
val = self._read_byte_data(APDS9960_REG_CONFIG3)
@ -718,52 +697,49 @@ class APDS9960:
self._write_byte_data(APDS9960_REG_CONFIG3, val)
def getGestureEnterThresh(self):
"""Gets the entry proximity threshold for gesture sensing.
Returns:
int: current entry proximity threshold
Returns:
int: current entry proximity threshold
"""
return self._read_byte_data(APDS9960_REG_GPENTH)
def setGestureEnterThresh(self, threshold):
"""Sets the entry proximity threshold for gesture sensing.
Args:
threshold (int): threshold proximity value needed to start gesture mode
Args:
threshold (int): threshold proximity value needed to start gesture mode
"""
self._write_byte_data(APDS9960_REG_GPENTH, threshold)
def getGestureExitThresh(self):
"""Gets the exit proximity threshold for gesture sensing.
Returns:
int: current exit proximity threshold
Returns:
int: current exit proximity threshold
"""
return self._read_byte_data(APDS9960_REG_GEXTH)
def setGestureExitThresh(self, threshold):
"""Sets the exit proximity threshold for gesture sensing.
Args:
threshold (int): threshold proximity value needed to end gesture mode
Args:
threshold (int): threshold proximity value needed to end gesture mode
"""
self._write_byte_data(APDS9960_REG_GEXTH, threshold)
def getGestureGain(self):
"""Gets the gain of the photodiode during gesture mode.
Value Gain
0 1x
1 2x
2 4x
3 8x
Value Gain
0 1x
1 2x
2 4x
3 8x
Returns:
int: the current photodiode gain
Returns:
int: the current photodiode gain
"""
val = self._read_byte_data(APDS9960_REG_GCONF2)
@ -773,14 +749,14 @@ class APDS9960:
def setGestureGain(self, gain):
"""Sets the gain of the photodiode during gesture mode.
Value Gain
0 1x
1 2x
2 4x
3 8x
Value Gain
0 1x
1 2x
2 4x
3 8x
Args:
gain (int): the value for the photodiode gain
Args:
gain (int): the value for the photodiode gain
"""
val = self._read_byte_data(APDS9960_REG_GCONF2)
@ -792,18 +768,17 @@ class APDS9960:
self._write_byte_data(APDS9960_REG_GCONF2, val)
def getGestureLEDDrive(self):
"""Gets the drive current of the LED during gesture mode.
Value LED Current
0 100 mA
1 50 mA
2 25 mA
3 12.5 mA
Value LED Current
0 100 mA
1 50 mA
2 25 mA
3 12.5 mA
Returns:
int: the LED drive current value
Returns:
int: the LED drive current value
"""
val = self._read_byte_data(APDS9960_REG_GCONF2)
@ -813,41 +788,40 @@ class APDS9960:
def setGestureLEDDrive(self, drive):
"""Sets LED drive strength for proximity and ALS.
Value LED Current
0 100 mA
1 50 mA
2 25 mA
3 12.5 mA
Value LED Current
0 100 mA
1 50 mA
2 25 mA
3 12.5 mA
Args:
drive (int): value for the LED drive current
Args:
drive (int): value for the LED drive current
"""
val = self._read_byte_data(APDS9960_REG_GCONF2)
# set bits in register to given value
drive &= 0b00000011;
drive = drive << 3;
val &= 0b11100111;
val |= drive;
drive &= 0b00000011
drive = drive << 3
val &= 0b11100111
val |= drive
self._write_byte_data(APDS9960_REG_GCONF2, val)
def getGestureWaitTime(self):
"""Gets the time in low power mode between gesture detections.
Value Wait time
0 0 ms
1 2.8 ms
2 5.6 ms
3 8.4 ms
4 14.0 ms
5 22.4 ms
6 30.8 ms
7 39.2 ms
Value Wait time
0 0 ms
1 2.8 ms
2 5.6 ms
3 8.4 ms
4 14.0 ms
5 22.4 ms
6 30.8 ms
7 39.2 ms
Returns:
int: the current wait time between gestures
Returns:
int: the current wait time between gestures
"""
val = self._read_byte_data(APDS9960_REG_GCONF2)
@ -857,18 +831,18 @@ class APDS9960:
def setGestureWaitTime(self, time):
"""Sets the time in low power mode between gesture detections.
Value Wait time
0 0 ms
1 2.8 ms
2 5.6 ms
3 8.4 ms
4 14.0 ms
5 22.4 ms
6 30.8 ms
7 39.2 ms
Value Wait time
0 0 ms
1 2.8 ms
2 5.6 ms
3 8.4 ms
4 14.0 ms
5 22.4 ms
6 30.8 ms
7 39.2 ms
Args:
time (int): value for the wait time
Args:
time (int): value for the wait time
"""
val = self._read_byte_data(APDS9960_REG_GCONF2)
@ -879,84 +853,83 @@ class APDS9960:
self._write_byte_data(APDS9960_REG_GCONF2, val)
def getLightIntLowThreshold(self):
"""Gets the low threshold for ambient light interrupts.
Returns:
int: threshold current low threshold stored on the APDS9960
Returns:
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):
"""Sets the low threshold for ambient light interrupts.
Args:
threshold (int): low threshold value for interrupt to trigger
Args:
threshold (int): low threshold value for interrupt to trigger
"""
# break 16-bit threshold into 2 8-bit values
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_AILTL, threshold & 0x00FF)
self._write_byte_data(APDS9960_REG_AILTH, (threshold & 0xFF00) >> 8)
def getLightIntHighThreshold(self):
"""Gets the high threshold for ambient light interrupts.
Returns:
int: threshold current low threshold stored on the APDS9960
Returns:
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):
"""Sets the high threshold for ambient light interrupts.
Args:
threshold (int): high threshold value for interrupt to trigger
Args:
threshold (int): high threshold value for interrupt to trigger
"""
# break 16-bit threshold into 2 8-bit values
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_AIHTL, threshold & 0x00FF)
self._write_byte_data(APDS9960_REG_AIHTH, (threshold & 0xFF00) >> 8)
def getProximityIntLowThreshold(self):
"""Gets the low threshold for proximity interrupts.
Returns:
int: threshold current low threshold stored on the APDS9960
Returns:
int: threshold current low threshold stored on the APDS9960
"""
return self._read_byte_data(APDS9960_REG_PILT)
def setProximityIntLowThreshold(self, threshold):
"""Sets the low threshold for proximity interrupts.
Args:
threshold (int): low threshold value for interrupt to trigger
Args:
threshold (int): low threshold value for interrupt to trigger
"""
self._write_byte_data(APDS9960_REG_PILT, threshold)
def getProximityIntHighThreshold(self):
"""Gets the high threshold for proximity interrupts.
Returns:
int: threshold current high threshold stored on the APDS9960
Returns:
int: threshold current high threshold stored on the APDS9960
"""
return self._read_byte_data(APDS9960_REG_PIHT)
def setProximityIntHighThreshold(self, threshold):
"""Sets the high threshold for proximity interrupts.
Args:
threshold (int): high threshold value for interrupt to trigger
Args:
threshold (int): high threshold value for interrupt to trigger
"""
self._write_byte_data(APDS9960_REG_PIHT, threshold)
def getAmbientLightIntEnable(self):
"""Gets if ambient light interrupts are enabled or not.
Returns:
bool: True if interrupts are enabled, False if not
Returns:
bool: True if interrupts are enabled, False if not
"""
val = self._read_byte_data(APDS9960_REG_ENABLE)
return (val >> 4) & 0b00000001 == 1
@ -964,24 +937,23 @@ class APDS9960:
def setAmbientLightIntEnable(self, enable):
"""Turns ambient light interrupts on or off.
Args:
enable (bool): True to enable interrupts, False to turn them off
Args:
enable (bool): True to enable interrupts, False to turn them off
"""
val = self._read_byte_data(APDS9960_REG_ENABLE)
# set bits in register to given value
val &= 0b11101111;
val &= 0b11101111
if enable:
val |= 0b00010000
self._write_byte_data(APDS9960_REG_ENABLE, val)
def getProximityIntEnable(self):
"""Gets if proximity interrupts are enabled or not.
Returns:
bool: True if interrupts are enabled, False if not
Returns:
bool: True if interrupts are enabled, False if not
"""
val = self._read_byte_data(APDS9960_REG_ENABLE)
return (val >> 5) & 0b00000001 == 1
@ -989,24 +961,23 @@ class APDS9960:
def setProximityIntEnable(self, enable):
"""Turns proximity interrupts on or off.
Args:
enable (bool): True to enable interrupts, False to turn them off
Args:
enable (bool): True to enable interrupts, False to turn them off
"""
val = self._read_byte_data(APDS9960_REG_ENABLE)
# set bits in register to given value
val &= 0b11011111;
val &= 0b11011111
if enable:
val |= 0b00100000
self._write_byte_data(APDS9960_REG_ENABLE, val)
def getGestureIntEnable(self):
"""Gets if gesture interrupts are enabled or not.
Returns:
bool: True if interrupts are enabled, False if not
Returns:
bool: True if interrupts are enabled, False if not
"""
val = self._read_byte_data(APDS9960_REG_GCONF4)
return (val >> 1) & 0b00000001 == 1
@ -1014,8 +985,8 @@ class APDS9960:
def setGestureIntEnable(self, enable):
"""Turns gesture-related interrupts on or off.
Args:
enable (bool): True to enable interrupts, False to turn them off
Args:
enable (bool): True to enable interrupts, False to turn them off
"""
val = self._read_byte_data(APDS9960_REG_GCONF4)
@ -1026,24 +997,19 @@ class APDS9960:
self._write_byte_data(APDS9960_REG_GCONF4, val)
def clearAmbientLightInt(self):
"""Clears the ambient light interrupt.
"""
"""Clears the ambient light interrupt."""
self._read_byte_data(APDS9960_REG_AICLEAR)
def clearProximityInt(self):
"""Clears the proximity interrupt.
"""
"""Clears the proximity interrupt."""
self._read_byte_data(APDS9960_REG_PICLEAR)
def getGestureMode(self):
"""Tells if the gesture state machine is currently running.
Returns:
bool: True if gesture state machine is running, False if not
Returns:
bool: True if gesture state machine is running, False if not
"""
val = self._read_byte_data(APDS9960_REG_GCONF4)
return val & 0b00000001 == 1
@ -1051,8 +1017,8 @@ class APDS9960:
def setGestureMode(self, enable):
"""Turns gesture-related interrupts on or off.
Args:
enable (bool): True to enter gesture state machine, False to turn them off
Args:
enable (bool): True to enter gesture state machine, False to turn them off
"""
val = self._read_byte_data(APDS9960_REG_GCONF4)
@ -1063,7 +1029,6 @@ class APDS9960:
self._write_byte_data(APDS9960_REG_GCONF4, val)
# *******************************************************************************
# Raw I2C Reads and Writes
# *******************************************************************************
@ -1074,12 +1039,10 @@ class APDS9960:
def _write_byte_data(self, cmd, val):
return self.bus.write_byte_data(self.address, cmd, val)
def _read_i2c_block_data(self, cmd, num):
return self.bus.read_i2c_block_data(self.address, cmd, num)
class uAPDS9960(APDS9960):
"""
APDS9960 for MicroPython
@ -1087,6 +1050,7 @@ class uAPDS9960(APDS9960):
sensor = uAPDS9960(bus=I2C_instance,
address=APDS9960_I2C_ADDR, valid_id=APDS9960_DEV_ID)
"""
def _read_byte_data(self, cmd):
return self.bus.readfrom_mem(self.address, cmd, 1)[0]

View File

@ -1,6 +1,12 @@
class ADPS9960InvalidDevId(ValueError):
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):
def __init__(self, mode):

View File

@ -11,9 +11,9 @@ MAGGYRO_MODE = 0x06
AMG_MODE = 0x07
IMUPLUS_MODE = 0x08
COMPASS_MODE = 0x09
M4G_MODE = 0x0a
NDOF_FMC_OFF_MODE = 0x0b
NDOF_MODE = 0x0c
M4G_MODE = 0x0A
NDOF_FMC_OFF_MODE = 0x0B
NDOF_MODE = 0x0C
AXIS_P0 = bytes([0x21, 0x04])
AXIS_P1 = bytes([0x24, 0x00])
@ -24,75 +24,91 @@ AXIS_P5 = bytes([0x21, 0x01])
AXIS_P6 = bytes([0x21, 0x07])
AXIS_P7 = bytes([0x24, 0x05])
_MODE_REGISTER = 0x3d
_POWER_REGISTER = 0x3e
_MODE_REGISTER = 0x3D
_POWER_REGISTER = 0x3E
_AXIS_MAP_CONFIG = 0x41
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.address = address
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.system_trigger(0x20)# reset
self.system_trigger(0x20) # reset
pyb.delay(700)
self.power_mode(0x00)#POWER_NORMAL
self.power_mode(0x00) # POWER_NORMAL
self.axis(axis)
self.page(0)
pyb.delay(10)
self.operation_mode(mode)
self.system_trigger(0x80) # external oscillator
self.system_trigger(0x80) # external oscillator
pyb.delay(200)
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):
self.i2c.writeto_mem(self.address, register, data)
def operation_mode(self, mode=None):
if mode:
self.write_registers(_MODE_REGISTER, bytes([mode]))
else:
return(self.read_registers(_MODE_REGISTER, 1)[0])
return self.read_registers(_MODE_REGISTER, 1)[0]
def system_trigger(self, data):
self.write_registers(0x3f, bytes([data]))
self.write_registers(0x3F, bytes([data]))
def power_mode(self, mode=None):
if mode:
self.write_registers(_POWER_REGISTER, bytes([mode]))
else:
return(self.read_registers(_POWER_REGISTER, 1))
return self.read_registers(_POWER_REGISTER, 1)
def page(self, num=None):
if num:
self.write_registers(0x3f, bytes([num]))
self.write_registers(0x3F, bytes([num]))
else:
self.read_registers(0x3f)
self.read_registers(0x3F)
def temperature(self):
return(self.read_registers(0x34, 1)[0])
return self.read_registers(0x34, 1)[0]
def read_id(self):
return(self.read_registers(0x00, 4))
return self.read_registers(0x00, 4)
def axis(self, placement=None):
if placement:
self.write_registers(_AXIS_MAP_CONFIG, placement)
else:
return(self.read_registers(_AXIS_MAP_CONFIG, 2))
return self.read_registers(_AXIS_MAP_CONFIG, 2)
def quaternion(self):
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):
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):
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):
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):
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):
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):
data = struct.unpack("<hhh", self.read_registers(0x2e, 6))
return [d/100 for d in data] #[x, y, z]
data = struct.unpack("<hhh", self.read_registers(0x2E, 6))
return [d / 100 for d in data] # [x, y, z]

View File

@ -10,7 +10,8 @@
import time
import struct
class HTS221():
class HTS221:
def __init__(self, i2c, data_rate=1, dev_addr=0x5F):
self.bus = i2c
self.odr = data_rate
@ -18,7 +19,7 @@ class HTS221():
# Set configuration register
# 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
# PD | BDU | ODR
@ -38,13 +39,13 @@ class HTS221():
# Temperature Calibration values
raw = self.read_reg(0x35, 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.T3 = self.read_reg(0x3E, 2)
def read_reg(self, reg_addr, size):
fmt = 'B' if size == 1 else 'H'
reg_addr = reg_addr if size == 1 else reg_addr|0x80
fmt = "B" if size == 1 else "H"
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]
def humidity(self):
@ -55,4 +56,6 @@ class HTS221():
temp = self.read_reg(0x2A, 2)
if temp > 32767:
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
)

View File

@ -15,46 +15,72 @@
from utime import sleep_ms, ticks_ms
from pyb import UART, Pin
MODE_ABP = 0
MODE_OTAA = 1
MODE_ABP = 0
MODE_OTAA = 1
RF_MODE_RFO = 0
RF_MODE_PABOOST = 1
RF_MODE_RFO = 0
RF_MODE_PABOOST = 1
BAND_AS923 = 0
BAND_AU915 = 1
BAND_EU868 = 5
BAND_KR920 = 6
BAND_IN865 = 7
BAND_US915 = 8
BAND_US915_HYBRID = 9
BAND_AS923 = 0
BAND_AU915 = 1
BAND_EU868 = 5
BAND_KR920 = 6
BAND_IN865 = 7
BAND_US915 = 8
BAND_US915_HYBRID = 9
CLASS_A = 'A'
CLASS_B = 'B'
CLASS_C = 'C'
CLASS_A = "A"
CLASS_B = "B"
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 = {
"": LoraErrorTimeout, # empty buffer
"+ERR": LoraError,
"+ERR_PARAM": LoraErrorParam,
"+ERR_BUSY": LoraErrorBusy,
"+ERR_PARAM_OVERFLOW": LoraErrorOverflow,
"+ERR_NO_NETWORK": LoraErrorNoNetwork,
"+ERR_RX": LoraErrorRX,
"+ERR_UNKNOWN": LoraErrorUnknown
"": LoraErrorTimeout, # empty buffer
"+ERR": LoraError,
"+ERR_PARAM": LoraErrorParam,
"+ERR_BUSY": LoraErrorBusy,
"+ERR_PARAM_OVERFLOW": LoraErrorOverflow,
"+ERR_NO_NETWORK": LoraErrorNoNetwork,
"+ERR_RX": LoraErrorRX,
"+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.uart = uart
self.rst_pin = rst_pin
@ -79,40 +105,39 @@ class Lora():
def init_modem(self):
# Portenta vision shield configuration
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:
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:
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)
def debug_print(self, data):
if self.debug:
print(data)
def is_arduino_firmware(self):
return 'ARD-078' in self.fw_version
return "ARD-078" in self.fw_version
def configure_class(self, _class):
self.send_command("+CLASS=", _class)
self.send_command("+CLASS=", _class)
def configure_band(self, 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)
return True
def set_baudrate(self, baudrate):
self.send_command("+UART=", baudrate)
self.send_command("+UART=", baudrate)
def set_autobaud(self, timeout=10000):
start = ticks_ms()
while ((ticks_ms() - start) < timeout):
if (self.send_command('', timeout=200, raise_error=False) == '+OK'):
while (ticks_ms() - start) < timeout:
if self.send_command("", timeout=200, raise_error=False) == "+OK":
sleep_ms(200)
while (self.uart.any()):
while self.uart.any():
self.uart.readchar()
return True
return False
@ -123,18 +148,18 @@ class Lora():
return dev + " " + fw_ver
def get_device_eui(self):
return self.send_command("+DEVEUI?")
return self.send_command("+DEVEUI?")
def factory_default(self):
self.send_command("+FACNEW")
def restart(self):
if (self.set_autobaud() == False):
raise(LoraError("Failed to set autobaud"))
if self.set_autobaud() is False:
raise (LoraError("Failed to set autobaud"))
# 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"):
raise(LoraError("Failed to reboot module"))
if self.send_command("+REBOOT", delimiter="+EVENT=0,0", timeout=10000) != "+EVENT=0,0":
raise (LoraError("Failed to reboot module"))
sleep_ms(1000)
self.fw_version = self.get_fw_version()
self.configure_band(self.band)
@ -205,72 +230,74 @@ class Lora():
def join(self, timeout_ms):
if self.send_command("+JOIN", timeout=timeout_ms) != "+ACK":
return False
response = self.receive('\r', timeout=timeout_ms)
response = self.receive("\r", timeout=timeout_ms)
return response == "+EVENT=1,1"
def get_join_status(self):
return int(self.send_command("+NJS?")) == 1
def get_max_size(self):
if (self.is_arduino_firmware()):
if self.is_arduino_firmware():
return 64
return int(self.send_command("+MSIZE?", timeout=2000))
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()
# Triggers a fake write
self.send_data('\0', True)
self.send_data("\0", True)
def send_data(self, buff, confirmed=True):
max_len = self.get_max_size()
if (len(buff) > max_len):
raise(LoraError("Packet exceeds max length"))
if len(buff) > max_len:
raise (LoraError("Packet exceeds max length"))
if self.send_command("+CTX " if confirmed else "+UTX ", len(buff), data=buff) != "+OK":
return False
if confirmed:
response = self.receive('\r', timeout=10000)
response = self.receive("\r", timeout=10000)
return response == "+ACK"
return True
def receive_data(self, timeout=1000):
response = self.receive('\r', timeout=timeout)
response = self.receive("\r", timeout=timeout)
if response.startswith("+RECV"):
params = response.split("=")[1].split(",")
port = params[0]
length = int(params[1])
dummy_data_length = 2 # Data starts with \n\n sequence
data = self.receive(max_bytes=length+dummy_data_length, timeout=timeout)[dummy_data_length:]
return {'port' : port, 'data' : data}
dummy_data_length = 2 # Data starts with \n\n sequence
data = self.receive(max_bytes=length + dummy_data_length, timeout=timeout)[
dummy_data_length:
]
return {"port": port, "data": data}
def receive(self, delimiter=None, max_bytes=None, timeout=1000):
buf = []
start = ticks_ms()
while ((ticks_ms() - start) < timeout):
while (self.uart.any()):
while (ticks_ms() - start) < timeout:
while self.uart.any():
buf += chr(self.uart.readchar())
if max_bytes and len(buf) == max_bytes:
data = ''.join(buf)
data = "".join(buf)
self.debug_print(data)
return data
if (len(buf) and delimiter != None):
data = ''.join(buf)
trimmed = data[0:-1] if data[-1] == '\r' else data
if len(buf) and delimiter is not None:
data = "".join(buf)
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)
return trimmed
if (isinstance(delimiter, str) and trimmed == delimiter):
if isinstance(delimiter, str) and trimmed == delimiter:
self.debug_print(trimmed)
return trimmed
if (isinstance(delimiter, list) and trimmed in delimiter):
if isinstance(delimiter, list) and trimmed in delimiter:
self.debug_print(trimmed)
return trimmed
data = ''.join(buf)
data = "".join(buf)
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):
return self.uart.any()
@ -279,17 +306,17 @@ class Lora():
self.change_mode(MODE_OTAA)
self.send_command("+APPEUI=", appEui)
self.send_command("+APPKEY=", appKey)
if (devEui):
if devEui:
self.send_command("+DEVEUI=", devEui)
network_joined = self.join(timeout)
# This delay was in MKRWAN.h
#delay(1000);
# delay(1000);
return network_joined
def join_ABP(self, nwkId, devAddr, nwkSKey, appSKey, timeout=60000):
self.change_mode(MODE_ABP)
# Commented in MKRWAN.h
#self.send_command("+IDNWK=", nwkId)
# self.send_command("+IDNWK=", nwkId)
self.send_command("+DEVADDR=", devAddr)
self.send_command("+NWKSKEY=", nwkSKey)
self.send_command("+APPSKEY=", appSKey)
@ -299,13 +326,13 @@ class Lora():
def handle_error(self, command, data):
if not data.startswith("+ERR") and data != "":
return
if (data in self.LoraErrors):
raise(self.LoraErrors[data]('Command "%s" has failed!'%command))
raise(LoraError('Command: "%s" failed with unknown status: "%s"'%(command, data)))
if data in self.LoraErrors:
raise (self.LoraErrors[data]('Command "%s" has failed!' % command))
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
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.uart.write(uart_cmd)
@ -321,6 +348,6 @@ class Lora():
if raise_error:
self.handle_error(cmd, response)
if cmd.endswith('?'):
return response.split('=')[1]
if cmd.endswith("?"):
return response.split("=")[1]
return response

View File

@ -5,15 +5,16 @@
# v1.0 2016.4
# 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.addr = addr
self.tb = bytearray(1)
@ -30,8 +31,10 @@ class LPS22H():
else:
self.getreg(LPS22_CTRL_REG1)
self.oneshot = oneshot
if oneshot: self.rb[0] &= 0x0F
else: self.rb[0] |= 0x10
if oneshot:
self.rb[0] &= 0x0F
else:
self.rb[0] |= 0x10
self.setreg(LPS22_CTRL_REG1, self.rb[0])
def int16(self, d):
@ -46,12 +49,12 @@ class LPS22H():
return self.rb[0]
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):
if self.oneshot:
self.setreg(LPS22_CTRL_REG2, self.getreg(LPS22_CTRL_REG2) | 0x01)
self.getreg(0x28 + b*2)
self.getreg(0x28 + b * 2)
while 1:
if self.getreg(LPS22_STATUS) & b:
return
@ -59,23 +62,27 @@ class LPS22H():
def temperature(self):
self.ONE_SHOT(2)
try:
return self.int16(self.get2reg(LPS22_TEMP_OUT_L))/100
return self.int16(self.get2reg(LPS22_TEMP_OUT_L)) / 100
except MemoryError:
return self.temperature_irq()
def pressure(self):
self.ONE_SHOT(1)
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:
return self.pressure_irq()
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):
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):
self.ONE_SHOT(1)

View File

@ -143,7 +143,7 @@ class LSM6DSOX:
self.reset()
# Load and configure MLC if UCF file is provided
if ucf != None:
if ucf is not None:
self.load_mlc(ucf)
# Set Gyroscope datarate and scale.

View File

@ -45,39 +45,41 @@ while (True):
"""
import array
class LSM9DS1:
WHO_AM_I = const(0xf)
CTRL_REG1_G = const(0x10)
INT_GEN_SRC_G = const(0x14)
OUT_TEMP = const(0x15)
OUT_G = const(0x18)
CTRL_REG4_G = const(0x1e)
STATUS_REG = const(0x27)
OUT_XL = const(0x28)
FIFO_CTRL_REG = const(0x2e)
FIFO_SRC = const(0x2f)
OFFSET_REG_X_M = const(0x05)
CTRL_REG1_M = const(0x20)
OUT_M = const(0x28)
SCALE_GYRO = [(245,0),(500,1),(2000,3)]
SCALE_ACCEL = [(2,0),(4,2),(8,3),(16,1)]
WHO_AM_I = const(0xF)
CTRL_REG1_G = const(0x10)
INT_GEN_SRC_G = const(0x14)
OUT_TEMP = const(0x15)
OUT_G = const(0x18)
CTRL_REG4_G = const(0x1E)
STATUS_REG = const(0x27)
OUT_XL = const(0x28)
FIFO_CTRL_REG = const(0x2E)
FIFO_SRC = const(0x2F)
OFFSET_REG_X_M = const(0x05)
CTRL_REG1_M = const(0x20)
OUT_M = const(0x28)
SCALE_GYRO = [(245, 0), (500, 1), (2000, 3)]
SCALE_ACCEL = [(2, 0), (4, 2), (8, 3), (16, 1)]
def __init__(self, i2c, address_gyro=0x6B, address_magnet=0x1E):
self.i2c = i2c
self.address_gyro = address_gyro
self.address_magnet = address_magnet
# check id's of accelerometer/gyro and magnetometer
if (self.read_id_magnet() != b'=') or (self.read_id_gyro() != b'h'):
raise OSError("Invalid LSM9DS1 device, using address {}/{}".format(
address_gyro,address_magnet))
if (self.read_id_magnet() != b"=") or (self.read_id_gyro() != b"h"):
raise OSError(
"Invalid LSM9DS1 device, using address {}/{}".format(address_gyro, address_magnet)
)
# allocate scratch buffer for efficient conversions and memread op's
self.scratch = array.array('B',[0,0,0,0,0,0])
self.scratch_int = array.array('h',[0,0,0])
self.scratch = array.array("B", [0, 0, 0, 0, 0, 0])
self.scratch_int = array.array("h", [0, 0, 0])
self.init_gyro_accel()
self.init_magnetometer()
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)
scale_gyro: 0-2 (245dps, 500dps, 2000dps )
scale_accel: 0-3 (+/-2g, +/-4g, +/-8g, +-16g)
@ -91,7 +93,7 @@ class LSM9DS1:
mv = memoryview(self.scratch)
# angular control registers 1-3 / Orientation
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])
# ctrl4 - enable x,y,z, outputs, no irq latching, no 4D
# ctrl5 - enable all axes, no decimation
@ -106,8 +108,8 @@ class LSM9DS1:
i2c.writeto_mem(addr, CTRL_REG4_G, mv[:6])
# 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'\xc0')
i2c.writeto_mem(addr, FIFO_CTRL_REG, b"\x00")
i2c.writeto_mem(addr, FIFO_CTRL_REG, b"\xc0")
self.scale_gyro = 32768 / self.SCALE_GYRO[scale_gyro][0]
self.scale_accel = 32768 / self.SCALE_ACCEL[scale_accel][0]
@ -122,26 +124,26 @@ class LSM9DS1:
i2c = self.i2c
addr = self.address_magnet
mv = memoryview(self.scratch)
mv[0] = 0x40 | (sample_rate << 2) # ctrl1: high performance mode
mv[1] = scale_magnet << 5 # ctrl2: scale, normal mode, no reset
mv[2] = 0x00 # ctrl3: continous conversion, no low power, I2C
mv[3] = 0x08 # ctrl4: high performance z-axis
mv[4] = 0x00 # ctr5: no fast read, no block update
mv[0] = 0x40 | (sample_rate << 2) # ctrl1: high performance mode
mv[1] = scale_magnet << 5 # ctrl2: scale, normal mode, no reset
mv[2] = 0x00 # ctrl3: continous conversion, no low power, I2C
mv[3] = 0x08 # ctrl4: high performance z-axis
mv[4] = 0x00 # ctr5: no fast read, no block update
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):
"""
offset is a magnet vecor that will be substracted by the magnetometer
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[0] = offset[0] & 0xff
mv[0] = offset[0] & 0xFF
mv[1] = offset[0] >> 8
mv[2] = offset[1] & 0xff
mv[2] = offset[1] & 0xFF
mv[3] = offset[1] >> 8
mv[4] = offset[2] & 0xff
mv[4] = offset[2] & 0xFF
mv[5] = offset[2] >> 8
self.i2c.writeto_mem(self.address_magnet, OFFSET_REG_X_M, mv[:6])
@ -158,28 +160,30 @@ class LSM9DS1:
mv = memoryview(self.scratch_int)
f = self.scale_factor_magnet
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):
"""Returns gyroscope vector in degrees/sec."""
mv = memoryview(self.scratch_int)
f = self.scale_gyro
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):
"""Returns acceleration vector in gravity units (9.81m/s^2)."""
mv = memoryview(self.scratch_int)
f = self.scale_accel
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):
"""A generator that returns tuples of (gyro,accelerometer) data from the fifo."""
while True:
fifo_state = int.from_bytes(self.i2c.readfrom_mem(self.address_gyro, FIFO_SRC, 1),'big')
if fifo_state & 0x3f:
fifo_state = int.from_bytes(
self.i2c.readfrom_mem(self.address_gyro, FIFO_SRC, 1), "big"
)
if fifo_state & 0x3F:
# print("Available samples=%d" % (fifo_state & 0x1f))
yield self.read_gyro(),self.read_accel()
yield self.read_gyro(), self.read_accel()
else:
break

View File

@ -1,51 +1,284 @@
import struct
class ModbusRTU():
class ModbusRTU:
def __init__(self, uart, slave_id=0x01, register_num=30):
self.SLAVE_ID = slave_id
self.uart = uart
self.register_num = register_num
self.REGISTER = [0]*self.register_num
self.REGISTER = [0] * self.register_num
self.CRC16_TABLE = [
0x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241,0xC601,
0x06C0,0x0780,0xC741,0x0500,0xC5C1,0xC481,0x0440,0xCC01,0x0CC0,
0x0D80,0xCD41,0x0F00,0xCFC1,0xCE81,0x0E40,0x0A00,0xCAC1,0xCB81,
0x0B40,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]
0x0000,
0xC0C1,
0xC181,
0x0140,
0xC301,
0x03C0,
0x0280,
0xC241,
0xC601,
0x06C0,
0x0780,
0xC741,
0x0500,
0xC5C1,
0xC481,
0x0440,
0xCC01,
0x0CC0,
0x0D80,
0xCD41,
0x0F00,
0xCFC1,
0xCE81,
0x0E40,
0x0A00,
0xCAC1,
0xCB81,
0x0B40,
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):
return self.uart.any()
def clear(self):
self.REGISTER = [0]*self.register_num
self.REGISTER = [0] * self.register_num
def crc16(self, data):
crc = 0xFFFF
for char in data:
crc = (crc >> 8) ^ self.CRC16_TABLE[((crc) ^ char) & 0xFF]
return struct.pack('<H',crc)
def handle(self, debug = False):
return struct.pack("<H", crc)
def handle(self, debug=False):
REQUEST = self.uart.read()
if debug:
print("GOT REQUEST: ", REQUEST)
@ -53,79 +286,79 @@ class ModbusRTU():
error_check = REQUEST[-2:]
function_code = REQUEST[1]
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 debug:
print("crc not match")
return 0 # do nothing
return 0 # do nothing
if self.SLAVE_ID != additional_address:
if debug:
print("OpenMV slave id: ", self.SLAVE_ID)
print("got cmd id: ", additional_address)
return 0 # do nothing
return 0 # do nothing
if function_code == 0x03:
starting_address = struct.unpack('>h', data[:2])[0]
quantity_of_registers = struct.unpack('>h', data[2:4])[0]
starting_address = struct.unpack(">h", data[:2])[0]
quantity_of_registers = struct.unpack(">h", data[2:4])[0]
response_registers = []
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])
except IndexError as err:
RESPONSE += struct.pack('b', function_code|0x80)
RESPONSE += struct.pack('b', 0x02) # Illegal Data Address
RESPONSE += struct.pack("b", function_code | 0x80)
RESPONSE += struct.pack("b", 0x02) # Illegal Data Address
if debug:
print("Illegal Data Address: ")
print(err)
else:
RESPONSE += struct.pack('b', function_code)
RESPONSE += struct.pack('b', 2*quantity_of_registers)
RESPONSE += struct.pack("b", function_code)
RESPONSE += struct.pack("b", 2 * quantity_of_registers)
for b in response_registers:
RESPONSE += struct.pack('>h', b)
RESPONSE += struct.pack(">h", b)
elif function_code == 0x06:
register_address = struct.unpack('>h', data[:2])[0]
register_value = struct.unpack('>h', data[2:4])[0]
register_address = struct.unpack(">h", data[:2])[0]
register_value = struct.unpack(">h", data[2:4])[0]
try:
self.REGISTER[register_address] = register_value
except IndexError as err:
RESPONSE += struct.pack('b', function_code|0x80)
RESPONSE += struct.pack('b', 0x02) # Illegal Data Address
RESPONSE += struct.pack("b", function_code | 0x80)
RESPONSE += struct.pack("b", 0x02) # Illegal Data Address
if debug:
print("Illegal Data Address: ")
print(err)
else:
RESPONSE += struct.pack('b', function_code)
RESPONSE += struct.pack('>h', register_address)
RESPONSE += struct.pack('>h', self.REGISTER[register_address])
RESPONSE += struct.pack("b", function_code)
RESPONSE += struct.pack(">h", register_address)
RESPONSE += struct.pack(">h", self.REGISTER[register_address])
elif function_code == 0x10:
starting_address = struct.unpack('>h', data[:2])[0]
quantity_of_registers = struct.unpack('>h', data[2:4])[0]
byte_of_registers = struct.unpack('b', data[4:5])[0]
starting_address = struct.unpack(">h", data[:2])[0]
quantity_of_registers = struct.unpack(">h", data[2:4])[0]
byte_of_registers = struct.unpack("b", data[4:5])[0]
try:
if byte_of_registers != 2*quantity_of_registers:
if byte_of_registers != 2 * quantity_of_registers:
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:
RESPONSE += struct.pack('b', function_code|0x80)
RESPONSE += struct.pack('b', 0x03) # Illegal Data Value
RESPONSE += struct.pack("b", function_code | 0x80)
RESPONSE += struct.pack("b", 0x03) # Illegal Data Value
if debug:
print("Illegal Data Value, data length error")
else:
try:
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:
RESPONSE += struct.pack('b', function_code|0x80)
RESPONSE += struct.pack('b', 0x02) # Illegal Data Address
RESPONSE += struct.pack("b", function_code | 0x80)
RESPONSE += struct.pack("b", 0x02) # Illegal Data Address
if debug:
print("Illegal Data Address: ")
print(err)
else:
RESPONSE += struct.pack('b', function_code)
RESPONSE += struct.pack('>h', starting_address)
RESPONSE += struct.pack('>h', quantity_of_registers)
RESPONSE += struct.pack("b", function_code)
RESPONSE += struct.pack(">h", starting_address)
RESPONSE += struct.pack(">h", quantity_of_registers)
else:
RESPONSE += struct.pack('b', function_code|0x80)
RESPONSE += struct.pack('b', 0x01) # Illegal Function
RESPONSE += struct.pack("b", function_code | 0x80)
RESPONSE += struct.pack("b", 0x01) # Illegal Function
RESPONSE += self.crc16(RESPONSE)
if debug:
print("FUNCTION CODE: ", function_code)

View File

@ -24,15 +24,24 @@
import usocket as socket
import ustruct as struct
from ubinascii import hexlify
class MQTTException(Exception):
pass
class MQTTClient:
def __init__(self, client_id, server, port=0, user=None, password=None, keepalive=0,
ssl=False, ssl_params={}):
class MQTTClient:
def __init__(
self,
client_id,
server,
port=0,
user=None,
password=None,
keepalive=0,
ssl=False,
ssl_params={},
):
if port == 0:
port = 8883 if ssl else 1883
self.client_id = client_id
@ -60,7 +69,7 @@ class MQTTClient:
sh = 0
while 1:
b = self.sock.read(1)[0]
n |= (b & 0x7f) << sh
n |= (b & 0x7F) << sh
if not b & 0x80:
return n
sh += 7
@ -83,6 +92,7 @@ class MQTTClient:
self.sock.connect(addr)
if self.ssl:
import ussl
self.sock = ussl.wrap_socket(self.sock, **self.ssl_params)
premsg = bytearray(b"\x10\0\0\0\0\0")
msg = bytearray(b"\x04MQTT\x04\x02\0\0")
@ -102,15 +112,15 @@ class MQTTClient:
msg[6] |= self.lw_retain << 5
i = 1
while sz > 0x7f:
premsg[i] = (sz & 0x7f) | 0x80
while sz > 0x7F:
premsg[i] = (sz & 0x7F) | 0x80
sz >>= 7
i += 1
premsg[i] = sz
self.sock.write(premsg[0:i + 2])
self.sock.write(premsg[0 : i + 2])
self.sock.write(msg)
#print(hex(len(msg)), hexlify(msg, ":"))
# print(hex(len(msg)), hexlify(msg, ":"))
self._send_str(self.client_id)
if self.lw_topic:
self._send_str(self.lw_topic)
@ -139,13 +149,13 @@ class MQTTClient:
sz += 2
assert sz < 2097152
i = 1
while sz > 0x7f:
pkt[i] = (sz & 0x7f) | 0x80
while sz > 0x7F:
pkt[i] = (sz & 0x7F) | 0x80
sz >>= 7
i += 1
pkt[i] = sz
#print(hex(len(pkt)), hexlify(pkt, ":"))
self.sock.write(pkt[0:i + 1])
# print(hex(len(pkt)), hexlify(pkt, ":"))
self.sock.write(pkt[0 : i + 1])
self._send_str(topic)
if qos > 0:
self.pid += 1
@ -171,7 +181,7 @@ class MQTTClient:
pkt = bytearray(b"\x82\0\0\0")
self.pid += 1
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._send_str(topic)
self.sock.write(qos.to_bytes(1, "little"))
@ -179,7 +189,7 @@ class MQTTClient:
op = self.wait_msg()
if op == 0x90:
resp = self.sock.read(4)
#print(resp)
# print(resp)
assert resp[1] == pkt[2] and resp[2] == pkt[3]
if resp[3] == 0x80:
raise MQTTException(resp[3])
@ -191,7 +201,7 @@ class MQTTClient:
# messages processed internally.
def wait_msg(self):
res = self.sock.read(1)
if res == b"" or res == None:
if res == b"" or res is None:
return None
self.sock.setblocking(True)
if res == b"\xd0": # PINGRESP
@ -199,7 +209,7 @@ class MQTTClient:
assert sz == 0
return None
op = res[0]
if op & 0xf0 != 0x30:
if op & 0xF0 != 0x30:
return op
sz = self._recv_len()
topic_len = self.sock.read(2)

View File

@ -1,41 +1,46 @@
import pyb, micropython, array, uctypes
import micropython
import array
import uctypes
micropython.alloc_emergency_exception_buf(100)
class MutexException(OSError):
pass
class Mutex:
@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)
ldr(r0, [r1, 0]) # Wait for lock to be zero
ldr(r0, [r1, 0]) # Wait for lock to be zero
cmp(r0, 0)
bne(LOOP) # Another process has the lock: spin on it
cpsid(0) # OK, we have lock at this instant disable interrupts
ldr(r0, [r1, 0]) # and re-check in case an interrupt occurred
bne(LOOP) # Another process has the lock: spin on it
cpsid(0) # OK, we have lock at this instant disable interrupts
ldr(r0, [r1, 0]) # and re-check in case an interrupt occurred
cmp(r0, 0)
itt(ne) # if someone got in first re-enable ints
cpsie(0) # and start polling again
itt(ne) # if someone got in first re-enable ints
cpsie(0) # and start polling again
b(LOOP)
mov(r0, 1) # We have an exclusive access
str(r0, [r1, 0]) # set the lock
mov(r0, 1) # We have an exclusive access
str(r0, [r1, 0]) # set the lock
cpsie(0)
@micropython.asm_thumb
def _attempt(r0, r1): # Nonblocking. Try to lock. Return 0 on success, 1 on fail
cpsid(0) # disable interrupts
def _attempt(r0, r1): # Nonblocking. Try to lock. Return 0 on success, 1 on fail
cpsid(0) # disable interrupts
ldr(r0, [r1, 0])
cmp(r0, 0)
bne(FAIL) # Another process has the lock: fail
mov(r2, 1) # No lock
str(r2, [r1, 0]) # set the lock
bne(FAIL) # Another process has the lock: fail
mov(r2, 1) # No lock
str(r2, [r1, 0]) # set the lock
label(FAIL)
cpsie(0) # enable interrupts
cpsie(0) # enable interrupts
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):
self._acquire(uctypes.addressof(self.lock))
return self
@ -43,13 +48,12 @@ class Mutex:
def __exit__(self, *_):
self.lock[0] = 0
# POSIX pthread_mutex_unlock()
# POSIX pthread_mutex_unlock()
def release(self):
if self.lock[0] == 0:
raise MutexException('Semaphore already released')
raise MutexException("Semaphore already released")
self.lock[0] = 0
# 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.
# 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.
return self._attempt(uctypes.addressof(self.lock)) == 0

View File

@ -1,4 +1,4 @@
'''
"""
Example:
from pid import PID
pid1 = PID(p=0.07, i=0, imax=90)
@ -6,21 +6,23 @@ while(True):
error = 50 #error should be caculated, target - mesure
output=pid1.get_pid(error,1)
#control value with output
'''
"""
from pyb import millis
from math import pi, isnan
class PID:
_kp = _ki = _kd = _integrator = _imax = 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):
self._kp = float(p)
self._ki = float(i)
self._kd = float(d)
self._imax = abs(imax)
self._last_derivative = float('nan')
self._last_derivative = float("nan")
def get_pid(self, error, scaler):
tnow = millis()
@ -38,19 +40,22 @@ class PID:
self._last_derivative = 0
else:
derivative = (error - self._last_error) / delta_time
derivative = self._last_derivative + \
((delta_time / (self._RC + delta_time)) * \
(derivative - self._last_derivative))
derivative = self._last_derivative + (
(delta_time / (self._RC + delta_time)) * (derivative - self._last_derivative)
)
self._last_error = error
self._last_derivative = derivative
output += self._kd * derivative
output *= scaler
if abs(self._ki) > 0 and dt > 0:
self._integrator += (error * self._ki) * scaler * delta_time
if self._integrator < -self._imax: self._integrator = -self._imax
elif self._integrator > self._imax: self._integrator = self._imax
if self._integrator < -self._imax:
self._integrator = -self._imax
elif self._integrator > self._imax:
self._integrator = self._imax
output += self._integrator
return output
def reset_I(self):
self._integrator = 0
self._last_derivative = float('nan')
self._last_derivative = float("nan")

View File

@ -5,7 +5,13 @@
#
# 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:

View File

@ -5,7 +5,10 @@
#
# 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:

View File

@ -3,23 +3,24 @@ import framebuf
from pyb import SPI
# register definitions
SET_CONTRAST = const(0x81)
SET_ENTIRE_ON = const(0xa4)
SET_NORM_INV = const(0xa6)
SET_DISP = const(0xae)
SET_MEM_ADDR = const(0x20)
SET_COL_ADDR = const(0x21)
SET_PAGE_ADDR = const(0x22)
SET_CONTRAST = const(0x81)
SET_ENTIRE_ON = const(0xA4)
SET_NORM_INV = const(0xA6)
SET_DISP = const(0xAE)
SET_MEM_ADDR = const(0x20)
SET_COL_ADDR = const(0x21)
SET_PAGE_ADDR = const(0x22)
SET_DISP_START_LINE = const(0x40)
SET_SEG_REMAP = const(0xa0)
SET_MUX_RATIO = const(0xa8)
SET_COM_OUT_DIR = const(0xc0)
SET_DISP_OFFSET = const(0xd3)
SET_COM_PIN_CFG = const(0xda)
SET_DISP_CLK_DIV = const(0xd5)
SET_PRECHARGE = const(0xd9)
SET_VCOM_DESEL = const(0xdb)
SET_CHARGE_PUMP = const(0x8d)
SET_SEG_REMAP = const(0xA0)
SET_MUX_RATIO = const(0xA8)
SET_COM_OUT_DIR = const(0xC0)
SET_DISP_OFFSET = const(0xD3)
SET_COM_PIN_CFG = const(0xDA)
SET_DISP_CLK_DIV = const(0xD5)
SET_PRECHARGE = const(0xD9)
SET_VCOM_DESEL = const(0xDB)
SET_CHARGE_PUMP = const(0x8D)
class SSD1306:
def __init__(self, width, height, external_vcc):
@ -35,27 +36,37 @@ class SSD1306:
def init_display(self):
for cmd in (
SET_DISP | 0x00, # off
SET_DISP | 0x00, # off
# address setting
SET_MEM_ADDR, 0x00, # horizontal
SET_MEM_ADDR,
0x00, # horizontal
# resolution and layout
SET_DISP_START_LINE | 0x00,
SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
SET_MUX_RATIO, self.height - 1,
SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
SET_DISP_OFFSET, 0x00,
SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12,
SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
SET_MUX_RATIO,
self.height - 1,
SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
SET_DISP_OFFSET,
0x00,
SET_COM_PIN_CFG,
0x02 if self.height == 32 else 0x12,
# timing and driving scheme
SET_DISP_CLK_DIV, 0x80,
SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1,
SET_VCOM_DESEL, 0x30, # 0.83*Vcc
SET_DISP_CLK_DIV,
0x80,
SET_PRECHARGE,
0x22 if self.external_vcc else 0xF1,
SET_VCOM_DESEL,
0x30, # 0.83*Vcc
# display
SET_CONTRAST, 0xff, # maximum
SET_ENTIRE_ON, # output follows RAM contents
SET_NORM_INV, # not inverted
SET_CONTRAST,
0xFF, # maximum
SET_ENTIRE_ON, # output follows RAM contents
SET_NORM_INV, # not inverted
# charge pump
SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14,
SET_DISP | 0x01): # on
SET_CHARGE_PUMP,
0x10 if self.external_vcc else 0x14,
SET_DISP | 0x01,
): # on
self.write_cmd(cmd)
self.fill(0)
self.show()
@ -97,28 +108,28 @@ class SSD1306:
def text(self, string, x, y, col=1):
self.framebuf.text(string, x, y, col)
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.addr = addr
self.temp = bytearray(2)
super().__init__(width, height, external_vcc)
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.i2c.writeto(self.addr, self.temp)
def write_data(self, buf):
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.write(self.temp)
self.i2c.write(buf)
self.i2c.stop()
class SSD1306_SPI(SSD1306):
def __init__(self, width, height, spi, dc, res, cs, external_vcc=False):
self.rate = 10 * 1024 * 1024
@ -142,7 +153,7 @@ class SSD1306_SPI(SSD1306):
self.cs.high()
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.dc.high()
self.cs.low()

View File

@ -1,17 +1,19 @@
import pyb
class Motor():
class Motor:
def __init__(self, channel):
if channel == 1:
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.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)
tim = pyb.Timer(4, freq=1000)
self.power = tim.channel(1, pyb.Timer.PWM, pin=pyb.Pin("P7"), pulse_width_percent=0)
elif channel == 2:
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.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)
tim = pyb.Timer(4, freq=1000)
self.power = tim.channel(2, pyb.Timer.PWM, pin=pyb.Pin("P8"), pulse_width_percent=0)
def set_speed(self, pwm):
if pwm < 0:
self.pin1.low()
@ -21,13 +23,14 @@ class Motor():
self.pin2.low()
self.power.pulse_width_percent(abs(pwm))
class Stepper():
class Stepper:
def __init__(self, stepnumber=200, rpms=2, power=50):
self.stepnumber = stepnumber
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.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.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.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)
tim = pyb.Timer(4, freq=1000)
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)
@ -36,13 +39,13 @@ class Stepper():
self.phase = self.phase_list()
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:
for p in phase_list:
yield p
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):
self.power1.pulse_width_percent(power)
@ -56,4 +59,3 @@ class Stepper():
self.pin3.value(phase[2])
self.pin4.value(phase[3])
pyb.udelay(self.delay_time)

View File

@ -42,24 +42,36 @@ verbose_l = 0
client_busy = False
# Interfaces: (IP-Address (string), IP-Address (integer), Netmask (integer))
_month_name = ("", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
_month_name = (
"",
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
)
class FTP_client:
def __init__(self, ftpsocket, local_addr):
self.command_client, self.remote_addr = ftpsocket.accept()
self.remote_addr = self.remote_addr[0]
self.command_client.settimeout(_COMMAND_TIMEOUT)
log_msg(1, "FTP Command connection from:", self.remote_addr)
self.command_client.setsockopt(socket.SOL_SOCKET,
_SO_REGISTER_HANDLER,
self.exec_ftp_command)
self.command_client.setsockopt(
socket.SOL_SOCKET, _SO_REGISTER_HANDLER, self.exec_ftp_command
)
self.command_client.sendall("220 Hello, this is the {}.\r\n".format(sys.platform))
self.cwd = '/'
self.cwd = "/"
self.fromname = None
# self.logged_in = False
# self.logged_in = False
self.act_data_addr = self.remote_addr
self.DATA_PORT = 20
self.active = True
@ -69,13 +81,12 @@ class FTP_client:
try:
for fname in uos.listdir(path):
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)
try:
for fname in uos.listdir(path):
if self.fncmp(fname, pattern):
data_client.sendall(
self.make_description(path, fname, full))
data_client.sendall(self.make_description(path, fname, full))
except:
pass
@ -83,20 +94,18 @@ class FTP_client:
global _month_name
if full:
stat = uos.stat(self.get_absolute_path(path, fname))
file_permissions = ("drwxr-xr-x"
if (stat[0] & 0o170000 == 0o040000)
else "-rw-r--r--")
file_permissions = "drwxr-xr-x" if (stat[0] & 0o170000 == 0o040000) else "-rw-r--r--"
file_size = stat[6]
tm = stat[7] & 0xffffffff
tm = stat[7] & 0xFFFFFFFF
tm = localtime(tm if tm < 0x80000000 else tm - 0x100000000)
if tm[0] != localtime()[0]:
description = "{} 1 owner group {:>10} {} {:2} {:>5} {}\r\n".\
format(file_permissions, file_size,
_month_name[tm[1]], tm[2], tm[0], fname)
description = "{} 1 owner group {:>10} {} {:2} {:>5} {}\r\n".format(
file_permissions, file_size, _month_name[tm[1]], tm[2], tm[0], fname
)
else:
description = "{} 1 owner group {:>10} {} {:2} {:02}:{:02} {}\r\n".\
format(file_permissions, file_size,
_month_name[tm[1]], tm[2], tm[3], tm[4], fname)
description = "{} 1 owner group {:>10} {} {:2} {:02}:{:02} {}\r\n".format(
file_permissions, file_size, _month_name[tm[1]], tm[2], tm[3], tm[4], fname
)
else:
description = fname + "\r\n"
return description
@ -125,22 +134,22 @@ class FTP_client:
# Just a few special cases "..", "." and ""
# If payload start's with /, set cwd to /
# and consider the remainder a relative path
if payload.startswith('/'):
if payload.startswith("/"):
cwd = "/"
for token in payload.split("/"):
if token == '..':
if token == "..":
cwd = self.split_path(cwd)[0]
elif token != '.' and token != '':
if cwd == '/':
elif token != "." and token != "":
if cwd == "/":
cwd += token
else:
cwd = cwd + '/' + token
cwd = cwd + "/" + token
return cwd
def split_path(self, path): # instead of path.rpartition('/')
tail = path.split('/')[-1]
head = path[:-(len(tail) + 1)]
return ('/' if head == '' else head, tail)
tail = path.split("/")[-1]
head = path[: -(len(tail) + 1)]
return ("/" if head == "" else head, tail)
# compare fname against pattern. Pattern may contain
# the wildcards ? and *.
@ -148,15 +157,15 @@ class FTP_client:
pi = 0
si = 0
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
pi += 1
else:
if pattern[pi] == '*': # recurse
if pattern[pi] == "*": # recurse
if pi == len(pattern.rstrip("*?")): # only wildcards left
return True
while si < len(fname):
if self.fncmp(fname[si:], pattern[pi + 1:]):
if self.fncmp(fname[si:], pattern[pi + 1 :]):
return True
else:
si += 1
@ -210,7 +219,7 @@ class FTP_client:
# return
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)
log_msg(1, "Command={}, Payload={}".format(command, payload))
@ -229,9 +238,9 @@ class FTP_client:
elif command == "SYST":
cl.sendall("215 UNIX Type: L8\r\n")
elif command in ("TYPE", "NOOP", "ABOR"): # just accept & ignore
cl.sendall('200 OK\r\n')
cl.sendall("200 OK\r\n")
elif command == "QUIT":
cl.sendall('221 Bye.\r\n')
cl.sendall("221 Bye.\r\n")
close_client(cl)
elif command == "PWD" or command == "XPWD":
cl.sendall('257 "{}"\r\n'.format(self.cwd))
@ -239,44 +248,44 @@ class FTP_client:
try:
if (uos.stat(path)[0] & 0o170000) == 0o040000:
self.cwd = path
cl.sendall('250 OK\r\n')
cl.sendall("250 OK\r\n")
else:
cl.sendall('550 Fail\r\n')
cl.sendall("550 Fail\r\n")
except:
cl.sendall('550 Fail\r\n')
cl.sendall("550 Fail\r\n")
elif command == "PASV":
cl.sendall('227 Entering Passive Mode ({},{},{}).\r\n'.format(
self.pasv_data_addr.replace('.', ','),
_DATA_PORT >> 8, _DATA_PORT % 256))
cl.sendall(
"227 Entering Passive Mode ({},{},{}).\r\n".format(
self.pasv_data_addr.replace(".", ","), _DATA_PORT >> 8, _DATA_PORT % 256
)
)
self.active = False
elif command == "PORT":
items = payload.split(",")
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":
# replace by command session addr
self.act_data_addr = self.remote_addr
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
else:
cl.sendall('504 Fail\r\n')
cl.sendall("504 Fail\r\n")
elif command == "LIST" or command == "NLST":
if payload.startswith("-"):
option = payload.split()[0].lower()
path = self.get_absolute_path(
self.cwd, payload[len(option):].lstrip())
path = self.get_absolute_path(self.cwd, payload[len(option) :].lstrip())
else:
option = ""
try:
data_client = self.open_dataclient()
cl.sendall("150 Directory listing:\r\n")
self.send_list_data(path, data_client,
command == "LIST" or 'l' in option)
self.send_list_data(path, data_client, command == "LIST" or "l" in option)
cl.sendall("226 Done.\r\n")
data_client.close()
except:
cl.sendall('550 Fail\r\n')
cl.sendall("550 Fail\r\n")
if data_client is not None:
data_client.close()
elif command == "RETR":
@ -289,43 +298,47 @@ class FTP_client:
data_client = None
cl.sendall("226 Done.\r\n")
except:
cl.sendall('550 Fail\r\n')
cl.sendall("550 Fail\r\n")
if data_client is not None:
data_client.close()
elif command == "STOR" or command == "APPE":
try:
data_client = self.open_dataclient()
cl.sendall("150 Opened data connection.\r\n")
self.save_file_data(path, data_client,
"wb" if command == "STOR" else "ab")
self.save_file_data(path, data_client, "wb" if command == "STOR" else "ab")
# if the next statement is reached,
# the data_client was closed.
data_client = None
cl.sendall("226 Done.\r\n")
except:
cl.sendall('550 Fail\r\n')
cl.sendall("550 Fail\r\n")
if data_client is not None:
data_client.close()
elif command == "SIZE":
try:
cl.sendall('213 {}\r\n'.format(uos.stat(path)[6]))
cl.sendall("213 {}\r\n".format(uos.stat(path)[6]))
except:
cl.sendall('550 Fail\r\n')
cl.sendall("550 Fail\r\n")
elif command == "MDTM":
try:
tm=localtime(uos.stat(path)[8])
cl.sendall('213 {:04d}{:02d}{:02d}{:02d}{:02d}{:02d}\r\n'.format(*tm[0:6]))
tm = localtime(uos.stat(path)[8])
cl.sendall("213 {:04d}{:02d}{:02d}{:02d}{:02d}{:02d}\r\n".format(*tm[0:6]))
except:
cl.sendall('550 Fail\r\n')
cl.sendall("550 Fail\r\n")
elif command == "STAT":
if payload == "":
cl.sendall("211-Connected to ({})\r\n"
" Data address ({})\r\n"
" TYPE: Binary STRU: File MODE: Stream\r\n"
" Session timeout {}\r\n"
"211 Client count is {}\r\n".format(
self.remote_addr, self.pasv_data_addr,
_COMMAND_TIMEOUT, len(client_list)))
cl.sendall(
"211-Connected to ({})\r\n"
" Data address ({})\r\n"
" TYPE: Binary STRU: File MODE: Stream\r\n"
" Session timeout {}\r\n"
"211 Client count is {}\r\n".format(
self.remote_addr,
self.pasv_data_addr,
_COMMAND_TIMEOUT,
len(client_list),
)
)
else:
cl.sendall("213-Directory listing:\r\n")
self.send_list_data(path, cl, True)
@ -333,9 +346,9 @@ class FTP_client:
elif command == "DELE":
try:
uos.remove(path)
cl.sendall('250 OK\r\n')
cl.sendall("250 OK\r\n")
except:
cl.sendall('550 Fail\r\n')
cl.sendall("550 Fail\r\n")
elif command == "RNFR":
try:
# just test if the name exists, exception if not
@ -343,35 +356,35 @@ class FTP_client:
self.fromname = path
cl.sendall("350 Rename from\r\n")
except:
cl.sendall('550 Fail\r\n')
cl.sendall("550 Fail\r\n")
elif command == "RNTO":
try:
uos.rename(self.fromname, path)
cl.sendall('250 OK\r\n')
except:
cl.sendall('550 Fail\r\n')
self.fromname = None
try:
uos.rename(self.fromname, path)
cl.sendall("250 OK\r\n")
except:
cl.sendall("550 Fail\r\n")
self.fromname = None
elif command == "CDUP" or command == "XCUP":
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":
try:
uos.rmdir(path)
cl.sendall('250 OK\r\n')
cl.sendall("250 OK\r\n")
except:
cl.sendall('550 Fail\r\n')
cl.sendall("550 Fail\r\n")
elif command == "MKD" or command == "XMKD":
try:
uos.mkdir(path)
cl.sendall('250 OK\r\n')
cl.sendall("250 OK\r\n")
except:
cl.sendall('550 Fail\r\n')
cl.sendall("550 Fail\r\n")
elif command == "SITE":
try:
exec(payload.replace('\0','\n'))
cl.sendall('250 OK\r\n')
exec(payload.replace("\0", "\n"))
cl.sendall("250 OK\r\n")
except:
cl.sendall('550 Fail\r\n')
cl.sendall("550 Fail\r\n")
else:
cl.sendall("502 Unsupported command.\r\n")
# log_msg(2,
@ -422,8 +435,7 @@ def accept_ftp_connect(ftpsocket, local_addr):
def num_ip(ip):
items = ip.split(".")
return (int(items[0]) << 24 | int(items[1]) << 16 |
int(items[2]) << 8 | int(items[3]))
return int(items[0]) << 24 | int(items[1]) << 16 | int(items[2]) << 8 | int(items[3])
def stop():
@ -432,8 +444,7 @@ def stop():
global client_busy
for client in client_list:
client.command_client.setsockopt(socket.SOL_SOCKET,
_SO_REGISTER_HANDLER, None)
client.command_client.setsockopt(socket.SOL_SOCKET, _SO_REGISTER_HANDLER, None)
client.command_client.close()
del 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.bind(addr[0][4])
sock.listen(1)
sock.setsockopt(socket.SOL_SOCKET,
_SO_REGISTER_HANDLER,
lambda s : accept_ftp_connect(s, ifconfig[0]))
sock.setsockopt(
socket.SOL_SOCKET, _SO_REGISTER_HANDLER, lambda s: accept_ftp_connect(s, ifconfig[0])
)
ftpsockets.append(sock)
if splash:
print("FTP server started on {}:{}".format(ifconfig[0], port))
datasocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
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.settimeout(10)
def restart(port=21, verbose=0, splash=True):
stop()
sleep_ms(200)

View File

@ -2,23 +2,25 @@
# copyright (c) 2018 Shawwwn <shawwwn1@gmail.com>
# License: MIT
# Internet Checksum Algorithm
# Author: Olav Morken
# https://github.com/olavmrk/python-ping/blob/master/ping.py
# @data: bytes
def checksum(data):
if len(data) & 0x1: # Odd number of bytes
data += b'\0'
if len(data) & 0x1: # Odd number of bytes
data += b"\0"
cs = 0
for pos in range(0, len(data), 2):
b1 = data[pos]
b2 = data[pos + 1]
cs += (b1 << 8) + b2
while cs >= 0x10000:
cs = (cs & 0xffff) + (cs >> 16)
cs = ~cs & 0xffff
cs = (cs & 0xFFFF) + (cs >> 16)
cs = ~cs & 0xFFFF
return cs
def ping(host, count=4, timeout=5000, interval=10, quiet=False, size=64):
import utime
import uselect
@ -29,7 +31,7 @@ def ping(host, count=4, timeout=5000, interval=10, quiet=False, size=64):
# prepare packet
assert size >= 16, "pkt size too small"
pkt = b'Q'*size
pkt = b"Q" * size
pkt_desc = {
"type": uctypes.UINT8 | 0,
"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,
"seq": uctypes.INT16 | 6,
"timestamp": uctypes.UINT64 | 8,
} # packet header descriptor
} # packet header descriptor
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.checksum = 0
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
sock = usocket.socket(usocket.AF_INET, usocket.SOCK_RAW, 1)
sock.setblocking(0)
sock.settimeout(timeout/1000)
addr = usocket.getaddrinfo(host, 1)[0][-1][0] # ip address
sock.settimeout(timeout / 1000)
addr = usocket.getaddrinfo(host, 1)[0][-1][0] # ip address
sock.connect((addr, 1))
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
t = 0
n_trans = 0
n_recv = 0
finish = False
while t < timeout:
if t==interval and c<=count:
if t == interval and c <= count:
# send packet
h.checksum = 0
h.seq = c
@ -68,7 +70,7 @@ def ping(host, count=4, timeout=5000, interval=10, quiet=False, size=64):
h.checksum = checksum(pkt)
if sock.send(pkt) == size:
n_trans += 1
t = 0 # reset timeout
t = 0 # reset timeout
else:
seqs.remove(c)
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)
# TODO: validate checksum (optional)
seq = h2.seq
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
ttl = ustruct.unpack('!B', resp_mv[8:9])[0] # time-to-live
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
ttl = ustruct.unpack("!B", resp_mv[8:9])[0] # time-to-live
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)
if len(seqs) == 0:
finish = True

View File

@ -20,7 +20,8 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# 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:
# https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4
# https://docs.python-requests.org/en/master/
@ -28,6 +29,7 @@
import usocket
import ubinascii
class Response:
def __init__(self, code, reason, headers=None, content=None):
self.encoding = "utf-8"
@ -46,23 +48,26 @@ class Response:
def json(self):
import ujson
return ujson.loads(self._content)
def readline(s):
l = bytearray()
while True:
try:
l += s.read(1)
if (l[-1] == b'\n'):
if l[-1] == b"\n":
break
except:
break
return l
def socket_readall(s):
buf = b''
buf = b""
while True:
recv = b''
recv = b""
try:
recv = s.recv(1)
except:
@ -72,6 +77,7 @@ def socket_readall(s):
buf += recv
return buf
def request(method, url, data=None, json=None, files=None, headers={}, auth=None, stream=None):
try:
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
elif proto == "https:":
import ussl
port = 443
else:
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)
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_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))
if not "Host" in headers:
if "Host" not in headers:
s.write(b"Host: %s\r\n" % host)
# 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:
import ujson
data = ujson.dumps(json)
s.write(b"Content-Type: application/json\r\n")
if files is not None:
data = bytearray()
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():
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"--%s\r\n" % (boundary)
data += b'Content-Disposition: form-data; name="%s"; filename="%s"\r\n\r\n' % (
name,
fileobj[0],
)
data += fileobj[1].read()
data += b"\r\n"
data += b"\r\n--%s--\r\n"%(boundary)
data += b"\r\n--%s--\r\n" % (boundary)
if 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)
elif l.startswith(b"Location:") and not 200 <= status <= 299:
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)
resp_code = int(sline[1])
resp_reason = sline[2].decode().rstrip() if len(sline) > 2 else ""
continue
resp_headers.append(l)
resp_headers = b'\r\n'.join(resp_headers)
content = b'\r\n'.join(response)
resp_headers = b"\r\n".join(resp_headers)
content = b"\r\n".join(response)
except OSError:
s.close()
raise
return Response(resp_code, resp_reason, resp_headers, content)
def head(url, **kw):
return request("HEAD", url, **kw)
def get(url, **kw):
return request("GET", url, **kw)
def post(url, **kw):
return request("POST", url, **kw)
def put(url, **kw):
return request("PUT", url, **kw)
def patch(url, **kw):
return request("PATCH", url, **kw)
def delete(url, **kw):
return request("DELETE", url, **kw)

View File

@ -10,6 +10,7 @@ from uio import IOBase
last_client_socket = None
server_socket = None
# Provide necessary functions for dupterm and replace telnet control characters that come in.
class TelnetWrapper(IOBase):
def __init__(self, socket):
@ -23,7 +24,7 @@ class TelnetWrapper(IOBase):
byte = 0
# discard telnet control characters and
# null bytes
while(byte == 0):
while byte == 0:
byte = self.socket.recv(1)[0]
if byte == 0xFF:
self.discard_count = 2
@ -63,6 +64,7 @@ class TelnetWrapper(IOBase):
def close(self):
self.socket.close()
# Attach new clients to dupterm and
# send telnet control characters to disable line mode
# and stop local echoing
@ -80,11 +82,12 @@ def accept_telnet_connect(telnet_server):
# dupterm_notify() not available under MicroPython v1.1
# 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, 251, 1])) # turn off local echo
last_client_socket.sendall(bytes([255, 252, 34])) # dont allow line mode
last_client_socket.sendall(bytes([255, 251, 1])) # turn off local echo
uos.dupterm(TelnetWrapper(last_client_socket))
def stop():
global server_socket, last_client_socket
uos.dupterm(None)
@ -93,6 +96,7 @@ def stop():
if last_client_socket:
last_client_socket.close()
# start listening for telnet connections on port 23
def start(port=23):
stop()

View File

@ -1,109 +1,117 @@
import pyb
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, # 0x2f : bit 0 if GPIO 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() */
0x02, # 0x31 : bit 1 = interrupt depending on the polarity, use CheckForDataReady() */
0x00, # 0x32 : not user-modifiable */
0x02, # 0x33 : not user-modifiable */
0x08, # 0x34 : not user-modifiable */
0x00, # 0x35 : not user-modifiable */
0x08, # 0x36 : not user-modifiable */
0x10, # 0x37 : not user-modifiable */
0x01, # 0x38 : not user-modifiable */
0x01, # 0x39 : not user-modifiable */
0x00, # 0x3a : not user-modifiable */
0x00, # 0x3b : not user-modifiable */
0x00, # 0x3c : not user-modifiable */
0x00, # 0x3d : not user-modifiable */
0xff, # 0x3e : not user-modifiable */
0x00, # 0x3f : not user-modifiable */
0x0F, # 0x40 : not user-modifiable */
0x00, # 0x41 : not user-modifiable */
0x00, # 0x42 : not user-modifiable */
0x00, # 0x43 : not user-modifiable */
0x00, # 0x44 : not user-modifiable */
0x00, # 0x45 : 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 */
0x0b, # 0x47 : not user-modifiable */
0x00, # 0x48 : not user-modifiable */
0x00, # 0x49 : not user-modifiable */
0x02, # 0x4a : not user-modifiable */
0x0a, # 0x4b : not user-modifiable */
0x21, # 0x4c : not user-modifiable */
0x00, # 0x4d : not user-modifiable */
0x00, # 0x4e : not user-modifiable */
0x05, # 0x4f : not user-modifiable */
0x00, # 0x50 : not user-modifiable */
0x00, # 0x51 : not user-modifiable */
0x00, # 0x52 : not user-modifiable */
0x00, # 0x53 : not user-modifiable */
0xc8, # 0x54 : not user-modifiable */
0x00, # 0x55 : not user-modifiable */
0x00, # 0x56 : not user-modifiable */
0x38, # 0x57 : not user-modifiable */
0xff, # 0x58 : not user-modifiable */
0x01, # 0x59 : not user-modifiable */
0x00, # 0x5a : not user-modifiable */
0x08, # 0x5b : not user-modifiable */
0x00, # 0x5c : not user-modifiable */
0x00, # 0x5d : not user-modifiable */
0x01, # 0x5e : not user-modifiable */
0xdb, # 0x5f : not user-modifiable */
0x0f, # 0x60 : not user-modifiable */
0x01, # 0x61 : not user-modifiable */
0xf1, # 0x62 : not user-modifiable */
0x0d, # 0x63 : not user-modifiable */
0x01, # 0x64 : Sigma threshold MSB (mm in 14.2 format for MSB+LSB), use SetSigmaThreshold(), default value 90 mm */
0x68, # 0x65 : Sigma threshold LSB */
0x00, # 0x66 : Min count Rate MSB (MCPS in 9.7 format for MSB+LSB), use SetSignalThreshold() */
0x80, # 0x67 : Min count Rate LSB */
0x08, # 0x68 : not user-modifiable */
0xb8, # 0x69 : not user-modifiable */
0x00, # 0x6a : not user-modifiable */
0x00, # 0x6b : not user-modifiable */
0x00, # 0x6c : Intermeasurement period MSB, 32 bits register, use SetIntermeasurementInMs() */
0x00, # 0x6d : Intermeasurement period */
0x0f, # 0x6e : Intermeasurement period */
0x89, # 0x6f : Intermeasurement period LSB */
0x00, # 0x70 : not user-modifiable */
0x00, # 0x71 : not user-modifiable */
0x00, # 0x72 : distance threshold high MSB (in mm, MSB+LSB), use SetD:tanceThreshold() */
0x00, # 0x73 : distance threshold high LSB */
0x00, # 0x74 : distance threshold low MSB ( in mm, MSB+LSB), use SetD:tanceThreshold() */
0x00, # 0x75 : distance threshold low LSB */
0x00, # 0x76 : not user-modifiable */
0x01, # 0x77 : not user-modifiable */
0x0f, # 0x78 : not user-modifiable */
0x0d, # 0x79 : not user-modifiable */
0x0e, # 0x7a : not user-modifiable */
0x0e, # 0x7b : not user-modifiable */
0x00, # 0x7c : not user-modifiable */
0x00, # 0x7d : not user-modifiable */
0x02, # 0x7e : not user-modifiable */
0xc7, # 0x7f : ROI center, use SetROI() */
0xff, # 0x80 : XY ROI (X=Width, Y=Height), use SetROI() */
0x9B, # 0x81 : not user-modifiable */
0x00, # 0x82 : not user-modifiable */
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 */
])
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, # 0x2f : bit 0 if GPIO 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()
0x02, # 0x31 : bit 1 = interrupt depending on the polarity, use CheckForDataReady()
0x00, # 0x32 : not user-modifiable
0x02, # 0x33 : not user-modifiable
0x08, # 0x34 : not user-modifiable
0x00, # 0x35 : not user-modifiable
0x08, # 0x36 : not user-modifiable
0x10, # 0x37 : not user-modifiable
0x01, # 0x38 : not user-modifiable
0x01, # 0x39 : not user-modifiable
0x00, # 0x3a : not user-modifiable
0x00, # 0x3b : not user-modifiable
0x00, # 0x3c : not user-modifiable
0x00, # 0x3d : not user-modifiable
0xFF, # 0x3e : not user-modifiable
0x00, # 0x3f : not user-modifiable
0x0F, # 0x40 : not user-modifiable
0x00, # 0x41 : not user-modifiable
0x00, # 0x42 : not user-modifiable
0x00, # 0x43 : not user-modifiable
0x00, # 0x44 : not user-modifiable
0x00, # 0x45 : 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
0x0B, # 0x47 : not user-modifiable
0x00, # 0x48 : not user-modifiable
0x00, # 0x49 : not user-modifiable
0x02, # 0x4a : not user-modifiable
0x0A, # 0x4b : not user-modifiable
0x21, # 0x4c : not user-modifiable
0x00, # 0x4d : not user-modifiable
0x00, # 0x4e : not user-modifiable
0x05, # 0x4f : not user-modifiable
0x00, # 0x50 : not user-modifiable
0x00, # 0x51 : not user-modifiable
0x00, # 0x52 : not user-modifiable
0x00, # 0x53 : not user-modifiable
0xC8, # 0x54 : not user-modifiable
0x00, # 0x55 : not user-modifiable
0x00, # 0x56 : not user-modifiable
0x38, # 0x57 : not user-modifiable
0xFF, # 0x58 : not user-modifiable
0x01, # 0x59 : not user-modifiable
0x00, # 0x5a : not user-modifiable
0x08, # 0x5b : not user-modifiable
0x00, # 0x5c : not user-modifiable
0x00, # 0x5d : not user-modifiable
0x01, # 0x5e : not user-modifiable
0xDB, # 0x5f : not user-modifiable
0x0F, # 0x60 : not user-modifiable
0x01, # 0x61 : not user-modifiable
0xF1, # 0x62 : not user-modifiable
0x0D, # 0x63 : not user-modifiable
0x01, # 0x64 : Sigma threshold MSB (mm in 14.2 format for MSB+LSB),
# use SetSigmaThreshold(), default value 90 mm
0x68, # 0x65 : Sigma threshold LSB
0x00, # 0x66 : Min count Rate MSB (MCPS in 9.7 format for MSB+LSB), use SetSignalThreshold()
0x80, # 0x67 : Min count Rate LSB
0x08, # 0x68 : not user-modifiable
0xB8, # 0x69 : not user-modifiable
0x00, # 0x6a : not user-modifiable
0x00, # 0x6b : not user-modifiable
0x00, # 0x6c : Intermeasurement period MSB, 32 bits register, use SetIntermeasurementInMs()
0x00, # 0x6d : Intermeasurement period
0x0F, # 0x6e : Intermeasurement period
0x89, # 0x6f : Intermeasurement period LSB
0x00, # 0x70 : not user-modifiable
0x00, # 0x71 : not user-modifiable
0x00, # 0x72 : distance threshold high MSB (in mm, MSB+LSB), use SetD:tanceThreshold()
0x00, # 0x73 : distance threshold high LSB
0x00, # 0x74 : distance threshold low MSB ( in mm, MSB+LSB), use SetD:tanceThreshold()
0x00, # 0x75 : distance threshold low LSB
0x00, # 0x76 : not user-modifiable
0x01, # 0x77 : not user-modifiable
0x0F, # 0x78 : not user-modifiable
0x0D, # 0x79 : not user-modifiable
0x0E, # 0x7a : not user-modifiable
0x0E, # 0x7b : not user-modifiable
0x00, # 0x7c : not user-modifiable
0x00, # 0x7d : not user-modifiable
0x02, # 0x7e : not user-modifiable
0xC7, # 0x7f : ROI center, use SetROI()
0xFF, # 0x80 : XY ROI (X=Width, Y=Height), use SetROI()
0x9B, # 0x81 : not user-modifiable
0x00, # 0x82 : not user-modifiable
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:
def __init__(self,i2c, address=0x29):
def __init__(self, i2c, address=0x29):
self.i2c = i2c
self.address = address
self.reset()
pyb.delay(1)
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
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
# measurement is started; assumes MM1 and MM2 are disabled
self.writeReg16Bit(0x001E, self.readReg16Bit(0x0022) * 4)
@ -111,53 +119,61 @@ class VL53L1X:
def writeReg(self, reg, value):
return self.i2c.writeto_mem(self.address, reg, bytes([value]), addrsize=16)
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):
return self.i2c.readfrom_mem(self.address, reg, 1, addrsize=16)[0]
def readReg16Bit(self, reg):
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):
return self.readReg16Bit(0x010F)
def reset(self):
self.writeReg(0x0000, 0x00)
pyb.delay(100)
self.writeReg(0x0000, 0x01)
def read(self):
data = self.i2c.readfrom_mem(self.address, 0x0089, 17, addrsize=16) # RESULT__RANGE_STATUS
range_status = data[0]
data = self.i2c.readfrom_mem(self.address, 0x0089, 17, addrsize=16) # RESULT__RANGE_STATUS
# range_status = data[0]
# report_status = data[1]
stream_count = data[2]
dss_actual_effective_spads_sd0 = (data[3]<<8) + data[4]
# stream_count = data[2]
# dss_actual_effective_spads_sd0 = (data[3] << 8) + data[4]
# 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]
# phase_sd0 = (data[11]<<8) + data[12]
final_crosstalk_corrected_range_mm_sd0 = (data[13]<<8) + data[14]
peak_signal_count_rate_crosstalk_corrected_mcps_sd0 = (data[15]<<8) + data[16]
#status = None
#if range_status in (17, 2, 1, 3):
#status = "HardwareFail"
#elif range_status == 13:
#status = "MinRangeFail"
#elif range_status == 18:
#status = "SynchronizationInt"
#elif range_status == 5:
#status = "OutOfBoundsFail"
#elif range_status == 4:
#status = "SignalFail"
#elif range_status == 6:
#status = "SignalFail"
#elif range_status == 7:
#status = "WrapTargetFail"
#elif range_status == 12:
#status = "XtalkSignalFail"
#elif range_status == 8:
#status = "RangeValidMinRangeClipped"
#elif range_status == 9:
#if stream_count == 0:
#status = "RangeValidNoWrapCheckFail"
#else:
#status = "OK"
final_crosstalk_corrected_range_mm_sd0 = (data[13] << 8) + data[14]
# peak_signal_count_rate_crosstalk_corrected_mcps_sd0 = (data[15] << 8) + data[16]
# status = None
# if range_status in (17, 2, 1, 3):
# status = "HardwareFail"
# elif range_status == 13:
# status = "MinRangeFail"
# elif range_status == 18:
# status = "SynchronizationInt"
# elif range_status == 5:
# status = "OutOfBoundsFail"
# elif range_status == 4:
# status = "SignalFail"
# elif range_status == 6:
# status = "SignalFail"
# elif range_status == 7:
# status = "WrapTargetFail"
# elif range_status == 12:
# status = "XtalkSignalFail"
# elif range_status == 8:
# status = "RangeValidMinRangeClipped"
# elif range_status == 9:
# if stream_count == 0:
# status = "RangeValidNoWrapCheckFail"
# else:
# status = "OK"
return final_crosstalk_corrected_range_mm_sd0