Merge branch 'master' into master
This commit is contained in:
commit
0288306c32
41 changed files with 1456 additions and 12 deletions
|
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
ESP32BootROM - part of the Firmware Updater for the
|
||||
Arduino MKR WiFi 1010, Arduino MKR Vidor 4000, and Arduino UNO WiFi Rev.2.
|
||||
|
||||
Copyright (c) 2018 Arduino SA. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "ESP32BootROM.h"
|
||||
|
||||
extern ESP32BootROMClass ESP32BootROM;
|
||||
|
||||
//#define DEBUG 1
|
||||
|
||||
ESP32BootROMClass::ESP32BootROMClass(HardwareSerial& serial, int gpio0Pin, int resetnPin) :
|
||||
_serial(&serial),
|
||||
_gpio0Pin(gpio0Pin),
|
||||
_resetnPin(resetnPin)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int ESP32BootROMClass::begin(unsigned long baudrate)
|
||||
{
|
||||
_serial->begin(115200);
|
||||
|
||||
pinMode(_gpio0Pin, OUTPUT);
|
||||
pinMode(_resetnPin, OUTPUT);
|
||||
|
||||
digitalWrite(_gpio0Pin, LOW);
|
||||
|
||||
digitalWrite(_resetnPin, LOW);
|
||||
delay(10);
|
||||
digitalWrite(_resetnPin, HIGH);
|
||||
delay(100);
|
||||
|
||||
int synced = 0;
|
||||
|
||||
for (int retries = 0; !synced && (retries < 5); retries++) {
|
||||
synced = sync();
|
||||
}
|
||||
|
||||
if (!synced) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(ARDUINO_SAMD_MKRVIDOR4000) || defined(ARDUINO_AVR_UNO_WIFI_REV2)
|
||||
(void)baudrate;
|
||||
#else
|
||||
if (baudrate != 115200) {
|
||||
if (!changeBaudrate(baudrate)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
delay(100);
|
||||
|
||||
_serial->end();
|
||||
_serial->begin(baudrate);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!spiAttach()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ESP32BootROMClass::end() {
|
||||
_serial->end();
|
||||
}
|
||||
|
||||
int ESP32BootROMClass::sync()
|
||||
{
|
||||
const uint8_t data[] = {
|
||||
0x07, 0x07, 0x12, 0x20,
|
||||
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55
|
||||
};
|
||||
|
||||
command(0x08, data, sizeof(data));
|
||||
|
||||
int results[8];
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
results[i] = response(0x08, 100);
|
||||
}
|
||||
|
||||
return (results[0] == 0);
|
||||
}
|
||||
|
||||
int ESP32BootROMClass::changeBaudrate(unsigned long baudrate)
|
||||
{
|
||||
const uint32_t data[2] = {
|
||||
baudrate,
|
||||
0
|
||||
};
|
||||
|
||||
command(0x0f, data, sizeof(data));
|
||||
|
||||
return (response(0x0f, 3000) == 0);
|
||||
}
|
||||
|
||||
int ESP32BootROMClass::spiAttach()
|
||||
{
|
||||
const uint8_t data[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
command(0x0d, data, sizeof(data));
|
||||
|
||||
return (response(0x0d, 3000) == 0);
|
||||
}
|
||||
|
||||
int ESP32BootROMClass::beginFlash(uint32_t offset, uint32_t size, uint32_t chunkSize) {
|
||||
const uint32_t data[4] = {
|
||||
size,
|
||||
size / chunkSize,
|
||||
chunkSize,
|
||||
offset
|
||||
};
|
||||
|
||||
command(0x02, data, sizeof(data));
|
||||
|
||||
_flashSequenceNumber = 0;
|
||||
_chunkSize = chunkSize;
|
||||
|
||||
return (response(0x02, 120000) == 0);
|
||||
}
|
||||
|
||||
int ESP32BootROMClass::dataFlash(const void* data, uint32_t length)
|
||||
{
|
||||
uint32_t cmdData[4 + (_chunkSize / 4)];
|
||||
|
||||
cmdData[0] = length;
|
||||
cmdData[1] = _flashSequenceNumber++;
|
||||
cmdData[2] = 0;
|
||||
cmdData[3] = 0;
|
||||
|
||||
memcpy(&cmdData[4], data, length);
|
||||
|
||||
if (length < _chunkSize) {
|
||||
memset(&cmdData[4 + (length / 4)], 0xff, _chunkSize - length);
|
||||
}
|
||||
|
||||
command(0x03, cmdData, sizeof(cmdData));
|
||||
|
||||
return (response(0x03, 3000) == 0);
|
||||
}
|
||||
|
||||
int ESP32BootROMClass::endFlash(uint32_t reboot) {
|
||||
const uint32_t data[1] = {
|
||||
reboot
|
||||
};
|
||||
|
||||
command(0x04, data, sizeof(data));
|
||||
|
||||
return (response(0x04, 3000) == 0);
|
||||
}
|
||||
|
||||
int ESP32BootROMClass::md5Flash(uint32_t offset, uint32_t size, uint8_t* result)
|
||||
{
|
||||
const uint32_t data[4] = {
|
||||
offset,
|
||||
size,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
command(0x13, data, sizeof(data));
|
||||
|
||||
uint8_t asciiResult[32];
|
||||
|
||||
if (response(0x13, 3000, asciiResult) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char temp[3] = { 0, 0, 0 };
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
temp[0] = asciiResult[i * 2];
|
||||
temp[1] = asciiResult[i * 2 + 1];
|
||||
|
||||
result[i] = strtoul(temp, NULL, 16);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ESP32BootROMClass::command(int opcode, const void* data, uint16_t length)
|
||||
{
|
||||
uint32_t checksum = 0;
|
||||
|
||||
if (opcode == 0x03) {
|
||||
checksum = 0xef; // seed
|
||||
|
||||
for (uint16_t i = 16; i < length; i++) {
|
||||
checksum ^= ((const uint8_t*)data)[i];
|
||||
}
|
||||
}
|
||||
|
||||
_serial->write(0xc0);
|
||||
_serial->write((uint8_t)0x00); // direction
|
||||
_serial->write(opcode);
|
||||
_serial->write((uint8_t*)&length, sizeof(length));
|
||||
writeEscapedBytes((uint8_t*)&checksum, sizeof(checksum));
|
||||
writeEscapedBytes((uint8_t*)data, length);
|
||||
_serial->write(0xc0);
|
||||
#ifdef ARDUINO_SAMD_MKRVIDOR4000
|
||||
// _serial->flush(); // doesn't work!
|
||||
#else
|
||||
_serial->flush();
|
||||
#endif
|
||||
}
|
||||
|
||||
int ESP32BootROMClass::response(int opcode, unsigned long timeout, void* body)
|
||||
{
|
||||
uint8_t data[10 + 256];
|
||||
uint16_t index = 0;
|
||||
|
||||
uint8_t responseLength = 4;
|
||||
|
||||
for (unsigned long start = millis(); (index < (uint16_t)(10 + responseLength)) && (millis() - start) < timeout;) {
|
||||
if (_serial->available()) {
|
||||
data[index] = _serial->read();
|
||||
|
||||
if (index == 3) {
|
||||
responseLength = data[index];
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (index) {
|
||||
for (int i = 0; i < index; i++) {
|
||||
byte b = data[i];
|
||||
|
||||
if (b < 0x10) {
|
||||
Serial.print('0');
|
||||
}
|
||||
|
||||
Serial.print(b, HEX);
|
||||
Serial.print(' ');
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (index != (uint16_t)(10 + responseLength)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data[0] != 0xc0 || data[1] != 0x01 || data[2] != opcode || data[responseLength + 5] != 0x00 || data[responseLength + 6] != 0x00 || data[responseLength + 9] != 0xc0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (body) {
|
||||
memcpy(body, &data[9], responseLength - 4);
|
||||
}
|
||||
|
||||
return data[responseLength + 5];
|
||||
}
|
||||
|
||||
void ESP32BootROMClass::writeEscapedBytes(const uint8_t* data, uint16_t length)
|
||||
{
|
||||
uint16_t written = 0;
|
||||
|
||||
while (written < length) {
|
||||
uint8_t b = data[written++];
|
||||
|
||||
if (b == 0xdb) {
|
||||
_serial->write(0xdb);
|
||||
_serial->write(0xdd);
|
||||
} else if (b == 0xc0) {
|
||||
_serial->write(0xdb);
|
||||
_serial->write(0xdc);
|
||||
} else {
|
||||
_serial->write(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
ESP32BootROM - part of the Firmware Updater for the
|
||||
Arduino MKR WiFi 1010, Arduino MKR Vidor 4000, and Arduino UNO WiFi Rev.2.
|
||||
|
||||
Copyright (c) 2018 Arduino SA. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
class ESP32BootROMClass {
|
||||
public:
|
||||
ESP32BootROMClass(HardwareSerial& hwSerial, int gpio0Pin, int resetnPin);
|
||||
|
||||
int begin(unsigned long baudrate);
|
||||
void end();
|
||||
|
||||
int beginFlash(uint32_t offset, uint32_t size, uint32_t chunkSize);
|
||||
int dataFlash(const void* data, uint32_t length);
|
||||
int endFlash(uint32_t reboot);
|
||||
|
||||
int md5Flash(uint32_t offset, uint32_t size, uint8_t* result);
|
||||
|
||||
private:
|
||||
int sync();
|
||||
int changeBaudrate(unsigned long baudrate);
|
||||
int spiAttach();
|
||||
|
||||
void command(int opcode, const void* data, uint16_t length);
|
||||
int response(int opcode, unsigned long timeout, void* body = NULL);
|
||||
|
||||
void writeEscapedBytes(const uint8_t* data, uint16_t length);
|
||||
|
||||
private:
|
||||
HardwareSerial* _serial;
|
||||
int _gpio0Pin;
|
||||
int _resetnPin;
|
||||
|
||||
uint32_t _flashSequenceNumber;
|
||||
uint32_t _chunkSize;
|
||||
};
|
||||
|
||||
extern ESP32BootROMClass ESP32BootROM;
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
FirmwareUpdater - Firmware Updater for the
|
||||
Arduino MKR WiFi 1010, Arduino MKR Vidor 4000, and Arduino UNO WiFi Rev.2.
|
||||
|
||||
Copyright (c) 2018 Arduino SA. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "ESP32BootROM.h"
|
||||
#include "SdFat.h"
|
||||
#include "Adafruit_SPIFlash.h"
|
||||
|
||||
#if defined(ADAFRUIT_FEATHER_M4_EXPRESS) || \
|
||||
defined(ADAFRUIT_FEATHER_M0_EXPRESS) || \
|
||||
defined(ARDUINO_NRF52840_FEATHER) || \
|
||||
defined(ADAFRUIT_ITSYBITSY_M0_EXPRESS) || \
|
||||
defined(ADAFRUIT_ITSYBITSY_M4_EXPRESS)
|
||||
|
||||
#define SerialESP32 Serial1
|
||||
#define SPIWIFI SPI // The SPI port
|
||||
#define SPIWIFI_SS 13 // Chip select pin
|
||||
#define ESP32_RESETN 12 // Reset pin
|
||||
#define SPIWIFI_ACK 11 // a.k.a BUSY or READY pin
|
||||
#define ESP32_GPIO0 10
|
||||
#define NEOPIXEL_PIN 8
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(EXTERNAL_FLASH_USE_QSPI)
|
||||
Adafruit_FlashTransport_QSPI flashTransport;
|
||||
|
||||
#elif defined(EXTERNAL_FLASH_USE_SPI)
|
||||
Adafruit_FlashTransport_SPI flashTransport(EXTERNAL_FLASH_USE_CS, EXTERNAL_FLASH_USE_SPI);
|
||||
|
||||
#else
|
||||
#error No QSPI/SPI flash are defined on your board variant.h !
|
||||
#endif
|
||||
|
||||
Adafruit_SPIFlash flash(&flashTransport);
|
||||
|
||||
// file system object from SdFat
|
||||
FatFileSystem fatfs;
|
||||
|
||||
static const int MAX_PAYLOAD_SIZE = 1024;
|
||||
uint32_t firmsize;
|
||||
static uint8_t payload[MAX_PAYLOAD_SIZE];
|
||||
|
||||
File myFile;
|
||||
|
||||
ESP32BootROMClass ESP32BootROM(SerialESP32, ESP32_GPIO0, ESP32_RESETN);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
delay(100);
|
||||
|
||||
Serial.print("Initializing Filesystem on external flash...");
|
||||
flash.begin(); // Init external flash
|
||||
|
||||
Serial.print("JEDEC ID: "); Serial.println(flash.getJEDECID(), HEX);
|
||||
Serial.print("Flash size: "); Serial.println(flash.size());
|
||||
|
||||
if (!fatfs.begin(&flash)) { // Init file system on the flash
|
||||
Serial.println("FLASH init. failed!");
|
||||
while (1);
|
||||
}
|
||||
|
||||
|
||||
myFile = fatfs.open("/NINA HCI BT.bin", FILE_READ);
|
||||
if (!myFile) {
|
||||
Serial.println("Failed to open firmware file");
|
||||
while (1);
|
||||
}
|
||||
firmsize = myFile.size();
|
||||
Serial.print(firmsize); Serial.println(" bytes");
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
while (!ESP32BootROM.begin(921600)) {
|
||||
Serial.println("Unable to communicate with ESP32 boot ROM!");
|
||||
delay(100);
|
||||
return;
|
||||
}
|
||||
Serial.println("Ready!");
|
||||
|
||||
uint32_t timestamp = millis();
|
||||
|
||||
while (!ESP32BootROM.beginFlash(0, firmsize, MAX_PAYLOAD_SIZE)) {
|
||||
Serial.println("Failed to erase flash");
|
||||
delay(100);
|
||||
return;
|
||||
}
|
||||
Serial.println("Erase OK");
|
||||
|
||||
for (uint32_t i=0; i<firmsize; i+=MAX_PAYLOAD_SIZE) {
|
||||
memset(payload, 0xFF, MAX_PAYLOAD_SIZE);
|
||||
uint32_t num_read = myFile.read(&payload, MAX_PAYLOAD_SIZE);
|
||||
Serial.print("Packet #"); Serial.print(i/MAX_PAYLOAD_SIZE); Serial.print(": ");
|
||||
Serial.print(num_read); Serial.print(" byte payload...");
|
||||
|
||||
if (!ESP32BootROM.dataFlash(payload, MAX_PAYLOAD_SIZE)) {
|
||||
Serial.print("Failed to flash data");
|
||||
while (1);
|
||||
} else {
|
||||
Serial.println("OK");
|
||||
}
|
||||
}
|
||||
|
||||
myFile.close();
|
||||
|
||||
uint8_t md5[16];
|
||||
if (!ESP32BootROM.md5Flash(0, firmsize, md5)) {
|
||||
Serial.println("Error calculating MD5");
|
||||
} else {
|
||||
Serial.print("MD5 OK: ");
|
||||
for (int i=0; i<16; i++) {
|
||||
Serial.print("0x"); Serial.print(md5[i], HEX); Serial.print(" ");
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
Serial.print("Took "); Serial.print(millis()-timestamp); Serial.println(" millis");
|
||||
while (1);
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
Endianess.ino - Network byte order conversion functions.
|
||||
Copyright (c) 2015 Arduino LLC. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <Arduino.h>
|
||||
|
||||
bool isBigEndian() {
|
||||
uint32_t test = 0x11223344;
|
||||
uint8_t *pTest = reinterpret_cast<uint8_t *>(&test);
|
||||
return pTest[0] == 0x11;
|
||||
}
|
||||
|
||||
uint32_t fromNetwork32(uint32_t from) {
|
||||
static const bool be = isBigEndian();
|
||||
if (be) {
|
||||
return from;
|
||||
} else {
|
||||
uint8_t *pFrom = reinterpret_cast<uint8_t *>(&from);
|
||||
uint32_t to;
|
||||
to = pFrom[0]; to <<= 8;
|
||||
to |= pFrom[1]; to <<= 8;
|
||||
to |= pFrom[2]; to <<= 8;
|
||||
to |= pFrom[3];
|
||||
return to;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t fromNetwork16(uint16_t from) {
|
||||
static bool be = isBigEndian();
|
||||
if (be) {
|
||||
return from;
|
||||
} else {
|
||||
uint8_t *pFrom = reinterpret_cast<uint8_t *>(&from);
|
||||
uint16_t to;
|
||||
to = pFrom[0]; to <<= 8;
|
||||
to |= pFrom[1];
|
||||
return to;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t toNetwork32(uint32_t to) {
|
||||
return fromNetwork32(to);
|
||||
}
|
||||
|
||||
uint16_t toNetwork16(uint16_t to) {
|
||||
return fromNetwork16(to);
|
||||
}
|
||||
|
|
@ -71,8 +71,12 @@ unsigned long baud = 115200;
|
|||
#define ESP32_RESETN 5 // Reset pin
|
||||
#define ESP32_GPIO0 -1 // Not connected
|
||||
#define NEOPIXEL_PIN 8
|
||||
#elif defined(ADAFRUIT_PYPORTAL)
|
||||
#endif
|
||||
|
||||
#if defined(ADAFRUIT_PYPORTAL)
|
||||
#define NEOPIXEL_PIN 2
|
||||
#elif defined(ADAFRUIT_METRO_M4_AIRLIFT_LITE)
|
||||
#define NEOPIXEL_PIN 40
|
||||
#endif
|
||||
|
||||
Adafruit_NeoPixel pixel = Adafruit_NeoPixel(1, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,156 @@
|
|||
#include <Adafruit_APDS9960.h>
|
||||
#include <Adafruit_BMP280.h>
|
||||
#include <Adafruit_LIS3MDL.h>
|
||||
#include <Adafruit_LSM6DS33.h>
|
||||
#include <Adafruit_SHT31.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <PDM.h>
|
||||
|
||||
Adafruit_APDS9960 apds9960; // proximity, light, color, gesture
|
||||
Adafruit_BMP280 bmp280; // temperautre, barometric pressure
|
||||
Adafruit_LIS3MDL lis3mdl; // magnetometer
|
||||
Adafruit_LSM6DS33 lsm6ds33; // accelerometer, gyroscope
|
||||
Adafruit_SHT31 sht30; // humidity
|
||||
|
||||
uint8_t proximity;
|
||||
uint16_t r, g, b, c;
|
||||
float temperature, pressure, altitude;
|
||||
float magnetic_x, magnetic_y, magnetic_z;
|
||||
float accel_x, accel_y, accel_z;
|
||||
float gyro_x, gyro_y, gyro_z;
|
||||
float humidity;
|
||||
int32_t mic;
|
||||
|
||||
extern PDMClass PDM;
|
||||
short sampleBuffer[256]; // buffer to read samples into, each sample is 16-bits
|
||||
volatile int samplesRead; // number of samples read
|
||||
|
||||
void setup(void) {
|
||||
Serial.begin(115200);
|
||||
// while (!Serial) delay(10);
|
||||
Serial.println("Feather Sense Sensor Demo");
|
||||
|
||||
// initialize the sensors
|
||||
apds9960.begin();
|
||||
apds9960.enableProximity(true);
|
||||
apds9960.enableColor(true);
|
||||
bmp280.begin();
|
||||
lis3mdl.begin_I2C();
|
||||
lsm6ds33.begin_I2C();
|
||||
sht30.begin();
|
||||
PDM.onReceive(onPDMdata);
|
||||
PDM.begin(1, 16000);
|
||||
}
|
||||
|
||||
void loop(void) {
|
||||
proximity = apds9960.readProximity();
|
||||
while (!apds9960.colorDataReady()) {
|
||||
delay(5);
|
||||
}
|
||||
apds9960.getColorData(&r, &g, &b, &c);
|
||||
|
||||
temperature = bmp280.readTemperature();
|
||||
pressure = bmp280.readPressure();
|
||||
altitude = bmp280.readAltitude(1013.25);
|
||||
|
||||
lis3mdl.read();
|
||||
magnetic_x = lis3mdl.x;
|
||||
magnetic_y = lis3mdl.y;
|
||||
magnetic_z = lis3mdl.z;
|
||||
|
||||
sensors_event_t accel;
|
||||
sensors_event_t gyro;
|
||||
sensors_event_t temp;
|
||||
lsm6ds33.getEvent(&accel, &gyro, &temp);
|
||||
accel_x = accel.acceleration.x;
|
||||
accel_y = accel.acceleration.y;
|
||||
accel_z = accel.acceleration.z;
|
||||
gyro_x = gyro.gyro.x;
|
||||
gyro_y = gyro.gyro.y;
|
||||
gyro_z = gyro.gyro.z;
|
||||
|
||||
humidity = sht30.readHumidity();
|
||||
|
||||
samplesRead = 0;
|
||||
mic = getPDMwave(4000);
|
||||
|
||||
Serial.println("\nFeather Sense Sensor Demo");
|
||||
Serial.println("---------------------------------------------");
|
||||
Serial.print("Proximity: ");
|
||||
Serial.println(apds9960.readProximity());
|
||||
Serial.print("Red: ");
|
||||
Serial.print(r);
|
||||
Serial.print(" Green: ");
|
||||
Serial.print(g);
|
||||
Serial.print(" Blue :");
|
||||
Serial.print(b);
|
||||
Serial.print(" Clear: ");
|
||||
Serial.println(c);
|
||||
Serial.print("Temperature: ");
|
||||
Serial.print(temperature);
|
||||
Serial.println(" C");
|
||||
Serial.print("Barometric pressure: ");
|
||||
Serial.println(pressure);
|
||||
Serial.print("Altitude: ");
|
||||
Serial.print(altitude);
|
||||
Serial.println(" m");
|
||||
Serial.print("Magnetic: ");
|
||||
Serial.print(magnetic_x);
|
||||
Serial.print(" ");
|
||||
Serial.print(magnetic_y);
|
||||
Serial.print(" ");
|
||||
Serial.print(magnetic_z);
|
||||
Serial.println(" uTesla");
|
||||
Serial.print("Acceleration: ");
|
||||
Serial.print(accel_x);
|
||||
Serial.print(" ");
|
||||
Serial.print(accel_y);
|
||||
Serial.print(" ");
|
||||
Serial.print(accel_z);
|
||||
Serial.println(" m/s^2");
|
||||
Serial.print("Gyro: ");
|
||||
Serial.print(gyro_x);
|
||||
Serial.print(" ");
|
||||
Serial.print(gyro_y);
|
||||
Serial.print(" ");
|
||||
Serial.print(gyro_z);
|
||||
Serial.println(" dps");
|
||||
Serial.print("Humidity: ");
|
||||
Serial.print(humidity);
|
||||
Serial.println(" %");
|
||||
Serial.print("Mic: ");
|
||||
Serial.println(mic);
|
||||
delay(300);
|
||||
}
|
||||
|
||||
/*****************************************************************/
|
||||
int32_t getPDMwave(int32_t samples) {
|
||||
short minwave = 30000;
|
||||
short maxwave = -30000;
|
||||
|
||||
while (samples > 0) {
|
||||
if (!samplesRead) {
|
||||
yield();
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < samplesRead; i++) {
|
||||
minwave = min(sampleBuffer[i], minwave);
|
||||
maxwave = max(sampleBuffer[i], maxwave);
|
||||
samples--;
|
||||
}
|
||||
// clear the read count
|
||||
samplesRead = 0;
|
||||
}
|
||||
return maxwave - minwave;
|
||||
}
|
||||
|
||||
void onPDMdata() {
|
||||
// query the number of bytes available
|
||||
int bytesAvailable = PDM.available();
|
||||
|
||||
// read into the sample buffer
|
||||
PDM.read(sampleBuffer, bytesAvailable);
|
||||
|
||||
// 16-bit, 2 bytes per sample
|
||||
samplesRead = bytesAvailable / 2;
|
||||
}
|
||||
|
|
@ -6,8 +6,11 @@ To be used with another Circuit Playground Bluefruit running the Remote Control
|
|||
import board
|
||||
import neopixel
|
||||
from adafruit_circuitplayground.bluefruit import cpb
|
||||
from adafruit_led_animation.animation import Blink, Comet, Sparkle, AnimationGroup,\
|
||||
AnimationSequence
|
||||
from adafruit_led_animation.animation.blink import Blink
|
||||
from adafruit_led_animation.animation.comet import Comet
|
||||
from adafruit_led_animation.animation.sparkle import Sparkle
|
||||
from adafruit_led_animation.group import AnimationGroup
|
||||
from adafruit_led_animation.sequence import AnimationSequence
|
||||
import adafruit_led_animation.color as color
|
||||
|
||||
from adafruit_ble import BLERadio
|
||||
|
|
|
|||
183
Lucio_Blaster_2020/lucio_blaster_2020.py
Normal file
183
Lucio_Blaster_2020/lucio_blaster_2020.py
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
# Lucio 2020
|
||||
# Feather M4 + Propmaker + amps + lots of neopixels
|
||||
import board
|
||||
import busio
|
||||
from digitalio import DigitalInOut, Direction, Pull
|
||||
import audioio
|
||||
import audiomixer
|
||||
import audiomp3
|
||||
import adafruit_lis3dh
|
||||
import neopixel
|
||||
from adafruit_led_animation.animation.solid import Solid
|
||||
from adafruit_led_animation.animation.comet import Comet
|
||||
from adafruit_led_animation.animation.pulse import Pulse
|
||||
from adafruit_led_animation.helper import PixelSubset
|
||||
from adafruit_led_animation.group import AnimationGroup
|
||||
from adafruit_led_animation.color import RED, ORANGE, WHITE
|
||||
|
||||
ORANGE_DIM = 0x801400 # half value version
|
||||
RED_DIM = 0x800000
|
||||
|
||||
# ---Set Volume Max Here---
|
||||
VOLUME_MULT = 0.65 # 1 = full volume, 0.1 is very quiet, 0 is muted
|
||||
|
||||
# ---SWITCH/BUTTON SETUP---
|
||||
mode_switch = DigitalInOut(board.D9)
|
||||
mode_switch.switch_to_input(pull=Pull.UP)
|
||||
mode_state = mode_switch.value
|
||||
trig_button = DigitalInOut(board.A4)
|
||||
trig_button.switch_to_input(pull=Pull.UP)
|
||||
alt_button = DigitalInOut(board.A5)
|
||||
alt_button.switch_to_input(pull=Pull.UP)
|
||||
|
||||
# ---ACCELEROMETER SETUP---
|
||||
# Set up accelerometer on I2C bus, 4G range:
|
||||
i2c = busio.I2C(board.SCL, board.SDA)
|
||||
int1 = DigitalInOut(board.D6)
|
||||
accel = adafruit_lis3dh.LIS3DH_I2C(i2c, int1=int1)
|
||||
|
||||
# ---SPEAKER SETUP---
|
||||
enable = DigitalInOut(board.D10)
|
||||
enable.direction = Direction.OUTPUT
|
||||
enable.value = True
|
||||
# Set up speakers and mixer. Stereo files, where music has empty right channel, FX empty left
|
||||
speaker = audioio.AudioOut(board.A0, right_channel=board.A1)
|
||||
mixer = audiomixer.Mixer(channel_count=2, buffer_size=2304, sample_rate=22050)
|
||||
|
||||
# ---NEOPIXEL SETUP---
|
||||
pixel_pin = board.D5
|
||||
pixel_num = 154
|
||||
pixels = neopixel.NeoPixel(
|
||||
pixel_pin, pixel_num, brightness=0.6, auto_write=False, pixel_order=neopixel.GRBW
|
||||
)
|
||||
# ^ change pixel_order depending on RGB vs. RGBW pixels
|
||||
|
||||
|
||||
# ---Pixel Map---
|
||||
# this is the physical order in which the strips are plugged
|
||||
pixel_stripA = PixelSubset(pixels, 0, 18) # 18 pixel strip
|
||||
pixel_stripB = PixelSubset(pixels, 18, 36) # 18 pixel strip
|
||||
pixel_jewel = PixelSubset(pixels, 36, 43) # 7 pixel jewel
|
||||
pixel_ringsAll = PixelSubset(pixels, 43, 151) # all of the rings
|
||||
# or use rings individually:
|
||||
# pixel_ringA = PixelSubset(pixels, 43, 59) # 16 pixel ring
|
||||
# pixel_ringB = PixelSubset(pixels, 59, 75) # 16 pixel ring
|
||||
# pixel_ringC = PixelSubset(pixels, 75, 91) # 16 pixel ring
|
||||
# pixel_ringD = PixelSubset(pixels, 91, 151) # 60 pixel ring
|
||||
|
||||
# ---BPM---
|
||||
BPM = 128
|
||||
BEAT = 60 / BPM # quarter note beat
|
||||
b16TH = BEAT / 4 # 16TH note
|
||||
b64TH = BEAT / 16 # sixty-fourth
|
||||
|
||||
# ---Anim Setup---
|
||||
# heal color mode
|
||||
# Pulse 'speed' = smoothness
|
||||
pulse_rings_m0 = Pulse(pixel_ringsAll, speed=0.01, color=ORANGE, period=BEAT)
|
||||
pulse_jewel_m0 = Pulse(pixel_jewel, speed=0.01, color=ORANGE, period=BEAT)
|
||||
comet_stripA_m0 = Comet(
|
||||
pixel_stripA, speed=b64TH, color=ORANGE, tail_length=9, bounce=False
|
||||
)
|
||||
comet_stripB_m0 = Comet(
|
||||
pixel_stripB, speed=b64TH, color=ORANGE, tail_length=9, bounce=False
|
||||
)
|
||||
|
||||
# speed color mode
|
||||
pulse_rings_m1 = Pulse(pixel_ringsAll, speed=0.02, color=RED, period=BEAT / 2)
|
||||
pulse_jewel_m1 = Pulse(pixel_jewel, speed=0.02, color=RED, period=BEAT / 2)
|
||||
comet_stripA_m1 = Comet(
|
||||
pixel_stripA, speed=b64TH, color=RED, tail_length=9, bounce=False
|
||||
)
|
||||
comet_stripB_m1 = Comet(
|
||||
pixel_stripB, speed=b64TH, color=RED, tail_length=9, bounce=False
|
||||
)
|
||||
|
||||
solid_white = Solid(pixel_ringsAll, color=WHITE)
|
||||
|
||||
# ---Anim Modes---
|
||||
vu_strip_animations_mode0 = AnimationGroup(comet_stripA_m0, comet_stripB_m0, sync=True)
|
||||
vu_strip_animations_mode1 = AnimationGroup(comet_stripA_m1, comet_stripB_m1, sync=True)
|
||||
|
||||
# ---Audio Setup---
|
||||
if mode_state:
|
||||
BGM = "/lucio/bgmheal.mp3"
|
||||
else:
|
||||
BGM = "/lucio/bgmspeed.mp3"
|
||||
sample0 = audiomp3.MP3Decoder(open(BGM, "rb"))
|
||||
FX = "/lucio/shoot.mp3"
|
||||
sample1 = audiomp3.MP3Decoder(open(FX, "rb"))
|
||||
speaker.play(mixer)
|
||||
mixer.voice[0].play(sample0, loop=True)
|
||||
mixer.voice[0].level = 0.3 * VOLUME_MULT
|
||||
mixer.voice[1].level = 0.7 * VOLUME_MULT
|
||||
|
||||
|
||||
while True:
|
||||
if mode_state: # heal mode on startup
|
||||
vu_strip_animations_mode0.animate()
|
||||
pulse_rings_m0.animate()
|
||||
pulse_jewel_m0.animate()
|
||||
else: # speed mode on startup
|
||||
vu_strip_animations_mode1.animate()
|
||||
pulse_rings_m1.animate()
|
||||
pulse_jewel_m1.animate()
|
||||
|
||||
# Change modes
|
||||
if mode_switch.value:
|
||||
if mode_state == 0: # state has changed, toggle it
|
||||
BGM = "/lucio/bgmheal.mp3"
|
||||
sample0.file = open(BGM, "rb")
|
||||
mixer.voice[0].play(sample0, loop=True)
|
||||
vu_strip_animations_mode0.animate()
|
||||
pulse_rings_m0.animate()
|
||||
pulse_jewel_m0.animate()
|
||||
mode_state = 1
|
||||
else:
|
||||
if mode_state == 1:
|
||||
BGM = "/lucio/bgmspeed.mp3"
|
||||
sample0.file = open(BGM, "rb")
|
||||
mixer.voice[0].play(sample0, loop=True)
|
||||
vu_strip_animations_mode1.animate()
|
||||
pulse_rings_m1.animate()
|
||||
pulse_jewel_m1.animate()
|
||||
mode_state = 0
|
||||
|
||||
x, _, _ = accel.acceleration # get accelerometer values
|
||||
|
||||
if not mixer.voice[1].playing:
|
||||
if not trig_button.value: # trigger squeezed
|
||||
FX_sample = "/lucio/shoot.mp3"
|
||||
sample1.file = open(FX_sample, "rb")
|
||||
mixer.voice[1].play(sample1)
|
||||
if mode_state:
|
||||
solid_white.animate()
|
||||
else:
|
||||
solid_white.animate()
|
||||
|
||||
if not alt_button.value: # alt trigger squeezed
|
||||
FX_sample = "/lucio/alt_shoot.mp3"
|
||||
sample1.file = open(FX_sample, "rb")
|
||||
mixer.voice[1].play(sample1)
|
||||
if mode_state:
|
||||
solid_white.animate()
|
||||
else:
|
||||
solid_white.animate()
|
||||
|
||||
if accel.acceleration.x > 8: # reload
|
||||
FX_sample = "/lucio/reload.mp3"
|
||||
sample1.file = open(FX_sample, "rb")
|
||||
mixer.voice[1].play(sample1)
|
||||
if mode_state:
|
||||
solid_white.animate()
|
||||
else:
|
||||
solid_white.animate()
|
||||
|
||||
if accel.acceleration.x < -8: # Ultimate
|
||||
FX_sample = "/lucio/ultimate.mp3"
|
||||
sample1.file = open(FX_sample, "rb")
|
||||
mixer.voice[1].play(sample1)
|
||||
if mode_state:
|
||||
solid_white.animate()
|
||||
else:
|
||||
solid_white.animate()
|
||||
391
PyBadge_Blinka_Jump_Game/code.py
Normal file
391
PyBadge_Blinka_Jump_Game/code.py
Normal file
|
|
@ -0,0 +1,391 @@
|
|||
import time
|
||||
from random import randint
|
||||
from micropython import const
|
||||
import board
|
||||
import terminalio
|
||||
import displayio
|
||||
import adafruit_imageload
|
||||
import digitalio
|
||||
import simpleio
|
||||
from gamepadshift import GamePadShift
|
||||
from adafruit_display_text import label
|
||||
|
||||
# setup for PyBadge buttons
|
||||
BUTTON_LEFT = const(128)
|
||||
BUTTON_UP = const(64)
|
||||
BUTTON_DOWN = const(32)
|
||||
BUTTON_RIGHT = const(16)
|
||||
BUTTON_SEL = const(8)
|
||||
BUTTON_START = const(4)
|
||||
BUTTON_A = const(2)
|
||||
BUTTON_B = const(1)
|
||||
|
||||
pad = GamePadShift(digitalio.DigitalInOut(board.BUTTON_CLOCK),
|
||||
digitalio.DigitalInOut(board.BUTTON_OUT),
|
||||
digitalio.DigitalInOut(board.BUTTON_LATCH))
|
||||
|
||||
current_buttons = pad.get_pressed()
|
||||
last_read = 0
|
||||
|
||||
# enables speaker
|
||||
speakerEnable = digitalio.DigitalInOut(board.SPEAKER_ENABLE)
|
||||
speakerEnable.switch_to_output(value=True)
|
||||
|
||||
# Sprite cell values
|
||||
EMPTY = 0
|
||||
BLINKA_1 = 1
|
||||
BLINKA_2 = 2
|
||||
SPARKY = 3
|
||||
HEART = 4
|
||||
JUMP_1 = 5
|
||||
JUMP_2 = 6
|
||||
|
||||
# creates display
|
||||
display = board.DISPLAY
|
||||
# scale=2 allows the sprites to be bigger
|
||||
group = displayio.Group(max_size=30, scale=2)
|
||||
|
||||
# Blinka sprite setup
|
||||
blinka, blinka_pal = adafruit_imageload.load("/spritesNew.bmp",
|
||||
bitmap=displayio.Bitmap,
|
||||
palette=displayio.Palette)
|
||||
|
||||
# creates a transparent background for Blinka
|
||||
blinka_pal.make_transparent(7)
|
||||
blinka_grid = displayio.TileGrid(blinka, pixel_shader=blinka_pal,
|
||||
width=2, height=1,
|
||||
tile_height=16, tile_width=16,
|
||||
default_tile=EMPTY)
|
||||
blinka_grid.x = 0
|
||||
blinka_grid.y = 32
|
||||
|
||||
blinka_group = displayio.Group()
|
||||
blinka_group.append(blinka_grid)
|
||||
|
||||
# first Sparky sprite
|
||||
sparky0, sparky0_pal = adafruit_imageload.load("/spritesNew.bmp",
|
||||
bitmap=displayio.Bitmap,
|
||||
palette=displayio.Palette)
|
||||
sparky0_pal.make_transparent(7)
|
||||
sparky0_grid = displayio.TileGrid(sparky0, pixel_shader=sparky0_pal,
|
||||
width=1, height=1,
|
||||
tile_height=16, tile_width=16,
|
||||
default_tile=SPARKY)
|
||||
# all Sparky sprites begin off screen
|
||||
sparky0_grid.x = 100
|
||||
sparky0_grid.y = 32
|
||||
|
||||
sparky0_group = displayio.Group()
|
||||
sparky0_group.append(sparky0_grid)
|
||||
|
||||
# 2nd Sparky sprite
|
||||
sparky1, sparky1_pal = adafruit_imageload.load("/spritesNew.bmp",
|
||||
bitmap=displayio.Bitmap,
|
||||
palette=displayio.Palette)
|
||||
sparky1_pal.make_transparent(7)
|
||||
sparky1_grid = displayio.TileGrid(sparky1, pixel_shader=sparky1_pal,
|
||||
width=1, height=1,
|
||||
tile_height=16, tile_width=16,
|
||||
default_tile=SPARKY)
|
||||
sparky1_grid.x = 100
|
||||
sparky1_grid.y = 32
|
||||
|
||||
sparky1_group = displayio.Group()
|
||||
sparky1_group.append(sparky1_grid)
|
||||
|
||||
# 3rd Sparky sprite
|
||||
sparky2, sparky2_pal = adafruit_imageload.load("/spritesNew.bmp",
|
||||
bitmap=displayio.Bitmap,
|
||||
palette=displayio.Palette)
|
||||
sparky2_pal.make_transparent(7)
|
||||
sparky2_grid = displayio.TileGrid(sparky2, pixel_shader=sparky2_pal,
|
||||
width=1, height=1,
|
||||
tile_height=16, tile_width=16,
|
||||
default_tile=SPARKY)
|
||||
sparky2_grid.x = 100
|
||||
sparky2_grid.y = 32
|
||||
|
||||
sparky2_group = displayio.Group()
|
||||
sparky2_group.append(sparky2_grid)
|
||||
|
||||
# heart sprite group
|
||||
life_bit, life_pal = adafruit_imageload.load("/spritesNew.bmp",
|
||||
bitmap=displayio.Bitmap,
|
||||
palette=displayio.Palette)
|
||||
life_grid = displayio.TileGrid(life_bit, pixel_shader=life_pal,
|
||||
width=3, height=1,
|
||||
tile_height=16, tile_width=16,
|
||||
default_tile=HEART)
|
||||
|
||||
life_group = displayio.Group()
|
||||
life_group.append(life_grid)
|
||||
|
||||
# adding all graphics groups to the main display group
|
||||
group.append(blinka_group)
|
||||
group.append(sparky0_group)
|
||||
group.append(sparky1_group)
|
||||
group.append(sparky2_group)
|
||||
group.append(life_group)
|
||||
|
||||
# text area for the running score
|
||||
score_text = " "
|
||||
font = terminalio.FONT
|
||||
score_color = 0x0000FF
|
||||
|
||||
# text for "game over" graphic
|
||||
game_over_text = label.Label(font, text = " ", color = 0xFF00FF)
|
||||
# score text
|
||||
score_area = label.Label(font, text=score_text, color=score_color)
|
||||
# text for "new game" graphic
|
||||
new_game_text = label.Label(font, text = " ", color = 0xFF00FF)
|
||||
|
||||
# coordinants for text areas
|
||||
score_area.x = 57
|
||||
score_area.y = 6
|
||||
game_over_text.x = 13
|
||||
game_over_text.y = 30
|
||||
new_game_text.x = 8
|
||||
new_game_text.y = 30
|
||||
# creating a text display group
|
||||
text_group = displayio.Group()
|
||||
text_group.append(score_area)
|
||||
text_group.append(game_over_text)
|
||||
text_group.append(new_game_text)
|
||||
# adding text group to main display group
|
||||
group.append(text_group)
|
||||
|
||||
# displaying main display group
|
||||
display.show(group)
|
||||
|
||||
# state for hit detection
|
||||
crash = False
|
||||
# states to see if a Sparky is on screen
|
||||
sparky0 = False
|
||||
sparky1 = False
|
||||
sparky2 = False
|
||||
|
||||
# array of Sparky states
|
||||
sparky_states = [sparky0, sparky1, sparky2]
|
||||
# array of x location for Sparky's
|
||||
sparky_x = [sparky0_grid.x, sparky1_grid.x, sparky2_grid.x]
|
||||
|
||||
# function to display the heart sprites for lives
|
||||
def life():
|
||||
for _ in range(0, 3):
|
||||
life_grid[_, 0] = EMPTY
|
||||
for hearts in range(life_count):
|
||||
life_grid[hearts, 0] = HEART
|
||||
|
||||
# lives at beginning of the game
|
||||
life_count = 3
|
||||
|
||||
# variables for scoring
|
||||
jump_score = 0
|
||||
total_score = 0
|
||||
bonus = 0
|
||||
# state for Blinka being in default 'slither' mode
|
||||
snake = True
|
||||
# state to check if Blinka has jumped over Sparky
|
||||
cleared = False
|
||||
# state for the end of a game
|
||||
end = False
|
||||
# state for a new game beginning
|
||||
new_game = True
|
||||
# state for detecting game over
|
||||
game_over = False
|
||||
# variable to change between Blinka's two slither sprites
|
||||
b = 1
|
||||
# variable to hold time.monotonic() count for Blinka slither animation
|
||||
slither = 0
|
||||
# variables to hold time.monotonic() count to delay Sparky spawning
|
||||
blue = 0
|
||||
smoke = 0
|
||||
monster = 0
|
||||
|
||||
while True:
|
||||
|
||||
# checks if button has been pressed
|
||||
if (last_read + 0.01) < time.monotonic():
|
||||
buttons = pad.get_pressed()
|
||||
last_read = time.monotonic()
|
||||
# new game
|
||||
if new_game and not game_over:
|
||||
# graphics for new game splash screen
|
||||
blinka_grid.y = 16
|
||||
blinka_grid[0] = JUMP_1
|
||||
blinka_grid[1] = JUMP_2
|
||||
sparky0_grid.x = 5
|
||||
sparky1_grid.x = 40
|
||||
sparky2_grid.x = 65
|
||||
score_area.text = 300
|
||||
new_game_text.text = "BLINKA JUMP"
|
||||
life()
|
||||
# if start is pressed...
|
||||
if current_buttons != buttons:
|
||||
if buttons & BUTTON_START:
|
||||
# prepares display for gameplay
|
||||
print("start game")
|
||||
new_game_text.text = " "
|
||||
life_count = 3
|
||||
start = time.monotonic()
|
||||
new_game = False
|
||||
end = False
|
||||
sparky0_grid.x = 100
|
||||
sparky1_grid.x = 100
|
||||
sparky2_grid.x = 100
|
||||
# if game has started...
|
||||
if not game_over and not new_game:
|
||||
# gets time.monotonic() to have a running score
|
||||
mono = time.monotonic()
|
||||
score = mono - start
|
||||
# adds 10 points every time a Sparky is cleared
|
||||
total_score = score + jump_score
|
||||
# displays score as text
|
||||
score_area.text = int(total_score)
|
||||
|
||||
# puts Sparky states and x location into callable arrays
|
||||
for s in range(3):
|
||||
sparky_state = sparky_states[s]
|
||||
sparky_location = sparky_x[s]
|
||||
|
||||
# Sparkys are generated using a staggered delay
|
||||
# and matching an int to a random int
|
||||
# 1st Sparky
|
||||
if (blue + 0.03) < time.monotonic():
|
||||
if randint(1, 15) == 3:
|
||||
sparky_states[0] = True
|
||||
blue = time.monotonic()
|
||||
# 2nd Sparky
|
||||
if (smoke + 0.07) < time.monotonic():
|
||||
if randint(1, 15) == 7:
|
||||
sparky_states[1] = True
|
||||
smoke = time.monotonic()
|
||||
# 3rd Sparky
|
||||
if (monster + 0.12) < time.monotonic():
|
||||
if randint(1, 15) == 12:
|
||||
sparky_states[2] = True
|
||||
monster = time.monotonic()
|
||||
# if a Sparky is generated, it scrolls across the screen 1 pixel at a time
|
||||
# 1st Sparky
|
||||
if sparky_states[0] is True:
|
||||
sparky0_grid.x -= 1
|
||||
sparky_x[0] = sparky0_grid.x
|
||||
display.refresh(target_frames_per_second=120)
|
||||
# when a Sparky is 16 pixels off the display,
|
||||
# it goes back to its starting position
|
||||
if sparky0_grid.x is -16:
|
||||
sparky_states[0] = False
|
||||
sparky0_grid.x = 100
|
||||
sparky_x[0] = sparky0_grid.x
|
||||
# 2nd Sparky
|
||||
if sparky_states[1] is True:
|
||||
sparky1_grid.x -= 1
|
||||
sparky_x[1] = sparky1_grid.x
|
||||
display.refresh(target_frames_per_second=120)
|
||||
if sparky1_grid.x is -16:
|
||||
sparky_states[1] = False
|
||||
sparky1_grid.x = 100
|
||||
sparky_x[1] = sparky1_grid.x
|
||||
# 3rd Sparky
|
||||
if sparky_states[2] is True:
|
||||
sparky2_grid.x -= 1
|
||||
sparky_x[2] = sparky2_grid.x
|
||||
display.refresh(target_frames_per_second=120)
|
||||
if sparky2_grid.x is -16:
|
||||
sparky_states[2] = False
|
||||
sparky2_grid.x = 100
|
||||
sparky_x[2] = sparky2_grid.x
|
||||
|
||||
# if no lives are left then the game ends
|
||||
if life_count is 0:
|
||||
game_over = True
|
||||
|
||||
# if the A button is pressed then Blinka is no longer in the default
|
||||
# slither animation aka she jumps
|
||||
if current_buttons != buttons:
|
||||
if buttons & BUTTON_A:
|
||||
snake = False
|
||||
|
||||
# heart sprites are displayed to show life count
|
||||
life()
|
||||
|
||||
# if Blinka is slithering...
|
||||
if snake:
|
||||
# Blinka default location
|
||||
blinka_grid.y = 32
|
||||
# empty 2nd tile so that the jump sprite can be shown using
|
||||
# the same tilegrid
|
||||
blinka_grid[1] = EMPTY
|
||||
# every .15 seconds Blinka's slither sprite changes
|
||||
# so that her slithering is animated
|
||||
# b holds tilegrid position to display correct sprite
|
||||
if (slither + 0.15) < time.monotonic():
|
||||
blinka_grid[0] = b
|
||||
b += 1
|
||||
slither = time.monotonic()
|
||||
if b > 2:
|
||||
b = 1
|
||||
# if a Sparky collides with Blinka while she is slithering...
|
||||
for s in range(3):
|
||||
if sparky_x[s] == 8 and blinka_grid.y == 32:
|
||||
# tone is played
|
||||
simpleio.tone(board.SPEAKER, 493.88, 0.05)
|
||||
simpleio.tone(board.SPEAKER, 349.23, 0.05)
|
||||
# lose a life
|
||||
life_count = life_count - 1
|
||||
# if the A button is pressed then...
|
||||
else:
|
||||
# Blinka JUMPS
|
||||
# y location changes one row up and both jump sprites are shown
|
||||
blinka_grid.y = 16
|
||||
blinka_grid[0] = JUMP_1
|
||||
blinka_grid[1] = JUMP_2
|
||||
# if Blinka jumps over a Sparky...
|
||||
for j in range(3):
|
||||
if sparky_x[j] == 8 and not cleared:
|
||||
# 10 points to the player
|
||||
bonus += 1
|
||||
jump_score = bonus * 10
|
||||
cleared = True
|
||||
# special victory tone is played
|
||||
simpleio.tone(board.SPEAKER, 523.25, 0.005)
|
||||
simpleio.tone(board.SPEAKER, 783.99, 0.005)
|
||||
# resets back to Blinka animation
|
||||
snake = True
|
||||
# resets that Blinka has not jumped over a Sparky
|
||||
cleared = False
|
||||
|
||||
# if there are no more lives, the game is over
|
||||
if game_over and not new_game:
|
||||
# game over text is displayed
|
||||
game_over_text.text = "GAME OVER"
|
||||
score_area.text = " "
|
||||
# end game tone is played
|
||||
# and then the screen holds with the last
|
||||
# sprites on screen and game over text
|
||||
if not end:
|
||||
simpleio.tone(board.SPEAKER, 220, 0.05)
|
||||
simpleio.tone(board.SPEAKER, 207.65, 0.05)
|
||||
simpleio.tone(board.SPEAKER, 196, 0.5)
|
||||
end = True
|
||||
|
||||
# if the start button is pressed...
|
||||
if (current_buttons != buttons) and game_over:
|
||||
if buttons & BUTTON_START:
|
||||
# display, states and score are reset for gameplay
|
||||
game_over_text.text = " "
|
||||
life_count = 3
|
||||
start = time.monotonic()
|
||||
game_over = False
|
||||
end = False
|
||||
total_score = 0
|
||||
jump_score = 0
|
||||
bonus = 0
|
||||
score = 0
|
||||
blue = 0
|
||||
smoke = 0
|
||||
monster = 0
|
||||
sparky0_grid.x = 100
|
||||
sparky1_grid.x = 100
|
||||
sparky2_grid.x = 100
|
||||
# game begins again with all Sparky's off screen
|
||||
BIN
PyBadge_Blinka_Jump_Game/spritesNew.bmp
Normal file
BIN
PyBadge_Blinka_Jump_Game/spritesNew.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2 KiB |
|
|
@ -15,7 +15,7 @@ import neopixel
|
|||
from adafruit_esp32spi import adafruit_esp32spi
|
||||
from adafruit_esp32spi import adafruit_esp32spi_wifimanager
|
||||
import adafruit_esp32spi.adafruit_esp32spi_socket as socket
|
||||
import adafruit_minimqtt as MQTT
|
||||
import adafruit_minimqtt.adafruit_minimqtt as MQTT
|
||||
from adafruit_aws_iot import MQTT_CLIENT
|
||||
from adafruit_seesaw.seesaw import Seesaw
|
||||
import aws_gfx_helper
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import neopixel
|
|||
from adafruit_esp32spi import adafruit_esp32spi, adafruit_esp32spi_wifimanager
|
||||
import adafruit_esp32spi.adafruit_esp32spi_socket as socket
|
||||
from adafruit_gc_iot_core import MQTT_API, Cloud_Core
|
||||
import adafruit_minimqtt as MQTT
|
||||
import adafruit_minimqtt.adafruit_minimqtt as MQTT
|
||||
from adafruit_seesaw.seesaw import Seesaw
|
||||
import digitalio
|
||||
|
||||
|
|
|
|||
148
RGB_Matrix_Slot_Machine/code.py
Normal file
148
RGB_Matrix_Slot_Machine/code.py
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
import random
|
||||
import time
|
||||
|
||||
import adafruit_imageload.bmp
|
||||
import audioio
|
||||
import audiomp3
|
||||
import board
|
||||
import displayio
|
||||
import digitalio
|
||||
import framebufferio
|
||||
import rgbmatrix
|
||||
|
||||
displayio.release_displays()
|
||||
|
||||
matrix = rgbmatrix.RGBMatrix(
|
||||
width=64, height=32, bit_depth=4,
|
||||
rgb_pins=[board.D6, board.D5, board.D9, board.D11, board.D10, board.D12],
|
||||
addr_pins=[board.A5, board.A4, board.A3, board.A2],
|
||||
clock_pin=board.D13, latch_pin=board.D0, output_enable_pin=board.D1)
|
||||
display = framebufferio.FramebufferDisplay(matrix, auto_refresh=False)
|
||||
|
||||
# Each wheel can be in one of three states:
|
||||
STOPPED, RUNNING, BRAKING = range(3)
|
||||
|
||||
# Return a duplicate of the input list in a random (shuffled) order.
|
||||
def shuffled(seq):
|
||||
return sorted(seq, key=lambda _: random.random())
|
||||
|
||||
# The Wheel class manages the state of one wheel. "pos" is a position in
|
||||
# floating point coordinates, with one 1 pixel being 1 position.
|
||||
# The wheel also has a velocity (in positions
|
||||
# per tick) and a state (one of the above constants)
|
||||
class Wheel(displayio.TileGrid):
|
||||
def __init__(self, bitmap, palette):
|
||||
# Portions of up to 3 tiles are visible.
|
||||
super().__init__(bitmap=bitmap, pixel_shader=palette,
|
||||
width=1, height=3, tile_width=20, tile_height=24)
|
||||
self.order = shuffled(range(20))
|
||||
self.state = STOPPED
|
||||
self.pos = 0
|
||||
self.vel = 0
|
||||
self.termvel = 2
|
||||
self.y = 0
|
||||
self.x = 0
|
||||
self.stop_time = time.monotonic_ns()
|
||||
self.step()
|
||||
|
||||
def step(self):
|
||||
# Update each wheel for one time step
|
||||
if self.state == RUNNING:
|
||||
# Slowly lose speed when running, but go at least terminal velocity
|
||||
self.vel = max(self.vel * .99, self.termvel)
|
||||
if time.monotonic_ns() > self.stop_time:
|
||||
self.state = BRAKING
|
||||
elif self.state == BRAKING:
|
||||
# More quickly lose speed when baking, down to speed 0.4
|
||||
self.vel = max(self.vel * .85, 0.4)
|
||||
|
||||
# Advance the wheel according to the velocity, and wrap it around
|
||||
# after 24*20 positions
|
||||
self.pos = (self.pos + self.vel) % (20*24)
|
||||
|
||||
# Compute the rounded Y coordinate
|
||||
yy = round(self.pos)
|
||||
# Compute the offset of the tile (tiles are 24 pixels tall)
|
||||
yyy = yy % 24
|
||||
# Find out which tile is the top tile
|
||||
off = yy // 24
|
||||
|
||||
# If we're braking and a tile is close to midscreen,
|
||||
# then stop and make sure that tile is exactly centered
|
||||
if self.state == BRAKING and self.vel <= 2 and yyy < 8:
|
||||
self.pos = off * 24
|
||||
self.vel = 0
|
||||
yyy = 0
|
||||
self.state = STOPPED
|
||||
|
||||
# Move the displayed tiles to the correct height and make sure the
|
||||
# correct tiles are displayed.
|
||||
self.y = yyy - 20
|
||||
for i in range(3):
|
||||
self[i] = self.order[(19 - i + off) % 20]
|
||||
|
||||
# Set the wheel running again, using a slight bit of randomness.
|
||||
# The 'i' value makes sure the first wheel brakes first, the second
|
||||
# brakes second, and the third brakes third.
|
||||
def kick(self, i):
|
||||
self.state = RUNNING
|
||||
self.vel = random.uniform(8, 10)
|
||||
self.termvel = random.uniform(1.8, 4.2)
|
||||
self.stop_time = time.monotonic_ns() + 3000000000 + i * 350000000
|
||||
|
||||
|
||||
# This bitmap contains the emoji we're going to use. It is assumed
|
||||
# to contain 20 icons, each 20x24 pixels. This fits nicely on the 64x32
|
||||
# RGB matrix display.
|
||||
the_bitmap, the_palette = adafruit_imageload.load(
|
||||
"/emoji.bmp",
|
||||
bitmap=displayio.Bitmap,
|
||||
palette=displayio.Palette)
|
||||
|
||||
# Our fruit machine has 3 wheels, let's create them with a correct horizontal
|
||||
# (x) offset and arbitrary vertical (y) offset.
|
||||
g = displayio.Group(max_size=3)
|
||||
wheels = []
|
||||
for idx in range(3):
|
||||
wheel = Wheel(the_bitmap, the_palette)
|
||||
wheel.x = idx * 22
|
||||
wheel.y = -20
|
||||
g.append(wheel)
|
||||
wheels.append(wheel)
|
||||
display.show(g)
|
||||
|
||||
# We want a digital input to trigger the fruit machine
|
||||
button = digitalio.DigitalInOut(board.A1)
|
||||
button.switch_to_input(pull=digitalio.Pull.UP)
|
||||
|
||||
# Enable the speaker
|
||||
enable = digitalio.DigitalInOut(board.D4)
|
||||
enable.switch_to_output(True)
|
||||
|
||||
mp3file = open("/triangles-loop.mp3", "rb")
|
||||
sample = audiomp3.MP3Decoder(mp3file)
|
||||
|
||||
# Play the sample (just loop it for now)
|
||||
speaker = audioio.AudioOut(board.A0)
|
||||
speaker.play(sample, loop=True)
|
||||
|
||||
# Here's the main loop
|
||||
while True:
|
||||
# Refresh the dislpay (doing this manually ensures the wheels move
|
||||
# together, not at different times)
|
||||
display.refresh(minimum_frames_per_second=0, target_frames_per_second=60)
|
||||
|
||||
all_stopped = all(si.state == STOPPED for si in wheels)
|
||||
if all_stopped:
|
||||
# Once everything comes to a stop, wait until the lever is pulled and
|
||||
# start everything over again. Maybe you want to check if the
|
||||
# combination is a "winner" and add a light show or something.
|
||||
|
||||
while button.value:
|
||||
pass
|
||||
for idx, si in enumerate(wheels):
|
||||
si.kick(idx)
|
||||
|
||||
# Otherwise, let the wheels keep spinning...
|
||||
for idx, si in enumerate(wheels):
|
||||
si.step()
|
||||
BIN
RGB_Matrix_Slot_Machine/emoji.bmp
Normal file
BIN
RGB_Matrix_Slot_Machine/emoji.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
BIN
RGB_Matrix_Slot_Machine/triangles-loop.mp3
Normal file
BIN
RGB_Matrix_Slot_Machine/triangles-loop.mp3
Normal file
Binary file not shown.
0
ST_Combo_Boards/lis3mdl_lsm6ds_test/.uno.test.only
Normal file
0
ST_Combo_Boards/lis3mdl_lsm6ds_test/.uno.test.only
Normal file
|
|
@ -1,5 +1,9 @@
|
|||
// Basic demo for accelerometer, gyro, and magnetometer readings from the Adafruit
|
||||
// LSM6DSOX+LIS3MDL Breakout or FeatherWing and the LSM6DSOX+LIS3MDL Breakout
|
||||
// Basic demo for accelerometer, gyro, and magnetometer readings
|
||||
// from the following Adafruit ST Sensor combo boards:
|
||||
// * LSM6DSOX + LIS3MDL FeatherWing : https://www.adafruit.com/product/4565
|
||||
// * ISM330DHCX + LIS3MDL FeatherWing https://www.adafruit.com/product/4569
|
||||
// * LSM6DSOX + LIS3MDL Breakout : https://www.adafruit.com/product/4517
|
||||
// * LSM6DS33 + LIS3MDL Breakout Lhttps://www.adafruit.com/product/4485
|
||||
|
||||
#include <Adafruit_LSM6DSOX.h>
|
||||
Adafruit_LSM6DSOX lsm6ds;
|
||||
|
|
@ -9,8 +13,12 @@ Adafruit_LSM6DSOX lsm6ds;
|
|||
//#include <Adafruit_LSM6DS33.h>
|
||||
//Adafruit_LSM6DS33 lsm6ds;
|
||||
|
||||
#include <Adafruit_LIS3MDL.h>
|
||||
// To use with the ISM330DHCX+LIS3MDL Feather Wing, uncomment these two lines
|
||||
// and comment out the lines referring to the LSM6DSOX above
|
||||
//#include <Adafruit_ISM330DHCX.h>
|
||||
//Adafruit_ISM330DHCX lsm6ds;
|
||||
|
||||
#include <Adafruit_LIS3MDL.h>
|
||||
Adafruit_LIS3MDL lis3mdl;
|
||||
|
||||
void setup(void) {
|
||||
|
|
@ -114,8 +122,9 @@ void setup(void) {
|
|||
case LSM6DS_GYRO_RANGE_2000_DPS:
|
||||
Serial.println("2000 degrees/s");
|
||||
break;
|
||||
case ISM330DHCT_GYRO_RANGE_4000_DPS:
|
||||
break; // unsupported range for the DSOX
|
||||
case ISM330DHCX_GYRO_RANGE_4000_DPS:
|
||||
Serial.println("4000 degrees/s");
|
||||
break;
|
||||
}
|
||||
// lsm6ds.setGyroDataRate(LSM6DS_RATE_12_5_HZ);
|
||||
Serial.print("Gyro data rate set to: ");
|
||||
|
|
@ -1 +1 @@
|
|||
depends=Adafruit ILI9341, Adafruit BusIO, SD, Adafruit NeoPixel, Adafruit VS1053 Library, Adafruit BluefruitLE nRF51, Adafruit seesaw Library, Ethernet, Adafruit IO Arduino, Adafruit LSM303, FastLED, Adafruit LiquidCrystal, Adafruit SoftServo, TinyWireM, Adafruit AM radio library, WaveHC, Adafruit LED Backpack Library, MAX31850 OneWire, Adafruit VC0706 Serial Camera Library, RTClib, Adafruit SleepyDog Library, Adafruit Thermal Printer Library, Adafruit Zero I2S Library, Adafruit EPD, Adafruit SSD1351 library, Adafruit FONA Library, Adafruit Motor Shield V2 Library, Adafruit NeoMatrix, Adafruit Soundboard library, Adafruit Circuit Playground, MIDI, ArduinoJson, Adafruit TCS34725, Adafruit Pixie, Adafruit GPS Library, TinyGPS, WiFi101, Adafruit DotStar, Adafruit Si7021 Library, Adafruit WS2801 Library, Mouse, Keyboard, Time, IRremote, Adafruit LSM9DS0 Library, Adafruit Arcada Library, MIDIUSB, PubSubClient, Adafruit LIS2MDL, Adafruit NeoPXL8, Adafruit MCP23017 Arduino Library, Adafruit MLX90640, LiquidCrystal, Adafruit NeoTrellis M4 Library, RGB matrix Panel, Adafruit MLX90614 Library, Adafruit RGB LCD Shield Library, MAX6675 library, Adafruit MP3, Adafruit Keypad, Adafruit Arcada GifDecoder, Keypad, Neosegment, Encoder, Adafruit TiCoServo, Adafruit Trellis Library, FauxmoESP, Adafruit LSM303 Accel, Adafruit LSM303DLH Mag, CapacitiveSensor, Adafruit Zero PDM Library, Adafruit DMA neopixel library, elapsedMillis, DST RTC
|
||||
depends=Adafruit ILI9341, Adafruit BusIO, SD, Adafruit NeoPixel, Adafruit VS1053 Library, Adafruit BluefruitLE nRF51, Adafruit seesaw Library, Ethernet, Adafruit IO Arduino, FastLED, Adafruit LiquidCrystal, Adafruit SoftServo, TinyWireM, Adafruit AM radio library, WaveHC, Adafruit LED Backpack Library, MAX31850 OneWire, Adafruit VC0706 Serial Camera Library, RTClib, Adafruit SleepyDog Library, Adafruit Thermal Printer Library, Adafruit Zero I2S Library, Adafruit EPD, Adafruit SSD1351 library, Adafruit FONA Library, Adafruit Motor Shield V2 Library, Adafruit NeoMatrix, Adafruit Soundboard library, Adafruit Circuit Playground, ArduinoJson, Adafruit TCS34725, Adafruit Pixie, Adafruit GPS Library, TinyGPS, WiFi101, Adafruit DotStar, Adafruit Si7021 Library, Adafruit WS2801 Library, Mouse, Keyboard, Time, IRremote, Adafruit LSM9DS0 Library, Adafruit Arcada Library, MIDIUSB, PubSubClient, Adafruit LIS2MDL, Adafruit NeoPXL8, Adafruit MCP23017 Arduino Library, Adafruit MLX90640, LiquidCrystal, Adafruit NeoTrellis M4 Library, RGB matrix Panel, Adafruit MLX90614 Library, Adafruit RGB LCD Shield Library, MAX6675 library, Adafruit MP3, Adafruit Keypad, Adafruit Arcada GifDecoder, Keypad, Neosegment, Encoder, Adafruit TiCoServo, Adafruit Trellis Library, FauxmoESP, Adafruit LSM303 Accel, Adafruit LSM303DLH Mag, CapacitiveSensor, Adafruit Zero PDM Library, Adafruit DMA neopixel library, elapsedMillis, DST RTC
|
||||
|
|
@ -11,7 +11,7 @@ import neopixel
|
|||
from adafruit_bitmap_font import bitmap_font
|
||||
from adafruit_display_text.label import Label
|
||||
from adafruit_io.adafruit_io import IO_MQTT
|
||||
import adafruit_minimqtt as MQTT
|
||||
import adafruit_minimqtt.adafruit_minimqtt as MQTT
|
||||
from adafruit_pyportal import PyPortal
|
||||
from adafruit_seesaw.seesaw import Seesaw
|
||||
from simpleio import map_range
|
||||
|
|
|
|||
Loading…
Reference in a new issue